You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
10 KiB
289 lines
10 KiB
/*
|
|
* 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 "nodes.h"
|
|
#include "optimization.h"
|
|
|
|
namespace art {
|
|
|
|
/**
|
|
* 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, const char* name = kInductionPassName);
|
|
|
|
bool Run() override;
|
|
|
|
static constexpr const char* kInductionPassName = "induction_var_analysis";
|
|
|
|
private:
|
|
struct NodeInfo {
|
|
explicit NodeInfo(uint32_t d) : depth(d), done(false) {}
|
|
uint32_t depth;
|
|
bool done;
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
bool IsVisitedNode(HInstruction* instruction) const {
|
|
return map_.find(instruction) != map_.end();
|
|
}
|
|
|
|
InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
|
|
DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
|
|
return CreateSimplifiedInvariant(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(HLoopInformation* loop);
|
|
void VisitNode(HLoopInformation* loop, HInstruction* instruction);
|
|
uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
|
|
void ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction);
|
|
void ClassifyNonTrivial(HLoopInformation* loop);
|
|
InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
|
|
|
|
// Transfer operations.
|
|
InductionInfo* TransferPhi(HLoopInformation* loop,
|
|
HInstruction* phi,
|
|
size_t input_index,
|
|
size_t adjust_input_size);
|
|
InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
|
|
InductionInfo* TransferNeg(InductionInfo* a);
|
|
InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
|
|
InductionInfo* TransferConversion(InductionInfo* a, DataType::Type from, DataType::Type to);
|
|
|
|
// Solvers.
|
|
InductionInfo* SolvePhi(HInstruction* phi, size_t input_index, size_t adjust_input_size);
|
|
InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
|
|
HInstruction* entry_phi,
|
|
HInstruction* phi);
|
|
InductionInfo* SolveAddSub(HLoopInformation* loop,
|
|
HInstruction* entry_phi,
|
|
HInstruction* instruction,
|
|
HInstruction* x,
|
|
HInstruction* y,
|
|
InductionOp op,
|
|
bool is_first_call); // possibly swaps x and y to try again
|
|
InductionInfo* SolveOp(HLoopInformation* loop,
|
|
HInstruction* entry_phi,
|
|
HInstruction* instruction,
|
|
HInstruction* x,
|
|
HInstruction* y,
|
|
InductionOp op);
|
|
InductionInfo* SolveTest(HLoopInformation* loop,
|
|
HInstruction* entry_phi,
|
|
HInstruction* instruction,
|
|
int64_t oppositive_value);
|
|
InductionInfo* SolveConversion(HLoopInformation* loop,
|
|
HInstruction* entry_phi,
|
|
HTypeConversion* conversion);
|
|
|
|
//
|
|
// Loop trip count analysis methods.
|
|
//
|
|
|
|
// Trip count information.
|
|
void VisitControl(HLoopInformation* loop);
|
|
void VisitCondition(HLoopInformation* loop,
|
|
HBasicBlock* body,
|
|
InductionInfo* a,
|
|
InductionInfo* b,
|
|
DataType::Type type,
|
|
IfCondition cmp);
|
|
void VisitTripCount(HLoopInformation* loop,
|
|
InductionInfo* lower_expr,
|
|
InductionInfo* upper_expr,
|
|
InductionInfo* stride,
|
|
int64_t stride_value,
|
|
DataType::Type type,
|
|
IfCondition cmp);
|
|
bool IsTaken(InductionInfo* lower_expr, InductionInfo* upper_expr, IfCondition cmp);
|
|
bool IsFinite(InductionInfo* upper_expr,
|
|
int64_t stride_value,
|
|
DataType::Type type,
|
|
IfCondition cmp);
|
|
bool FitsNarrowerControl(InductionInfo* lower_expr,
|
|
InductionInfo* upper_expr,
|
|
int64_t stride_value,
|
|
DataType::Type type,
|
|
IfCondition cmp);
|
|
bool RewriteBreakLoop(HLoopInformation* loop,
|
|
HBasicBlock* body,
|
|
int64_t stride_value,
|
|
DataType::Type type);
|
|
|
|
//
|
|
// Helper methods.
|
|
//
|
|
|
|
// Assign and lookup.
|
|
void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
|
|
InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
|
|
InductionInfo* CreateConstant(int64_t value, DataType::Type type);
|
|
InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
|
|
HInstruction* GetShiftConstant(HLoopInformation* loop,
|
|
HInstruction* instruction,
|
|
InductionInfo* initial);
|
|
void AssignCycle(HPhi* phi);
|
|
ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
|
|
|
|
// Constants.
|
|
bool IsExact(InductionInfo* info, /*out*/ int64_t* value);
|
|
bool IsAtMost(InductionInfo* info, /*out*/ int64_t* value);
|
|
bool IsAtLeast(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);
|
|
|
|
// TODO: fine tune the following data structures, only keep relevant data.
|
|
|
|
// Temporary book-keeping during the analysis.
|
|
uint32_t global_depth_;
|
|
ArenaVector<HInstruction*> stack_;
|
|
ArenaSafeMap<HInstruction*, NodeInfo> map_;
|
|
ArenaVector<HInstruction*> scc_;
|
|
ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
|
|
DataType::Type type_;
|
|
|
|
/**
|
|
* 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<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_
|