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
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 66a3b8b..52f1e9a 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -564,6 +564,19 @@
     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 9e871c4..48d1a9d 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -103,7 +103,6 @@
   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 @@
   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 e15e731..0ce8bfa 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -629,7 +629,6 @@
     }
   }
 
-  const size_t total_tries = tries.size();
   size_t removed_tries = 0;
   bool any_block_in_loop = false;
 
@@ -641,10 +640,6 @@
     }
   }
 
-  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::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 @@
   }
   SsaRedundantPhiElimination(graph_).Run();
   RemoveDeadInstructions();
+  UpdateGraphFlags();
   return true;
 }
 
diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h
index 1988733..b91006b 100644
--- a/compiler/optimizing/dead_code_elimination.h
+++ b/compiler/optimizing/dead_code_elimination.h
@@ -48,6 +48,12 @@
   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 b20b531..ca29a09 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -80,9 +80,91 @@
   // 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::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 @@
 
   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 @@
 
   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::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 @@
 
   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::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 738c0d6..674798e 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -66,6 +66,7 @@
   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 @@
   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 @@
   // 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 b1c48050..a7a97f6 100644
--- a/compiler/optimizing/load_store_elimination_test.cc
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -542,6 +542,7 @@
   AddVecStore(entry_block_, array_, j_);
   HInstruction* vstore = AddVecStore(entry_block_, array_, i_);
 
+  graph_->SetHasSIMD(true);
   PerformLSE();
 
   ASSERT_FALSE(IsRemoved(vstore));
@@ -557,6 +558,7 @@
   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 @@
   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 @@
   // 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 @@
   // a[j] = 0;
   HInstruction* a_set = AddArraySet(return_block_, array_, j_, c0);
 
+  graph_->SetHasSIMD(true);
   PerformLSE();
 
   ASSERT_TRUE(IsRemoved(vload));
@@ -709,6 +714,7 @@
   // x = a[j];
   HInstruction* load = AddArrayGet(return_block_, array_, j_);
 
+  graph_->SetHasSIMD(true);
   PerformLSE();
 
   ASSERT_TRUE(IsRemoved(vload));
@@ -749,6 +755,7 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 001649c..7a52502 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -507,9 +507,8 @@
     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 @@
       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 71c6988..7f694fb 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -95,10 +95,7 @@
   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 0e85838..0876ce0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -262,6 +262,7 @@
 }
 
 void HGraph::ClearLoopInformation() {
+  SetHasLoops(false);
   SetHasIrreducibleLoops(false);
   for (HBasicBlock* block : GetActiveBlocks()) {
     block->SetLoopInformation(nullptr);
@@ -742,6 +743,8 @@
 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 @@
     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 @@
       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 f33b0d8..8f7635a 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -811,14 +811,11 @@
   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 @@
   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