diff options
author | 2022-12-16 19:28:47 +0000 | |
---|---|---|
committer | 2023-01-13 16:19:02 +0000 | |
commit | 74da668328e1c501742a864d23ba8c114ece5e64 (patch) | |
tree | a8e6d643230ff9bec8ae8878cd8d1021b813a3e5 | |
parent | 1f3861de4cacb51eacbb624e377b9dc7d7f96cc1 (diff) |
Update the graph flags and check consistency
Check that the flags are up to date in graph checker. Mainly a
correctness check CL but it brings slight code size reduction
(e.g. not needing vreg info if HasMonitorOperations is false).
Update loop_optimization_test to stop using `LocalRun` directly
as it meant that it was breaking assumptions (i.e. top_loop_ was
nullptr when it was expected to have a value).
Bug: 264278131
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I29765b3be46d4bd7c91ea9c80f7565a3c88fae2e
-rw-r--r-- | compiler/optimizing/bounds_check_elimination.cc | 13 | ||||
-rw-r--r-- | compiler/optimizing/builder.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/dead_code_elimination.cc | 33 | ||||
-rw-r--r-- | compiler/optimizing/dead_code_elimination.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/graph_checker.cc | 148 | ||||
-rw-r--r-- | compiler/optimizing/graph_checker.h | 17 | ||||
-rw-r--r-- | compiler/optimizing/load_store_elimination_test.cc | 14 | ||||
-rw-r--r-- | compiler/optimizing/loop_optimization.cc | 9 | ||||
-rw-r--r-- | compiler/optimizing/loop_optimization_test.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 15 |
11 files changed, 225 insertions, 43 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index 66a3b8b506..52f1e9a934 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -564,6 +564,19 @@ class BCEVisitor : public HGraphVisitor { early_exit_loop_.clear(); taken_test_loop_.clear(); finite_loop_.clear(); + + // We may have eliminated all bounds checks so we should update the flag. + // TODO(solanes): Do this without a linear pass of the graph? + GetGraph()->SetHasBoundsChecks(false); + for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (instruction->IsBoundsCheck()) { + GetGraph()->SetHasBoundsChecks(true); + return; + } + } + } } private: diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 9e871c41bc..48d1a9da2f 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -103,7 +103,6 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { graph_->SetNumberOfVRegs(code_item_accessor_.RegistersSize()); graph_->SetNumberOfInVRegs(code_item_accessor_.InsSize()); graph_->SetMaximumNumberOfOutVRegs(code_item_accessor_.OutsSize()); - graph_->SetHasTryCatch(code_item_accessor_.TriesSize() != 0); // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); @@ -168,7 +167,6 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { graph_->SetNumberOfVRegs(return_vregs + num_arg_vregs); graph_->SetNumberOfInVRegs(num_arg_vregs); graph_->SetMaximumNumberOfOutVRegs(num_arg_vregs); - graph_->SetHasTryCatch(false); // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index e15e731fcd..0ce8bfafae 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -629,7 +629,6 @@ bool HDeadCodeElimination::RemoveUnneededTries() { } } - const size_t total_tries = tries.size(); size_t removed_tries = 0; bool any_block_in_loop = false; @@ -641,10 +640,6 @@ bool HDeadCodeElimination::RemoveUnneededTries() { } } - if (removed_tries == total_tries) { - graph_->SetHasTryCatch(false); - } - if (removed_tries != 0) { // We want to: // 1) Update the dominance information @@ -741,6 +736,33 @@ void HDeadCodeElimination::RemoveDeadInstructions() { } } +void HDeadCodeElimination::UpdateGraphFlags() { + bool has_monitor_operations = false; + bool has_simd = false; + bool has_bounds_checks = false; + bool has_always_throwing_invokes = false; + + for (HBasicBlock* block : graph_->GetReversePostOrder()) { + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (instruction->IsMonitorOperation()) { + has_monitor_operations = true; + } else if (instruction->IsVecOperation()) { + has_simd = true; + } else if (instruction->IsBoundsCheck()) { + has_bounds_checks = true; + } else if (instruction->IsInvoke() && instruction->AsInvoke()->AlwaysThrows()) { + has_always_throwing_invokes = true; + } + } + } + + graph_->SetHasMonitorOperations(has_monitor_operations); + graph_->SetHasSIMD(has_simd); + graph_->SetHasBoundsChecks(has_bounds_checks); + graph_->SetHasAlwaysThrowingInvokes(has_always_throwing_invokes); +} + bool HDeadCodeElimination::Run() { // Do not eliminate dead blocks if the graph has irreducible loops. We could // support it, but that would require changes in our loop representation to handle @@ -764,6 +786,7 @@ bool HDeadCodeElimination::Run() { } SsaRedundantPhiElimination(graph_).Run(); RemoveDeadInstructions(); + UpdateGraphFlags(); return true; } diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h index 1988733d75..b91006be0d 100644 --- a/compiler/optimizing/dead_code_elimination.h +++ b/compiler/optimizing/dead_code_elimination.h @@ -48,6 +48,12 @@ class HDeadCodeElimination : public HOptimization { bool SimplifyAlwaysThrows(); bool SimplifyIfs(); void ConnectSuccessiveBlocks(); + // Updates the graph flags related to instructions (e.g. HasSIMD()) since we may have eliminated + // the relevant instructions. There's no need to update `SetHasTryCatch` since we do that in + // `ComputeTryBlockInformation`. Similarly with `HasLoops` and `HasIrreducibleLoops`: They are + // cleared in `ClearLoopInformation` and then set as true as part of `HLoopInformation::Populate`, + // if needed. + void UpdateGraphFlags(); // Helper struct to eliminate tries. struct TryBelongingInformation; diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index b20b53178f..ca29a09440 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -80,9 +80,91 @@ size_t GraphChecker::Run(bool pass_change, size_t last_size) { // as the latter might visit dead blocks removed by the dominator // computation. VisitReversePostOrder(); + CheckGraphFlags(); return current_size; } +void GraphChecker::VisitReversePostOrder() { + for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { + if (block->IsInLoop()) { + flag_info_.seen_loop = true; + if (block->GetLoopInformation()->IsIrreducible()) { + flag_info_.seen_irreducible_loop = true; + } + } + + VisitBasicBlock(block); + } +} + +static const char* StrBool(bool val) { + return val ? "true" : "false"; +} + +void GraphChecker::CheckGraphFlags() { + if (GetGraph()->HasMonitorOperations() != flag_info_.seen_monitor_operation) { + AddError( + StringPrintf("Flag mismatch: HasMonitorOperations() (%s) should be equal to " + "flag_info_.seen_monitor_operation (%s)", + StrBool(GetGraph()->HasMonitorOperations()), + StrBool(flag_info_.seen_monitor_operation))); + } + + if (GetGraph()->HasTryCatch() != flag_info_.seen_try_boundary) { + AddError( + StringPrintf("Flag mismatch: HasTryCatch() (%s) should be equal to " + "flag_info_.seen_try_boundary (%s)", + StrBool(GetGraph()->HasTryCatch()), + StrBool(flag_info_.seen_try_boundary))); + } + + if (GetGraph()->HasLoops() != flag_info_.seen_loop) { + AddError( + StringPrintf("Flag mismatch: HasLoops() (%s) should be equal to " + "flag_info_.seen_loop (%s)", + StrBool(GetGraph()->HasLoops()), + StrBool(flag_info_.seen_loop))); + } + + if (GetGraph()->HasIrreducibleLoops() && !GetGraph()->HasLoops()) { + AddError(StringPrintf("Flag mismatch: HasIrreducibleLoops() (%s) implies HasLoops() (%s)", + StrBool(GetGraph()->HasIrreducibleLoops()), + StrBool(GetGraph()->HasLoops()))); + } + + if (GetGraph()->HasIrreducibleLoops() != flag_info_.seen_irreducible_loop) { + AddError( + StringPrintf("Flag mismatch: HasIrreducibleLoops() (%s) should be equal to " + "flag_info_.seen_irreducible_loop (%s)", + StrBool(GetGraph()->HasIrreducibleLoops()), + StrBool(flag_info_.seen_irreducible_loop))); + } + + if (GetGraph()->HasSIMD() != flag_info_.seen_SIMD) { + AddError( + StringPrintf("Flag mismatch: HasSIMD() (%s) should be equal to " + "flag_info_.seen_SIMD (%s)", + StrBool(GetGraph()->HasSIMD()), + StrBool(flag_info_.seen_SIMD))); + } + + if (GetGraph()->HasBoundsChecks() != flag_info_.seen_bounds_checks) { + AddError( + StringPrintf("Flag mismatch: HasBoundsChecks() (%s) should be equal to " + "flag_info_.seen_bounds_checks (%s)", + StrBool(GetGraph()->HasBoundsChecks()), + StrBool(flag_info_.seen_bounds_checks))); + } + + if (GetGraph()->HasAlwaysThrowingInvokes() != flag_info_.seen_always_throwing_invokes) { + AddError( + StringPrintf("Flag mismatch: HasAlwaysThrowingInvokes() (%s) should be equal to " + "flag_info_.seen_always_throwing_invokes (%s)", + StrBool(GetGraph()->HasAlwaysThrowingInvokes()), + StrBool(flag_info_.seen_always_throwing_invokes))); + } +} + void GraphChecker::VisitBasicBlock(HBasicBlock* block) { current_block_ = block; @@ -310,12 +392,17 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) { VisitInstruction(check); + if (!GetGraph()->HasBoundsChecks()) { - AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, " - "but HasBoundsChecks() returns false", - check->DebugName(), - check->GetId())); + AddError( + StringPrintf("The graph doesn't have the HasBoundsChecks flag set but we saw " + "%s:%d in block %d.", + check->DebugName(), + check->GetId(), + check->GetBlock()->GetBlockId())); } + + flag_info_.seen_bounds_checks = true; } void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) { @@ -356,12 +443,14 @@ void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) { if (!GetGraph()->HasTryCatch()) { AddError( - StringPrintf("The graph doesn't have the HasTryCatch bit set but we saw " + StringPrintf("The graph doesn't have the HasTryCatch flag set but we saw " "%s:%d in block %d.", try_boundary->DebugName(), try_boundary->GetId(), try_boundary->GetBlock()->GetBlockId())); } + + flag_info_.seen_try_boundary = true; } void GraphChecker::VisitLoadException(HLoadException* load) { @@ -387,12 +476,14 @@ void GraphChecker::VisitMonitorOperation(HMonitorOperation* monitor_op) { if (!GetGraph()->HasMonitorOperations()) { AddError( - StringPrintf("The graph doesn't have the HasMonitorOperations bit set but we saw " + StringPrintf("The graph doesn't have the HasMonitorOperations flag set but we saw " "%s:%d in block %d.", monitor_op->DebugName(), monitor_op->GetId(), monitor_op->GetBlock()->GetBlockId())); } + + flag_info_.seen_monitor_operation = true; } void GraphChecker::VisitInstruction(HInstruction* instruction) { @@ -573,9 +664,26 @@ void GraphChecker::VisitInstruction(HInstruction* instruction) { } } -void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { +void GraphChecker::VisitInvoke(HInvoke* invoke) { VisitInstruction(invoke); + if (invoke->AlwaysThrows()) { + if (!GetGraph()->HasAlwaysThrowingInvokes()) { + AddError( + StringPrintf("The graph doesn't have the HasAlwaysThrowingInvokes flag set but we saw " + "%s:%d in block %d and it always throws.", + invoke->DebugName(), + invoke->GetId(), + invoke->GetBlock()->GetBlockId())); + } + flag_info_.seen_always_throwing_invokes = true; + } +} + +void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { + // We call VisitInvoke and not VisitInstruction to de-duplicate the always throwing code check. + VisitInvoke(invoke); + if (invoke->IsStaticWithExplicitClinitCheck()) { const HInstruction* last_input = invoke->GetInputs().back(); if (last_input == nullptr) { @@ -1089,13 +1197,13 @@ void GraphChecker::VisitArraySet(HArraySet* instruction) { if (instruction->NeedsTypeCheck() != instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC())) { - AddError(StringPrintf( - "%s %d has a flag mismatch. An ArraySet instruction can trigger a GC iff it " - "needs a type check. Needs type check: %s, Can trigger GC: %s", - instruction->DebugName(), - instruction->GetId(), - instruction->NeedsTypeCheck() ? "true" : "false", - instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC()) ? "true" : "false")); + AddError( + StringPrintf("%s %d has a flag mismatch. An ArraySet instruction can trigger a GC iff it " + "needs a type check. Needs type check: %s, Can trigger GC: %s", + instruction->DebugName(), + instruction->GetId(), + StrBool(instruction->NeedsTypeCheck()), + StrBool(instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC())))); } } @@ -1199,6 +1307,18 @@ void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) { void GraphChecker::VisitVecOperation(HVecOperation* instruction) { VisitInstruction(instruction); + + if (!GetGraph()->HasSIMD()) { + AddError( + StringPrintf("The graph doesn't have the HasSIMD flag set but we saw " + "%s:%d in block %d.", + instruction->DebugName(), + instruction->GetId(), + instruction->GetBlock()->GetBlockId())); + } + + flag_info_.seen_SIMD = true; + if (codegen_ == nullptr) { return; } diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h index 738c0d6d3e..674798e20b 100644 --- a/compiler/optimizing/graph_checker.h +++ b/compiler/optimizing/graph_checker.h @@ -66,6 +66,7 @@ class GraphChecker : public HGraphDelegateVisitor { void VisitDeoptimize(HDeoptimize* instruction) override; void VisitIf(HIf* instruction) override; void VisitInstanceOf(HInstanceOf* check) override; + void VisitInvoke(HInvoke* invoke) override; void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) override; void VisitLoadException(HLoadException* load) override; void VisitMonitorOperation(HMonitorOperation* monitor_operation) override; @@ -126,6 +127,11 @@ class GraphChecker : public HGraphDelegateVisitor { ArenaVector<std::string> errors_; private: + void VisitReversePostOrder(); + + // Checks that the graph's flags are set correctly. + void CheckGraphFlags(); + // String displayed before dumped errors. const char* const dump_prefix_; ScopedArenaAllocator allocator_; @@ -138,6 +144,17 @@ class GraphChecker : public HGraphDelegateVisitor { // Used to access target information. CodeGenerator* codegen_; + struct FlagInfo { + bool seen_try_boundary = false; + bool seen_monitor_operation = false; + bool seen_loop = false; + bool seen_irreducible_loop = false; + bool seen_SIMD = false; + bool seen_bounds_checks = false; + bool seen_always_throwing_invokes = false; + }; + FlagInfo flag_info_; + DISALLOW_COPY_AND_ASSIGN(GraphChecker); }; diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc index b1c48050f0..a7a97f667f 100644 --- a/compiler/optimizing/load_store_elimination_test.cc +++ b/compiler/optimizing/load_store_elimination_test.cc @@ -542,6 +542,7 @@ TEST_F(LoadStoreEliminationTest, SameHeapValue2) { AddVecStore(entry_block_, array_, j_); HInstruction* vstore = AddVecStore(entry_block_, array_, i_); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vstore)); @@ -557,6 +558,7 @@ TEST_F(LoadStoreEliminationTest, SameHeapValue3) { AddVecStore(entry_block_, array_, i_add1_); HInstruction* vstore = AddVecStore(entry_block_, array_, i_); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vstore)); @@ -601,6 +603,7 @@ TEST_F(LoadStoreEliminationTest, OverlappingLoadStore) { AddArraySet(entry_block_, array_, i_, c1); HInstruction* vload5 = AddVecLoad(entry_block_, array_, i_); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_TRUE(IsRemoved(load1)); @@ -634,6 +637,7 @@ TEST_F(LoadStoreEliminationTest, StoreAfterLoopWithoutSideEffects) { // a[j] = 1; HInstruction* array_set = AddArraySet(return_block_, array_, j_, c1); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_TRUE(IsRemoved(array_set)); @@ -671,6 +675,7 @@ TEST_F(LoadStoreEliminationTest, StoreAfterSIMDLoopWithSideEffects) { // a[j] = 0; HInstruction* a_set = AddArraySet(return_block_, array_, j_, c0); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_TRUE(IsRemoved(vload)); @@ -709,6 +714,7 @@ TEST_F(LoadStoreEliminationTest, LoadAfterSIMDLoopWithSideEffects) { // x = a[j]; HInstruction* load = AddArrayGet(return_block_, array_, j_); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_TRUE(IsRemoved(vload)); @@ -749,6 +755,7 @@ TEST_F(LoadStoreEliminationTest, MergePredecessorVecStores) { // down: a[i,... i + 3] = [1,...1] HInstruction* vstore4 = AddVecStore(down, array_, i_, vdata); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_TRUE(IsRemoved(vstore2)); @@ -839,6 +846,7 @@ TEST_F(LoadStoreEliminationTest, RedundantVStoreVLoadInLoop) { HInstruction* vstore2 = AddVecStore(loop_, array_b, phi_, vload->AsVecLoad()); HInstruction* vstore3 = AddVecStore(loop_, array_a, phi_, vstore1->InputAt(2)); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vstore1)); @@ -926,6 +934,7 @@ TEST_F(LoadStoreEliminationTest, VLoadDefaultValueInLoopWithoutWriteSideEffects) HInstruction* vload = AddVecLoad(loop_, array_a, phi_); HInstruction* vstore = AddVecStore(return_block_, array_, c0, vload->AsVecLoad()); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload)); @@ -949,6 +958,7 @@ TEST_F(LoadStoreEliminationTest, VLoadDefaultValue) { HInstruction* vload = AddVecLoad(pre_header_, array_a, c0); HInstruction* vstore = AddVecStore(return_block_, array_, c0, vload->AsVecLoad()); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload)); @@ -1025,6 +1035,7 @@ TEST_F(LoadStoreEliminationTest, VLoadAndLoadDefaultValueInLoopWithoutWriteSideE HInstruction* vstore = AddVecStore(return_block_, array_, c0, vload->AsVecLoad()); HInstruction* store = AddArraySet(return_block_, array_, c0, load); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload)); @@ -1055,6 +1066,7 @@ TEST_F(LoadStoreEliminationTest, VLoadAndLoadDefaultValue) { HInstruction* vstore = AddVecStore(return_block_, array_, c0, vload->AsVecLoad()); HInstruction* store = AddArraySet(return_block_, array_, c0, load); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload)); @@ -1086,6 +1098,7 @@ TEST_F(LoadStoreEliminationTest, VLoadDefaultValueAndVLoadInLoopWithoutWriteSide HInstruction* vstore1 = AddVecStore(return_block_, array_, c0, vload1->AsVecLoad()); HInstruction* vstore2 = AddVecStore(return_block_, array_, c128, vload2->AsVecLoad()); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload1)); @@ -1116,6 +1129,7 @@ TEST_F(LoadStoreEliminationTest, VLoadDefaultValueAndVLoad) { HInstruction* vstore1 = AddVecStore(return_block_, array_, c0, vload1->AsVecLoad()); HInstruction* vstore2 = AddVecStore(return_block_, array_, c128, vload2->AsVecLoad()); + graph_->SetHasSIMD(true); PerformLSE(); ASSERT_FALSE(IsRemoved(vload1)); diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 001649cb9f..7a52502562 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -507,9 +507,8 @@ bool HLoopOptimization::Run() { graph_->SetHasLoops(false); // no more loops } - // Detach. + // Detach allocator. loop_allocator_ = nullptr; - last_loop_ = top_loop_ = nullptr; return did_loop_opt; } @@ -530,11 +529,7 @@ bool HLoopOptimization::LocalRun() { AddLoop(block->GetLoopInformation()); } } - - // TODO(solanes): How can `top_loop_` be null if `graph_->HasLoops()` is true? - if (top_loop_ == nullptr) { - return false; - } + DCHECK(top_loop_ != nullptr); // Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use // temporary data structures using the phase-local allocator. All new HIR diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc index 71c69886f6..7f694fb655 100644 --- a/compiler/optimizing/loop_optimization_test.cc +++ b/compiler/optimizing/loop_optimization_test.cc @@ -95,10 +95,7 @@ class LoopOptimizationTest : public OptimizingUnitTest { void PerformAnalysis() { graph_->BuildDominatorTree(); iva_->Run(); - // Do not release the loop hierarchy. - ScopedArenaAllocator loop_allocator(GetArenaStack()); - loop_opt_->loop_allocator_ = &loop_allocator; - loop_opt_->LocalRun(); + loop_opt_->Run(); } /** Constructs string representation of computed loop hierarchy. */ diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 0e85838862..0876ce070e 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -262,6 +262,7 @@ void HGraph::ClearDominanceInformation() { } void HGraph::ClearLoopInformation() { + SetHasLoops(false); SetHasIrreducibleLoops(false); for (HBasicBlock* block : GetActiveBlocks()) { block->SetLoopInformation(nullptr); @@ -742,6 +743,8 @@ void HGraph::SimplifyLoop(HBasicBlock* header) { void HGraph::ComputeTryBlockInformation() { // Iterate in reverse post order to propagate try membership information from // predecessors to their successors. + bool graph_has_try_catch = false; + for (HBasicBlock* block : GetReversePostOrder()) { if (block->IsEntryBlock() || block->IsCatchBlock()) { // Catch blocks after simplification have only exceptional predecessors @@ -756,6 +759,7 @@ void HGraph::ComputeTryBlockInformation() { DCHECK_IMPLIES(block->IsLoopHeader(), !block->GetLoopInformation()->IsBackEdge(*first_predecessor)); const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors(); + graph_has_try_catch |= try_entry != nullptr; if (try_entry != nullptr && (block->GetTryCatchInformation() == nullptr || try_entry != &block->GetTryCatchInformation()->GetTryEntry())) { @@ -764,6 +768,8 @@ void HGraph::ComputeTryBlockInformation() { block->SetTryCatchInformation(new (allocator_) TryCatchInformation(*try_entry)); } } + + SetHasTryCatch(graph_has_try_catch); } void HGraph::SimplifyCFG() { diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index f33b0d8e96..8f7635aa21 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -811,14 +811,11 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { size_t temporaries_vreg_slots_; // Flag whether there are bounds checks in the graph. We can skip - // BCE if it's false. It's only best effort to keep it up to date in - // the presence of code elimination so there might be false positives. + // BCE if it's false. bool has_bounds_checks_; // Flag whether there are try/catch blocks in the graph. We will skip - // try/catch-related passes if it's false. It's only best effort to keep - // it up to date in the presence of code elimination so there might be - // false positives. + // try/catch-related passes if it's false. bool has_try_catch_; // Flag whether there are any HMonitorOperation in the graph. If yes this will mandate @@ -831,14 +828,10 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { bool has_simd_; // Flag whether there are any loops in the graph. We can skip loop - // optimization if it's false. It's only best effort to keep it up - // to date in the presence of code elimination so there might be false - // positives. + // optimization if it's false. bool has_loops_; - // Flag whether there are any irreducible loops in the graph. It's only - // best effort to keep it up to date in the presence of code elimination - // so there might be false positives. + // Flag whether there are any irreducible loops in the graph. bool has_irreducible_loops_; // Flag whether there are any direct calls to native code registered |