/*
* Copyright ( C ) 2015 The Android Open Source Project
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
#ifndef ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
#define ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
#include <string>
#include "base/arena_containers.h"
#include "base/array_ref.h"
#include "base/macros.h"
#include "base/scoped_arena_containers.h"
#include "nodes.h"
#include "optimization.h"
namespace art HIDDEN {
/**
* Induction variable analysis . This class does not have a direct public API .
* Instead , the results of induction variable analysis can be queried through
* friend classes , such as InductionVarRange .
*
* The analysis implementation is based on the paper by M . Gerlek et al .
* " Beyond Induction Variables : Detecting and Classifying Sequences Using a Demand - Driven SSA Form "
* ( ACM Transactions on Programming Languages and Systems , Volume 17 Issue 1 , Jan . 1995 ) .
*/
class HInductionVarAnalysis : public HOptimization {
public :
explicit HInductionVarAnalysis(HGraph* graph,
OptimizingCompilerStats* stats = nullptr,
const char * name = kInductionPassName);
bool Run() override;
static constexpr const char * kInductionPassName = "induction_var_analysis" ;
private :
struct NodeInfo;
struct StackEntry;
enum InductionClass {
kInvariant,
kLinear,
kPolynomial,
kGeometric,
kWrapAround,
kPeriodic
};
enum InductionOp {
// Operations.
kNop,
kAdd,
kSub,
kNeg,
kMul,
kDiv,
kRem,
kXor,
kFetch,
// Trip-counts.
kTripCountInLoop, // valid in full loop; loop is finite
kTripCountInBody, // valid in body only; loop is finite
kTripCountInLoopUnsafe, // valid in full loop; loop may be infinite
kTripCountInBodyUnsafe, // valid in body only; loop may be infinite
// Comparisons for trip-count tests.
kLT,
kLE,
kGT,
kGE
};
/**
* Defines a detected induction as :
* ( 1 ) invariant :
* op : a + b , a - b , - b , a * b , a / b , a % b , a ^ b , fetch
* ( 2 ) linear :
* nop : a * i + b
* ( 3 ) polynomial :
* nop : sum_lt ( a ) + b , for linear a
* ( 4 ) geometric :
* op : a * fetch ^ i + b , a * fetch ^ - i + b
* ( 5 ) wrap - around
* nop : a , then defined by b
* ( 6 ) periodic
* nop : a , then defined by b ( repeated when exhausted )
* ( 7 ) trip - count :
* tc : defined by a , taken - test in b
*/
struct InductionInfo : public ArenaObject<kArenaAllocInductionVarAnalysis> {
InductionInfo(InductionClass ic,
InductionOp op,
InductionInfo* a,
InductionInfo* b,
HInstruction* f,
DataType::Type t)
: induction_class(ic),
operation(op),
op_a(a),
op_b(b),
fetch(f),
type(t) {}
InductionClass induction_class;
InductionOp operation;
InductionInfo* op_a;
InductionInfo* op_b;
HInstruction* fetch;
DataType::Type type; // precision of operation
};
InductionInfo* CreateInvariantOp(const HBasicBlock* context,
const HLoopInformation* loop,
InductionOp op,
InductionInfo* a,
InductionInfo* b) {
DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
return CreateSimplifiedInvariant(context, loop, op, a, b);
}
InductionInfo* CreateInvariantFetch(HInstruction* f) {
DCHECK(f != nullptr);
return new (graph_->GetAllocator())
InductionInfo(kInvariant, kFetch, nullptr, nullptr, f, f->GetType());
}
InductionInfo* CreateTripCount(InductionOp op,
InductionInfo* a,
InductionInfo* b,
DataType::Type type) {
DCHECK(a != nullptr && b != nullptr);
return new (graph_->GetAllocator()) InductionInfo(kInvariant, op, a, b, nullptr, type);
}
InductionInfo* CreateInduction(InductionClass ic,
InductionOp op,
InductionInfo* a,
InductionInfo* b,
HInstruction* f,
DataType::Type type) {
DCHECK(a != nullptr && b != nullptr);
return new (graph_->GetAllocator()) InductionInfo(ic, op, a, b, f, type);
}
// Methods for analysis.
void VisitLoop(const HLoopInformation* loop);
void ReVisitLoop(const HLoopInformation* loop);
size_t TryVisitNodes(const HLoopInformation* loop,
HInstruction* start_instruction,
size_t global_depth,
/*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions);
void ExtractScc(ArrayRef<const StackEntry> stack_tail, ScopedArenaVector<HInstruction*>* scc);
void ClassifyTrivial(const HLoopInformation* loop, HInstruction* instruction);
void ClassifyNonTrivial(const HLoopInformation* loop, ArrayRef<const StackEntry> stack_tail);
InductionInfo* RotatePeriodicInduction(InductionInfo* induction,
InductionInfo* last,
DataType::Type type);
// Transfer operations.
InductionInfo* TransferPhi(const HLoopInformation* loop,
HInstruction* phi,
size_t input_index,
size_t adjust_input_size);
InductionInfo* TransferAddSub(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* a,
InductionInfo* b,
InductionOp op,
DataType::Type type);
InductionInfo* TransferNeg(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* a,
DataType::Type type);
InductionInfo* TransferMul(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* a,
InductionInfo* b,
DataType::Type type);
InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
// Solvers.
InductionInfo* SolvePhi(HInstruction* phi,
size_t input_index,
size_t adjust_input_size,
const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle);
InductionInfo* SolvePhiAllInputs(const HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* phi,
const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
DataType::Type type);
InductionInfo* SolveAddSub(const HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
HInstruction* x,
HInstruction* y,
InductionOp op,
const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
DataType::Type type);
InductionInfo* SolveOp(const HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
HInstruction* x,
HInstruction* y,
InductionOp op,
DataType::Type type);
InductionInfo* SolveTest(const HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
int64_t opposite_value,
DataType::Type type);
InductionInfo* SolveConversion(const HLoopInformation* loop,
HInstruction* entry_phi,
HTypeConversion* conversion,
const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
/*inout*/ DataType::Type* type);
//
// Loop trip count analysis methods.
//
// Trip count information.
void VisitControl(const HLoopInformation* loop);
void VisitCondition(const HBasicBlock* context,
const HLoopInformation* loop,
HBasicBlock* body,
InductionInfo* a,
InductionInfo* b,
DataType::Type type,
IfCondition cmp);
void VisitTripCount(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* lower_expr,
InductionInfo* upper_expr,
InductionInfo* stride,
int64_t stride_value,
DataType::Type type,
IfCondition cmp);
bool IsTaken(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* lower_expr,
InductionInfo* upper_expr,
IfCondition cmp);
bool IsFinite(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* upper_expr,
int64_t stride_value,
DataType::Type type,
IfCondition cmp);
bool FitsNarrowerControl(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* lower_expr,
InductionInfo* upper_expr,
int64_t stride_value,
DataType::Type type,
IfCondition cmp);
bool RewriteBreakLoop(const HBasicBlock* context,
const HLoopInformation* loop,
HBasicBlock* body,
int64_t stride_value,
DataType::Type type);
//
// Helper methods.
//
// Assign and lookup.
void AssignInfo(const HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
InductionInfo* LookupInfo(const HLoopInformation* loop, HInstruction* instruction);
InductionInfo* CreateConstant(int64_t value, DataType::Type type);
InductionInfo* CreateSimplifiedInvariant(const HBasicBlock* context,
const HLoopInformation* loop,
InductionOp op,
InductionInfo* a,
InductionInfo* b);
HInstruction* GetShiftConstant(const HLoopInformation* loop,
HInstruction* instruction,
InductionInfo* initial);
void AssignCycle(HPhi* phi, ArrayRef<HInstruction* const > scc);
ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
// Constants.
bool IsExact(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* info,
/*out*/int64_t* value);
bool IsAtMost(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* info,
/*out*/int64_t* value);
bool IsAtLeast(const HBasicBlock* context,
const HLoopInformation* loop,
InductionInfo* info,
/*out*/int64_t* value);
// Helpers.
static bool IsNarrowingLinear(InductionInfo* info);
static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
static std::string FetchToString(HInstruction* fetch);
static std::string InductionToString(InductionInfo* info);
// Returns true if we have a pathological case we don't want to analyze.
bool IsPathologicalCase();
// Starting with initial_phi, it calculates how many loop header phis in a row we have. To do
// this, we count the loop header phi which are used as an input of other loop header phis. It
// uses `cached_values` to avoid recomputing results.
void CalculateLoopHeaderPhisInARow(HPhi* initial_phi,
ScopedArenaSafeMap<HPhi*, int >& cached_values,
ScopedArenaAllocator& allocator);
/**
* Maintains the results of the analysis as a mapping from loops to a mapping from instructions
* to the induction information for that instruction in that loop .
*/
ArenaSafeMap<const HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
/**
* Preserves induction cycle information for each loop - phi .
*/
ArenaSafeMap<HPhi*, ArenaSet<HInstruction*>> cycles_;
friend class InductionVarAnalysisTest;
friend class InductionVarRange;
friend class InductionVarRangeTest;
DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
};
} // namespace art
#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_ANALYSIS_H_
Messung V0.5 in Prozent C=89 H=92 G=90
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland