summaryrefslogtreecommitdiff
path: root/compiler/optimizing/loop_optimization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/loop_optimization.cc')
-rw-r--r--compiler/optimizing/loop_optimization.cc107
1 files changed, 75 insertions, 32 deletions
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 77dfe68bf6..2d7c20825c 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -491,9 +491,9 @@ HLoopOptimization::HLoopOptimization(HGraph* graph,
}
bool HLoopOptimization::Run() {
- // Skip if there is no loop or the graph has try-catch/irreducible loops.
+ // Skip if there is no loop or the graph has irreducible loops.
// TODO: make this less of a sledgehammer.
- if (!graph_->HasLoops() || graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) {
+ if (!graph_->HasLoops() || graph_->HasIrreducibleLoops()) {
return false;
}
@@ -502,7 +502,7 @@ bool HLoopOptimization::Run() {
loop_allocator_ = &allocator;
// Perform loop optimizations.
- bool didLoopOpt = LocalRun();
+ const bool did_loop_opt = LocalRun();
if (top_loop_ == nullptr) {
graph_->SetHasLoops(false); // no more loops
}
@@ -511,7 +511,7 @@ bool HLoopOptimization::Run() {
loop_allocator_ = nullptr;
last_loop_ = top_loop_ = nullptr;
- return didLoopOpt;
+ return did_loop_opt;
}
//
@@ -519,7 +519,6 @@ bool HLoopOptimization::Run() {
//
bool HLoopOptimization::LocalRun() {
- bool didLoopOpt = false;
// Build the linear order using the phase-local allocator. This step enables building
// a loop hierarchy that properly reflects the outer-inner and previous-next relation.
ScopedArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder));
@@ -532,34 +531,37 @@ bool HLoopOptimization::LocalRun() {
}
}
+ // TODO(solanes): How can `top_loop_` be null if `graph_->HasLoops()` is true?
+ if (top_loop_ == nullptr) {
+ return false;
+ }
+
// Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use
// temporary data structures using the phase-local allocator. All new HIR
// should use the global allocator.
- if (top_loop_ != nullptr) {
- ScopedArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> reds(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSet<ArrayReference> refs(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> map(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> perm(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- // Attach.
- iset_ = &iset;
- reductions_ = &reds;
- vector_refs_ = &refs;
- vector_map_ = &map;
- vector_permanent_map_ = &perm;
- // Traverse.
- didLoopOpt = TraverseLoopsInnerToOuter(top_loop_);
- // Detach.
- iset_ = nullptr;
- reductions_ = nullptr;
- vector_refs_ = nullptr;
- vector_map_ = nullptr;
- vector_permanent_map_ = nullptr;
- }
- return didLoopOpt;
+ ScopedArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> reds(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSet<ArrayReference> refs(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> map(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> perm(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ // Attach.
+ iset_ = &iset;
+ reductions_ = &reds;
+ vector_refs_ = &refs;
+ vector_map_ = &map;
+ vector_permanent_map_ = &perm;
+ // Traverse.
+ const bool did_loop_opt = TraverseLoopsInnerToOuter(top_loop_);
+ // Detach.
+ iset_ = nullptr;
+ reductions_ = nullptr;
+ vector_refs_ = nullptr;
+ vector_map_ = nullptr;
+ vector_permanent_map_ = nullptr;
+ return did_loop_opt;
}
void HLoopOptimization::AddLoop(HLoopInformation* loop_info) {
@@ -618,6 +620,18 @@ bool HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
induction_range_.ReVisit(node->loop_info);
changed = true;
}
+
+ CalculateAndSetTryCatchKind(node);
+ if (node->try_catch_kind == LoopNode::TryCatchKind::kHasTryCatch) {
+ // The current optimizations assume that the loops do not contain try/catches.
+ // TODO(solanes, 227283906): Assess if we can modify them to work with try/catches.
+ continue;
+ }
+
+ DCHECK(node->try_catch_kind == LoopNode::TryCatchKind::kNoTryCatch)
+ << "kind: " << static_cast<int>(node->try_catch_kind)
+ << ". LoopOptimization requires the loops to not have try catches.";
+
// Repeat simplifications in the loop-body until no more changes occur.
// Note that since each simplification consists of eliminating code (without
// introducing new code), this process is always finite.
@@ -635,6 +649,37 @@ bool HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
return changed;
}
+void HLoopOptimization::CalculateAndSetTryCatchKind(LoopNode* node) {
+ DCHECK(node != nullptr);
+ DCHECK(node->try_catch_kind == LoopNode::TryCatchKind::kUnknown)
+ << "kind: " << static_cast<int>(node->try_catch_kind)
+ << ". SetTryCatchKind should be called only once per LoopNode.";
+
+ // If a inner loop has a try catch, then the outer loop has one too (as it contains `inner`).
+ // Knowing this, we could skip iterating through all of the outer loop's parents with a simple
+ // check.
+ for (LoopNode* inner = node->inner; inner != nullptr; inner = inner->next) {
+ DCHECK(inner->try_catch_kind != LoopNode::TryCatchKind::kUnknown)
+ << "kind: " << static_cast<int>(inner->try_catch_kind)
+ << ". Should have updated the inner loop before the outer loop.";
+
+ if (inner->try_catch_kind == LoopNode::TryCatchKind::kHasTryCatch) {
+ node->try_catch_kind = LoopNode::TryCatchKind::kHasTryCatch;
+ return;
+ }
+ }
+
+ for (HBlocksInLoopIterator it_loop(*node->loop_info); !it_loop.Done(); it_loop.Advance()) {
+ HBasicBlock* block = it_loop.Current();
+ if (block->GetTryCatchInformation() != nullptr) {
+ node->try_catch_kind = LoopNode::TryCatchKind::kHasTryCatch;
+ return;
+ }
+ }
+
+ node->try_catch_kind = LoopNode::TryCatchKind::kNoTryCatch;
+}
+
//
// Optimization.
//
@@ -782,8 +827,6 @@ bool HLoopOptimization::OptimizeInnerLoop(LoopNode* node) {
return TryOptimizeInnerLoopFinite(node) || TryPeelingAndUnrolling(node);
}
-
-
//
// Scalar loop peeling and unrolling: generic part methods.
//