summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/induction_var_analysis.cc610
-rw-r--r--compiler/optimizing/induction_var_analysis.h69
-rw-r--r--compiler/optimizing/loop_optimization.cc18
3 files changed, 389 insertions, 308 deletions
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index 3a10d5831d..e6d90795a1 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -15,45 +15,12 @@
*/
#include "induction_var_analysis.h"
+
#include "induction_var_range.h"
namespace art {
/**
- * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
- * along dependences, viz. any of (a, b, c, d), (d, a, b, c) (c, d, a, b), (b, c, d, a) assuming
- * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
- * classification, the lexicographically first loop-phi is rotated to the front.
- */
-static void RotateEntryPhiFirst(HLoopInformation* loop,
- ArenaVector<HInstruction*>* scc,
- ArenaVector<HInstruction*>* new_scc) {
- // Find very first loop-phi.
- const HInstructionList& phis = loop->GetHeader()->GetPhis();
- HInstruction* phi = nullptr;
- size_t phi_pos = -1;
- const size_t size = scc->size();
- for (size_t i = 0; i < size; i++) {
- HInstruction* other = (*scc)[i];
- if (other->IsLoopHeaderPhi() && (phi == nullptr || phis.FoundBefore(other, phi))) {
- phi = other;
- phi_pos = i;
- }
- }
-
- // If found, bring that loop-phi to front.
- if (phi != nullptr) {
- new_scc->clear();
- for (size_t i = 0; i < size; i++) {
- new_scc->push_back((*scc)[phi_pos]);
- if (++phi_pos >= size) phi_pos = 0;
- }
- DCHECK_EQ(size, new_scc->size());
- scc->swap(*new_scc);
- }
-}
-
-/**
* Returns true if the from/to types denote a narrowing, integral conversion (precision loss).
*/
static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to) {
@@ -157,10 +124,10 @@ HInstruction* FindFirstLoopHeaderPhiUse(HLoopInformation* loop, HInstruction* in
/**
* Relinks the Phi structure after break-loop rewriting.
*/
-bool FixOutsideUse(HLoopInformation* loop,
- HInstruction* instruction,
- HInstruction* replacement,
- bool rewrite) {
+static bool FixOutsideUse(HLoopInformation* loop,
+ HInstruction* instruction,
+ HInstruction* replacement,
+ bool rewrite) {
// Deal with regular uses.
const HUseList<HInstruction*>& uses = instruction->GetUses();
for (auto it = uses.begin(), end = uses.end(); it != end; ) {
@@ -185,9 +152,7 @@ bool FixOutsideUse(HLoopInformation* loop,
if (replacement == nullptr) {
return false;
} else if (rewrite) {
- user->RemoveAsUserOfInput(index);
- user->SetRawEnvAt(index, replacement);
- replacement->AddEnvUseAt(user, index);
+ user->ReplaceInput(replacement, index);
}
}
}
@@ -197,12 +162,12 @@ bool FixOutsideUse(HLoopInformation* loop,
/**
* Test and rewrite the loop body of a break-loop. Returns true on success.
*/
-bool RewriteBreakLoopBody(HLoopInformation* loop,
- HBasicBlock* body,
- HInstruction* cond,
- HInstruction* index,
- HInstruction* upper,
- bool rewrite) {
+static bool RewriteBreakLoopBody(HLoopInformation* loop,
+ HBasicBlock* body,
+ HInstruction* cond,
+ HInstruction* index,
+ HInstruction* upper,
+ bool rewrite) {
// Deal with Phis. Outside use prohibited, except for index (which gets exit value).
for (HInstructionIterator it(loop->GetHeader()->GetPhis()); !it.Done(); it.Advance()) {
HInstruction* exit_value = it.Current() == index ? upper : nullptr;
@@ -211,32 +176,46 @@ bool RewriteBreakLoopBody(HLoopInformation* loop,
}
}
// Deal with other statements in header.
- for (HInstruction* m = cond->GetPrevious(), *p = nullptr; m && !m->IsSuspendCheck(); m = p) {
- p = m->GetPrevious();
+ for (HInstruction* m = cond->GetPrevious(); m && !m->IsSuspendCheck();) {
+ HInstruction* p = m->GetPrevious();
if (rewrite) {
m->MoveBefore(body->GetFirstInstruction(), false);
}
if (!FixOutsideUse(loop, m, FindFirstLoopHeaderPhiUse(loop, m), rewrite)) {
return false;
}
+ m = p;
}
return true;
}
//
-// Class methods.
+// Class members.
//
+struct HInductionVarAnalysis::NodeInfo {
+ explicit NodeInfo(uint32_t d) : depth(d), done(false) {}
+ uint32_t depth;
+ bool done;
+};
+
+struct HInductionVarAnalysis::StackEntry {
+ StackEntry(HInstruction* insn, NodeInfo* info, size_t link = std::numeric_limits<size_t>::max())
+ : instruction(insn),
+ node_info(info),
+ user_link(link),
+ num_visited_inputs(0u),
+ low_depth(info->depth) {}
+
+ HInstruction* instruction;
+ NodeInfo* node_info;
+ size_t user_link; // Stack index of the user that is visiting this input.
+ size_t num_visited_inputs;
+ size_t low_depth;
+};
+
HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph, const char* name)
: HOptimization(graph, name),
- global_depth_(0),
- stack_(graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
- map_(std::less<HInstruction*>(),
- graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
- scc_(graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
- cycle_(std::less<HInstruction*>(),
- graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
- type_(DataType::Type::kVoid),
induction_(std::less<HLoopInformation*>(),
graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
cycles_(std::less<HPhi*>(),
@@ -257,12 +236,13 @@ bool HInductionVarAnalysis::Run() {
}
void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
+ ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
+ ScopedArenaSafeMap<HInstruction*, NodeInfo> visited_instructions(
+ std::less<HInstruction*>(), local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
+
// Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
// algorithm. Due to the descendant-first nature, classification happens "on-demand".
- global_depth_ = 0;
- DCHECK(stack_.empty());
- map_.clear();
-
+ size_t global_depth = 0;
for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
HBasicBlock* loop_block = it_loop.Current();
DCHECK(loop_block->IsInLoop());
@@ -271,108 +251,168 @@ void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
}
// Visit phi-operations and instructions.
for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
- HInstruction* instruction = it.Current();
- if (!IsVisitedNode(instruction)) {
- VisitNode(loop, instruction);
- }
+ global_depth = TryVisitNodes(loop, it.Current(), global_depth, &visited_instructions);
}
for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
- HInstruction* instruction = it.Current();
- if (!IsVisitedNode(instruction)) {
- VisitNode(loop, instruction);
- }
+ global_depth = TryVisitNodes(loop, it.Current(), global_depth, &visited_instructions);
}
}
- DCHECK(stack_.empty());
- map_.clear();
-
// Determine the loop's trip-count.
VisitControl(loop);
}
-void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
- const uint32_t d1 = ++global_depth_;
- map_.Put(instruction, NodeInfo(d1));
- stack_.push_back(instruction);
-
- // Visit all descendants.
- uint32_t low = d1;
- for (HInstruction* input : instruction->GetInputs()) {
- low = std::min(low, VisitDescendant(loop, input));
- }
-
- // Lower or found SCC?
- if (low < d1) {
- map_.find(instruction)->second.depth = low;
- } else {
- scc_.clear();
- cycle_.clear();
-
- // Pop the stack to build the SCC for classification.
- while (!stack_.empty()) {
- HInstruction* x = stack_.back();
- scc_.push_back(x);
- stack_.pop_back();
- map_.find(x)->second.done = true;
- if (x == instruction) {
+size_t HInductionVarAnalysis::TryVisitNodes(
+ HLoopInformation* loop,
+ HInstruction* start_instruction,
+ size_t global_depth,
+ /*inout*/ ScopedArenaSafeMap<HInstruction*, NodeInfo>* visited_instructions) {
+ // This is recursion-free version of the SCC search algorithm. We have limited stack space,
+ // so recursion with the depth dependent on the input is undesirable as such depth is unlimited.
+ auto [it, inserted] =
+ visited_instructions->insert(std::make_pair(start_instruction, NodeInfo(global_depth + 1u)));
+ if (!inserted) {
+ return global_depth;
+ }
+ NodeInfo* start_info = &it->second;
+ ++global_depth;
+ DCHECK_EQ(global_depth, start_info->depth);
+
+ ScopedArenaVector<StackEntry> stack(visited_instructions->get_allocator());
+ stack.push_back({start_instruction, start_info});
+
+ size_t current_entry = 0u;
+ while (!stack.empty()) {
+ StackEntry& entry = stack[current_entry];
+
+ // Look for unvisited inputs (also known as "descentants").
+ bool visit_input = false;
+ auto inputs = entry.instruction->GetInputs();
+ while (entry.num_visited_inputs != inputs.size()) {
+ HInstruction* input = inputs[entry.num_visited_inputs];
+ ++entry.num_visited_inputs;
+ // If the definition is either outside the loop (loop invariant entry value)
+ // or assigned in inner loop (inner exit value), the input is not visited.
+ if (input->GetBlock()->GetLoopInformation() != loop) {
+ continue;
+ }
+ // Try visiting the input. If already visited, update `entry.low_depth`.
+ auto [input_it, input_inserted] =
+ visited_instructions->insert(std::make_pair(input, NodeInfo(global_depth + 1u)));
+ NodeInfo* input_info = &input_it->second;
+ if (input_inserted) {
+ // Push the input on the `stack` and visit it now.
+ ++global_depth;
+ DCHECK_EQ(global_depth, input_info->depth);
+ stack.push_back({input, input_info, current_entry});
+ current_entry = stack.size() - 1u;
+ visit_input = true;
break;
+ } else if (!input_info->done && input_info->depth < entry.low_depth) {
+ entry.low_depth = input_it->second.depth;
}
+ continue;
+ }
+ if (visit_input) {
+ continue; // Process the new top of the stack.
}
- // Type of induction.
- type_ = scc_[0]->GetType();
-
- // Classify the SCC.
- if (scc_.size() == 1 && !scc_[0]->IsLoopHeaderPhi()) {
- ClassifyTrivial(loop, scc_[0]);
+ // All inputs of the current node have been visited.
+ // Check if we have found an input below this entry on the stack.
+ DCHECK(!entry.node_info->done);
+ size_t previous_entry = entry.user_link;
+ if (entry.node_info->depth > entry.low_depth) {
+ DCHECK_LT(previous_entry, current_entry) << entry.node_info->depth << " " << entry.low_depth;
+ entry.node_info->depth = entry.low_depth;
+ if (stack[previous_entry].low_depth > entry.low_depth) {
+ stack[previous_entry].low_depth = entry.low_depth;
+ }
} else {
- ClassifyNonTrivial(loop);
+ // Classify the SCC we have just found.
+ ArrayRef<StackEntry> stack_tail = ArrayRef<StackEntry>(stack).SubArray(current_entry);
+ for (StackEntry& tail_entry : stack_tail) {
+ tail_entry.node_info->done = true;
+ }
+ if (current_entry + 1u == stack.size() && !entry.instruction->IsLoopHeaderPhi()) {
+ ClassifyTrivial(loop, entry.instruction);
+ } else {
+ ClassifyNonTrivial(loop, ArrayRef<const StackEntry>(stack_tail));
+ }
+ stack.erase(stack.begin() + current_entry, stack.end());
}
-
- scc_.clear();
- cycle_.clear();
+ current_entry = previous_entry;
}
+
+ return global_depth;
}
-uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
- // If the definition is either outside the loop (loop invariant entry value)
- // or assigned in inner loop (inner exit value), the traversal stops.
- HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
- if (otherLoop != loop) {
- return global_depth_;
+/**
+ * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
+ * along dependences, viz. any of (a, b, c, d), (d, a, b, c) (c, d, a, b), (b, c, d, a) assuming
+ * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
+ * classification, the lexicographically first loop-phi is rotated to the front. We do that
+ * as we extract the SCC instructions.
+ */
+void HInductionVarAnalysis::ExtractScc(ArrayRef<const StackEntry> stack_tail,
+ ScopedArenaVector<HInstruction*>* scc) {
+ // Find very first loop-phi.
+ HInstruction* phi = nullptr;
+ size_t split_pos = 0;
+ const size_t size = stack_tail.size();
+ for (size_t i = 0; i != size; ++i) {
+ const StackEntry& entry = stack_tail[i];
+ HInstruction* instruction = entry.instruction;
+ if (instruction->IsLoopHeaderPhi()) {
+ // All loop Phis in SCC come from the same loop header.
+ HBasicBlock* block = instruction->GetBlock();
+ DCHECK(block->GetLoopInformation()->GetHeader() == block);
+ DCHECK(phi == nullptr || phi->GetBlock() == block);
+ if (phi == nullptr || block->GetPhis().FoundBefore(instruction, phi)) {
+ phi = instruction;
+ split_pos = i + 1u;
+ }
+ }
}
- // Inspect descendant node.
- if (!IsVisitedNode(instruction)) {
- VisitNode(loop, instruction);
- return map_.find(instruction)->second.depth;
- } else {
- auto it = map_.find(instruction);
- return it->second.done ? global_depth_ : it->second.depth;
+ // Extract SCC in two chunks.
+ DCHECK(scc->empty());
+ scc->reserve(size);
+ for (const StackEntry& entry : ReverseRange(stack_tail.SubArray(/*pos=*/ 0u, split_pos))) {
+ scc->push_back(entry.instruction);
+ }
+ for (const StackEntry& entry : ReverseRange(stack_tail.SubArray(/*pos=*/ split_pos))) {
+ scc->push_back(entry.instruction);
}
+ DCHECK_EQ(scc->size(), stack_tail.size());
}
void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
+ DataType::Type type = instruction->GetType();
InductionInfo* info = nullptr;
if (instruction->IsPhi()) {
info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 0);
} else if (instruction->IsAdd()) {
info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
- LookupInfo(loop, instruction->InputAt(1)), kAdd);
+ LookupInfo(loop, instruction->InputAt(1)),
+ kAdd,
+ type);
} else if (instruction->IsSub()) {
info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
- LookupInfo(loop, instruction->InputAt(1)), kSub);
+ LookupInfo(loop, instruction->InputAt(1)),
+ kSub,
+ type);
} else if (instruction->IsNeg()) {
- info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
+ info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)), type);
} else if (instruction->IsMul()) {
info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
- LookupInfo(loop, instruction->InputAt(1)));
+ LookupInfo(loop, instruction->InputAt(1)),
+ type);
} else if (instruction->IsShl()) {
HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
if (mulc != nullptr) {
info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
- LookupInfo(loop, mulc));
+ LookupInfo(loop, mulc),
+ type);
}
} else if (instruction->IsSelect()) {
info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);
@@ -390,19 +430,18 @@ void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction
}
}
-void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
- const size_t size = scc_.size();
+void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop,
+ ArrayRef<const StackEntry> stack_tail) {
+ const size_t size = stack_tail.size();
DCHECK_GE(size, 1u);
+ DataType::Type type = stack_tail.back().instruction->GetType();
- // Rotate proper loop-phi to front.
- if (size > 1) {
- ArenaVector<HInstruction*> other(
- graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis));
- RotateEntryPhiFirst(loop, &scc_, &other);
- }
+ ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
+ ScopedArenaVector<HInstruction*> scc(local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
+ ExtractScc(ArrayRef<const StackEntry>(stack_tail), &scc);
// Analyze from loop-phi onwards.
- HInstruction* phi = scc_[0];
+ HInstruction* phi = scc[0];
if (!phi->IsLoopHeaderPhi()) {
return;
}
@@ -415,8 +454,8 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
// Store interesting cycle in each loop phi.
for (size_t i = 0; i < size; i++) {
- if (scc_[i]->IsLoopHeaderPhi()) {
- AssignCycle(scc_[i]->AsPhi());
+ if (scc[i]->IsLoopHeaderPhi()) {
+ AssignCycle(scc[i]->AsPhi(), ArrayRef<HInstruction* const>(scc));
}
}
@@ -429,68 +468,83 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
initial,
update,
/*fetch*/ nullptr,
- type_));
+ type));
}
return;
}
- // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
+ // Inspect remainder of the cycle that resides in `scc`. The `cycle` mapping assigns
// temporary meaning to its nodes, seeded from the phi instruction and back.
+ ScopedArenaSafeMap<HInstruction*, InductionInfo*> cycle(
+ std::less<HInstruction*>(), local_allocator.Adapter(kArenaAllocInductionVarAnalysis));
for (size_t i = 1; i < size; i++) {
- HInstruction* instruction = scc_[i];
+ HInstruction* instruction = scc[i];
InductionInfo* update = nullptr;
if (instruction->IsPhi()) {
- update = SolvePhiAllInputs(loop, phi, instruction);
+ update = SolvePhiAllInputs(loop, phi, instruction, cycle, type);
} else if (instruction->IsAdd()) {
- update = SolveAddSub(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
+ update = SolveAddSub(loop,
+ phi,
+ instruction,
+ instruction->InputAt(0),
+ instruction->InputAt(1),
+ kAdd,
+ cycle,
+ type);
} else if (instruction->IsSub()) {
- update = SolveAddSub(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
+ update = SolveAddSub(loop,
+ phi,
+ instruction,
+ instruction->InputAt(0),
+ instruction->InputAt(1),
+ kSub,
+ cycle,
+ type);
} else if (instruction->IsMul()) {
update = SolveOp(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kMul);
+ loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kMul, type);
} else if (instruction->IsDiv()) {
update = SolveOp(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kDiv);
+ loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kDiv, type);
} else if (instruction->IsRem()) {
update = SolveOp(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kRem);
+ loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kRem, type);
} else if (instruction->IsShl()) {
HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
if (mulc != nullptr) {
- update = SolveOp(loop, phi, instruction, instruction->InputAt(0), mulc, kMul);
+ update = SolveOp(loop, phi, instruction, instruction->InputAt(0), mulc, kMul, type);
}
} else if (instruction->IsShr() || instruction->IsUShr()) {
HInstruction* divc = GetShiftConstant(loop, instruction, initial);
if (divc != nullptr) {
- update = SolveOp(loop, phi, instruction, instruction->InputAt(0), divc, kDiv);
+ update = SolveOp(loop, phi, instruction, instruction->InputAt(0), divc, kDiv, type);
}
} else if (instruction->IsXor()) {
update = SolveOp(
- loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kXor);
+ loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kXor, type);
} else if (instruction->IsEqual()) {
- update = SolveTest(loop, phi, instruction, 0);
+ update = SolveTest(loop, phi, instruction, /*opposite_value=*/ 0, type);
} else if (instruction->IsNotEqual()) {
- update = SolveTest(loop, phi, instruction, 1);
+ update = SolveTest(loop, phi, instruction, /*opposite_value=*/ 1, type);
} else if (instruction->IsSelect()) {
- update = SolvePhi(instruction, /*input_index*/ 0, /*adjust_input_size*/ 1); // acts like Phi
+ // Select acts like Phi.
+ update = SolvePhi(instruction, /*input_index=*/ 0, /*adjust_input_size=*/ 1, cycle);
} else if (instruction->IsTypeConversion()) {
- update = SolveConversion(loop, phi, instruction->AsTypeConversion());
+ update = SolveConversion(loop, phi, instruction->AsTypeConversion(), cycle, &type);
}
if (update == nullptr) {
return;
}
- cycle_.Put(instruction, update);
+ cycle.Put(instruction, update);
}
// Success if all internal links received the same temporary meaning.
- InductionInfo* induction = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
+ InductionInfo* induction = SolvePhi(phi, /*input_index=*/ 1, /*adjust_input_size=*/ 0, cycle);
if (induction != nullptr) {
switch (induction->induction_class) {
case kInvariant:
// Construct combined stride of the linear induction.
- induction = CreateInduction(kLinear, kNop, induction, initial, /*fetch*/ nullptr, type_);
+ induction = CreateInduction(kLinear, kNop, induction, initial, /*fetch*/ nullptr, type);
FALLTHROUGH_INTENDED;
case kPolynomial:
case kGeometric:
@@ -499,7 +553,7 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
// Statements are scanned in order.
AssignInfo(loop, phi, induction);
for (size_t i = 1; i < size; i++) {
- ClassifyTrivial(loop, scc_[i]);
+ ClassifyTrivial(loop, scc[i]);
}
break;
case kPeriodic:
@@ -507,8 +561,8 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
// rotating each first element to the end. Lastly, phi is classified.
// Statements are scanned in reverse order.
for (size_t i = size - 1; i >= 1; i--) {
- AssignInfo(loop, scc_[i], induction);
- induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
+ AssignInfo(loop, scc[i], induction);
+ induction = RotatePeriodicInduction(induction->op_b, induction->op_a, type);
}
AssignInfo(loop, phi, induction);
break;
@@ -520,7 +574,8 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
InductionInfo* induction,
- InductionInfo* last) {
+ InductionInfo* last,
+ DataType::Type type) {
// Rotates a periodic induction of the form
// (a, b, c, d, e)
// into
@@ -532,14 +587,14 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduc
induction,
last,
/*fetch*/ nullptr,
- type_);
+ type);
}
return CreateInduction(kPeriodic,
kNop,
induction->op_a,
- RotatePeriodicInduction(induction->op_b, last),
+ RotatePeriodicInduction(induction->op_b, last, type),
/*fetch*/ nullptr,
- type_);
+ type);
}
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(HLoopInformation* loop,
@@ -561,7 +616,8 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(HLoopIn
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
InductionInfo* b,
- InductionOp op) {
+ InductionOp op,
+ DataType::Type type) {
// Transfer over an addition or subtraction: any invariant, linear, polynomial, geometric,
// wrap-around, or periodic can be combined with an invariant to yield a similar result.
// Two linear or two polynomial inputs can be combined too. Other combinations fail.
@@ -573,39 +629,40 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(Indu
} else if ((a->induction_class == kLinear && b->induction_class == kLinear) ||
(a->induction_class == kPolynomial && b->induction_class == kPolynomial)) {
// Rule induc(a, b) + induc(a', b') -> induc(a + a', b + b').
- InductionInfo* new_a = TransferAddSub(a->op_a, b->op_a, op);
- InductionInfo* new_b = TransferAddSub(a->op_b, b->op_b, op);
- if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
+ InductionInfo* new_a = TransferAddSub(a->op_a, b->op_a, op, type);
+ InductionInfo* new_b = TransferAddSub(a->op_b, b->op_b, op, type);
+ if (new_a != nullptr && new_b != nullptr) {
+ return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
}
} else if (a->induction_class == kInvariant) {
// Rule a + induc(a', b') -> induc(a', a + b') or induc(a + a', a + b').
InductionInfo* new_a = b->op_a;
- InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
+ InductionInfo* new_b = TransferAddSub(a, b->op_b, op, type);
if (b->induction_class == kWrapAround || b->induction_class == kPeriodic) {
- new_a = TransferAddSub(a, new_a, op);
+ new_a = TransferAddSub(a, new_a, op, type);
} else if (op == kSub) { // Negation required.
- new_a = TransferNeg(new_a);
+ new_a = TransferNeg(new_a, type);
}
- if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type_);
+ if (new_a != nullptr && new_b != nullptr) {
+ return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type);
}
} else if (b->induction_class == kInvariant) {
// Rule induc(a, b) + b' -> induc(a, b + b') or induc(a + b', b + b').
InductionInfo* new_a = a->op_a;
- InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
+ InductionInfo* new_b = TransferAddSub(a->op_b, b, op, type);
if (a->induction_class == kWrapAround || a->induction_class == kPeriodic) {
- new_a = TransferAddSub(new_a, b, op);
+ new_a = TransferAddSub(new_a, b, op, type);
}
- if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
+ if (new_a != nullptr && new_b != nullptr) {
+ return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
}
}
}
return nullptr;
}
-HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a,
+ DataType::Type type) {
// Transfer over a unary negation: an invariant, linear, polynomial, geometric (mul),
// wrap-around, or periodic input yields a similar but negated induction as result.
if (a != nullptr) {
@@ -615,10 +672,10 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(Inducti
return CreateInvariantOp(kNeg, nullptr, a); // direct invariant
} else if (a->induction_class != kGeometric || a->operation == kMul) {
// Rule - induc(a, b) -> induc(-a, -b).
- InductionInfo* new_a = TransferNeg(a->op_a);
- InductionInfo* new_b = TransferNeg(a->op_b);
+ InductionInfo* new_a = TransferNeg(a->op_a, type);
+ InductionInfo* new_b = TransferNeg(a->op_b, type);
if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
+ return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
}
}
}
@@ -626,7 +683,8 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(Inducti
}
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
- InductionInfo* b) {
+ InductionInfo* b,
+ DataType::Type type) {
// Transfer over a multiplication: any invariant, linear, polynomial, geometric (mul),
// wrap-around, or periodic can be multiplied with an invariant to yield a similar
// but multiplied result. Two non-invariant inputs cannot be multiplied, however.
@@ -638,18 +696,18 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(Inducti
} else if (a->induction_class == kInvariant && (b->induction_class != kGeometric ||
b->operation == kMul)) {
// Rule a * induc(a', b') -> induc(a * a', b * b').
- InductionInfo* new_a = TransferMul(a, b->op_a);
- InductionInfo* new_b = TransferMul(a, b->op_b);
+ InductionInfo* new_a = TransferMul(a, b->op_a, type);
+ InductionInfo* new_b = TransferMul(a, b->op_b, type);
if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type_);
+ return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type);
}
} else if (b->induction_class == kInvariant && (a->induction_class != kGeometric ||
a->operation == kMul)) {
// Rule induc(a, b) * b' -> induc(a * b', b * b').
- InductionInfo* new_a = TransferMul(a->op_a, b);
- InductionInfo* new_b = TransferMul(a->op_b, b);
+ InductionInfo* new_a = TransferMul(a->op_a, b, type);
+ InductionInfo* new_b = TransferMul(a->op_b, b, type);
if (new_a != nullptr && new_b != nullptr) {
- return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
+ return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type);
}
}
}
@@ -672,17 +730,19 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferConversion(
return nullptr;
}
-HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HInstruction* phi,
- size_t input_index,
- size_t adjust_input_size) {
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(
+ HInstruction* phi,
+ size_t input_index,
+ size_t adjust_input_size,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle) {
// Match all phi inputs from input_index onwards exactly.
HInputsRef inputs = phi->GetInputs();
DCHECK_LT(input_index, inputs.size());
- auto ita = cycle_.find(inputs[input_index]);
- if (ita != cycle_.end()) {
+ auto ita = cycle.find(inputs[input_index]);
+ if (ita != cycle.end()) {
for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
- auto itb = cycle_.find(inputs[i]);
- if (itb == cycle_.end() ||
+ auto itb = cycle.find(inputs[i]);
+ if (itb == cycle.end() ||
!HInductionVarAnalysis::InductionEqual(ita->second, itb->second)) {
return nullptr;
}
@@ -695,9 +755,11 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HInstructi
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhiAllInputs(
HLoopInformation* loop,
HInstruction* entry_phi,
- HInstruction* phi) {
+ HInstruction* phi,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ DataType::Type type) {
// Match all phi inputs.
- InductionInfo* match = SolvePhi(phi, /*input_index*/ 0, /*adjust_input_size*/ 0);
+ InductionInfo* match = SolvePhi(phi, /*input_index=*/ 0, /*adjust_input_size=*/ 0, cycle);
if (match != nullptr) {
return match;
}
@@ -710,76 +772,84 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhiAllInputs(
if (a != nullptr && a->induction_class == kInvariant) {
if (phi->InputAt(1) == entry_phi) {
InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
- return CreateInduction(kPeriodic, kNop, a, initial, /*fetch*/ nullptr, type_);
+ return CreateInduction(kPeriodic, kNop, a, initial, /*fetch*/ nullptr, type);
}
- InductionInfo* b = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
+ InductionInfo* b = SolvePhi(phi, /*input_index=*/ 1, /*adjust_input_size=*/ 0, cycle);
if (b != nullptr && b->induction_class == kPeriodic) {
- return CreateInduction(kPeriodic, kNop, a, b, /*fetch*/ nullptr, type_);
+ return CreateInduction(kPeriodic, kNop, a, b, /*fetch*/ nullptr, type);
}
}
}
return nullptr;
}
-HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
- HInstruction* entry_phi,
- HInstruction* instruction,
- HInstruction* x,
- HInstruction* y,
- InductionOp op,
- bool is_first_call) {
- // Solve within a cycle over an addition or subtraction.
- InductionInfo* b = LookupInfo(loop, y);
- if (b != nullptr) {
- if (b->induction_class == kInvariant) {
- // Adding or subtracting an invariant value, seeded from phi,
- // keeps adding to the stride of the linear induction.
- if (x == entry_phi) {
- return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
- }
- auto it = cycle_.find(x);
- if (it != cycle_.end()) {
- InductionInfo* a = it->second;
- if (a->induction_class == kInvariant) {
- return CreateInvariantOp(op, a, b);
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(
+ HLoopInformation* loop,
+ HInstruction* entry_phi,
+ HInstruction* instruction,
+ HInstruction* x,
+ HInstruction* y,
+ InductionOp op,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ DataType::Type type) {
+ auto main_solve_add_sub = [&]() -> HInductionVarAnalysis::InductionInfo* {
+ // Solve within a cycle over an addition or subtraction.
+ InductionInfo* b = LookupInfo(loop, y);
+ if (b != nullptr) {
+ if (b->induction_class == kInvariant) {
+ // Adding or subtracting an invariant value, seeded from phi,
+ // keeps adding to the stride of the linear induction.
+ if (x == entry_phi) {
+ return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
}
- }
- } else if (b->induction_class == kLinear && b->type == type_) {
- // Solve within a tight cycle that adds a term that is already classified as a linear
- // induction for a polynomial induction k = k + i (represented as sum over linear terms).
- if (x == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
- InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
- InductionInfo* new_a = op == kAdd ? b : TransferNeg(b);
- if (new_a != nullptr) {
- return CreateInduction(kPolynomial, kNop, new_a, initial, /*fetch*/ nullptr, type_);
+ auto it = cycle.find(x);
+ if (it != cycle.end()) {
+ InductionInfo* a = it->second;
+ if (a->induction_class == kInvariant) {
+ return CreateInvariantOp(op, a, b);
+ }
+ }
+ } else if (b->induction_class == kLinear && b->type == type) {
+ // Solve within a tight cycle that adds a term that is already classified as a linear
+ // induction for a polynomial induction k = k + i (represented as sum over linear terms).
+ if (x == entry_phi &&
+ entry_phi->InputCount() == 2 &&
+ instruction == entry_phi->InputAt(1)) {
+ InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
+ InductionInfo* new_a = op == kAdd ? b : TransferNeg(b, type);
+ if (new_a != nullptr) {
+ return CreateInduction(kPolynomial, kNop, new_a, initial, /*fetch*/ nullptr, type);
+ }
}
}
}
- }
-
- // Try some alternatives before failing.
- if (op == kAdd) {
- // Try the other way around for an addition if considered for first time.
- if (is_first_call) {
- return SolveAddSub(loop, entry_phi, instruction, y, x, op, false);
- }
- } else if (op == kSub) {
- // Solve within a tight cycle that is formed by exactly two instructions,
- // one phi and one update, for a periodic idiom of the form k = c - k.
- if (y == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
- InductionInfo* a = LookupInfo(loop, x);
- if (a != nullptr && a->induction_class == kInvariant) {
- InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
- return CreateInduction(kPeriodic,
- kNop,
- CreateInvariantOp(kSub, a, initial),
- initial,
- /*fetch*/ nullptr,
- type_);
+ return nullptr;
+ };
+ HInductionVarAnalysis::InductionInfo* result = main_solve_add_sub();
+ if (result == nullptr) {
+ // Try some alternatives before failing.
+ if (op == kAdd) {
+ // Try the other way around for an addition.
+ std::swap(x, y);
+ result = main_solve_add_sub();
+ } else if (op == kSub) {
+ // Solve within a tight cycle that is formed by exactly two instructions,
+ // one phi and one update, for a periodic idiom of the form k = c - k.
+ if (y == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
+ InductionInfo* a = LookupInfo(loop, x);
+ if (a != nullptr && a->induction_class == kInvariant) {
+ InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
+ result = CreateInduction(kPeriodic,
+ kNop,
+ CreateInvariantOp(kSub, a, initial),
+ initial,
+ /*fetch*/ nullptr,
+ type);
+ }
}
}
}
- return nullptr;
+ return result;
}
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInformation* loop,
@@ -787,7 +857,8 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInform
HInstruction* instruction,
HInstruction* x,
HInstruction* y,
- InductionOp op) {
+ InductionOp op,
+ DataType::Type type) {
// Solve within a tight cycle for a binary operation k = k op c or, for some op, k = c op k.
if (entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
InductionInfo* c = nullptr;
@@ -811,9 +882,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInform
return CreateInduction(kGeometric,
op,
initial,
- CreateConstant(0, type_),
+ CreateConstant(0, type),
c->fetch,
- type_);
+ type);
}
break;
case kRem:
@@ -823,7 +894,7 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInform
initial,
CreateInvariantOp(kRem, initial, c),
/*fetch*/ nullptr,
- type_);
+ type);
case kXor:
// Idiomatic XOR periodic induction.
return CreateInduction(kPeriodic,
@@ -831,7 +902,7 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInform
CreateInvariantOp(kXor, initial, c),
initial,
/*fetch*/ nullptr,
- type_);
+ type);
default:
LOG(FATAL) << op;
UNREACHABLE();
@@ -844,15 +915,16 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInform
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveTest(HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
- int64_t opposite_value) {
+ int64_t opposite_value,
+ DataType::Type type) {
// Detect hidden XOR construction in x = (x == false) or x = (x != true).
int64_t value = -1;
HInstruction* x = instruction->InputAt(0);
HInstruction* y = instruction->InputAt(1);
if (IsExact(LookupInfo(loop, x), &value) && value == opposite_value) {
- return SolveOp(loop, entry_phi, instruction, graph_->GetIntConstant(1), y, kXor);
+ return SolveOp(loop, entry_phi, instruction, graph_->GetIntConstant(1), y, kXor, type);
} else if (IsExact(LookupInfo(loop, y), &value) && value == opposite_value) {
- return SolveOp(loop, entry_phi, instruction, x, graph_->GetIntConstant(1), kXor);
+ return SolveOp(loop, entry_phi, instruction, x, graph_->GetIntConstant(1), kXor, type);
}
return nullptr;
}
@@ -860,7 +932,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveTest(HLoopInfo
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveConversion(
HLoopInformation* loop,
HInstruction* entry_phi,
- HTypeConversion* conversion) {
+ HTypeConversion* conversion,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ /*inout*/ DataType::Type* type) {
DataType::Type from = conversion->GetInputType();
DataType::Type to = conversion->GetResultType();
// A narrowing conversion is allowed as *last* operation of the cycle of a linear induction
@@ -875,9 +949,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveConversion(
if (IsNarrowingIntegralConversion(from, to) &&
IsAtLeast(initial, &value) && value >= min &&
IsAtMost(initial, &value) && value <= max) {
- auto it = cycle_.find(conversion->GetInput());
- if (it != cycle_.end() && it->second->induction_class == kInvariant) {
- type_ = to;
+ auto it = cycle.find(conversion->GetInput());
+ if (it != cycle.end() && it->second->induction_class == kInvariant) {
+ *type = to;
return it->second;
}
}
@@ -1323,10 +1397,10 @@ HInstruction* HInductionVarAnalysis::GetShiftConstant(HLoopInformation* loop,
return nullptr;
}
-void HInductionVarAnalysis::AssignCycle(HPhi* phi) {
+void HInductionVarAnalysis::AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc) {
ArenaSet<HInstruction*>* set = &cycles_.Put(phi, ArenaSet<HInstruction*>(
graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)))->second;
- for (HInstruction* i : scc_) {
+ for (HInstruction* i : scc) {
set->insert(i);
}
}
diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h
index a48aa90059..616100b068 100644
--- a/compiler/optimizing/induction_var_analysis.h
+++ b/compiler/optimizing/induction_var_analysis.h
@@ -19,6 +19,9 @@
#include <string>
+#include "base/arena_containers.h"
+#include "base/array_ref.h"
+#include "base/scoped_arena_containers.h"
#include "nodes.h"
#include "optimization.h"
@@ -42,11 +45,8 @@ class HInductionVarAnalysis : public HOptimization {
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;
- };
+ struct NodeInfo;
+ struct StackEntry;
enum InductionClass {
kInvariant,
@@ -118,9 +118,6 @@ class HInductionVarAnalysis : public HOptimization {
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);
@@ -153,47 +150,65 @@ class HInductionVarAnalysis : public HOptimization {
// Methods for analysis.
void VisitLoop(HLoopInformation* loop);
- void VisitNode(HLoopInformation* loop, HInstruction* instruction);
- uint32_t VisitDescendant(HLoopInformation* loop, HInstruction* instruction);
+ size_t TryVisitNodes(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(HLoopInformation* loop, HInstruction* instruction);
- void ClassifyNonTrivial(HLoopInformation* loop);
- InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
+ void ClassifyNonTrivial(HLoopInformation* loop, ArrayRef<const StackEntry> stack_tail);
+ InductionInfo* RotatePeriodicInduction(InductionInfo* induction,
+ InductionInfo* last,
+ DataType::Type type);
// 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* TransferAddSub(InductionInfo* a,
+ InductionInfo* b,
+ InductionOp op,
+ DataType::Type type);
+ InductionInfo* TransferNeg(InductionInfo* a, DataType::Type type);
+ InductionInfo* TransferMul(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);
+ InductionInfo* SolvePhi(HInstruction* phi,
+ size_t input_index,
+ size_t adjust_input_size,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle);
InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
HInstruction* entry_phi,
- HInstruction* phi);
+ HInstruction* phi,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ DataType::Type type);
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
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ DataType::Type type);
InductionInfo* SolveOp(HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
HInstruction* x,
HInstruction* y,
- InductionOp op);
+ InductionOp op,
+ DataType::Type type);
InductionInfo* SolveTest(HLoopInformation* loop,
HInstruction* entry_phi,
HInstruction* instruction,
- int64_t oppositive_value);
+ int64_t opposite_value,
+ DataType::Type type);
InductionInfo* SolveConversion(HLoopInformation* loop,
HInstruction* entry_phi,
- HTypeConversion* conversion);
+ HTypeConversion* conversion,
+ const ScopedArenaSafeMap<HInstruction*, InductionInfo*>& cycle,
+ /*inout*/ DataType::Type* type);
//
// Loop trip count analysis methods.
@@ -241,7 +256,7 @@ class HInductionVarAnalysis : public HOptimization {
HInstruction* GetShiftConstant(HLoopInformation* loop,
HInstruction* instruction,
InductionInfo* initial);
- void AssignCycle(HPhi* phi);
+ void AssignCycle(HPhi* phi, ArrayRef<HInstruction* const> scc);
ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
// Constants.
@@ -255,16 +270,6 @@ class HInductionVarAnalysis : public HOptimization {
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.
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 23c86ce3f9..9e298a5418 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -2387,7 +2387,7 @@ bool HLoopOptimization::TrySetPhiInduction(HPhi* phi, bool restrict_uses) {
}
bool HLoopOptimization::TrySetPhiReduction(HPhi* phi) {
- DCHECK(iset_->empty());
+ DCHECK(phi->IsLoopHeaderPhi());
// Only unclassified phi cycles are candidates for reductions.
if (induction_range_.IsClassified(phi)) {
return false;
@@ -2399,15 +2399,18 @@ bool HLoopOptimization::TrySetPhiReduction(HPhi* phi) {
HInstruction* reduction = inputs[1];
if (HasReductionFormat(reduction, phi)) {
HLoopInformation* loop_info = phi->GetBlock()->GetLoopInformation();
- uint32_t use_count = 0;
- bool single_use_inside_loop =
+ DCHECK(loop_info->Contains(*reduction->GetBlock()));
+ const bool single_use_inside_loop =
// Reduction update only used by phi.
reduction->GetUses().HasExactlyOneElement() &&
!reduction->HasEnvironmentUses() &&
// Reduction update is only use of phi inside the loop.
- IsOnlyUsedAfterLoop(loop_info, phi, /*collect_loop_uses*/ true, &use_count) &&
- iset_->size() == 1;
- iset_->clear(); // leave the way you found it
+ std::none_of(phi->GetUses().begin(),
+ phi->GetUses().end(),
+ [loop_info, reduction](const HUseListNode<HInstruction*>& use) {
+ HInstruction* user = use.GetUser();
+ return user != reduction && loop_info->Contains(*user->GetBlock());
+ });
if (single_use_inside_loop) {
// Link reduction back, and start recording feed value.
reductions_->Put(reduction, phi);
@@ -2497,8 +2500,7 @@ bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
HInstruction* user = use.GetUser();
if (iset_->find(user) == iset_->end()) { // not excluded?
- HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation();
- if (other_loop_info != nullptr && other_loop_info->IsIn(*loop_info)) {
+ if (loop_info->Contains(*user->GetBlock())) {
// If collect_loop_uses is set, simply keep adding those uses to the set.
// Otherwise, reject uses inside the loop that were not already in the set.
if (collect_loop_uses) {