Step 2 of 2: conditional passes.

Rationale:
The change introduces actual conditional passes
(dependence on inliner). This ensures more
cases are optimized downstream without
needlessly introducing compile-time.

NOTE:
Some checker tests needed to be rewritten
due to subtle changes in the phase ordering.
No optimizations were harmed in the process,
though.

Bug: b/78171933, b/74026074

Test: test-art-host,target

Change-Id: I335260df780e14ba1f22499ad74d79060c7be44d
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f68bcbe..a6163a7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -313,11 +313,22 @@
         dex_compilation_unit,
         handles);
     DCHECK_EQ(length, optimizations.size());
-    // Run the optimization passes one by one.
+    // Run the optimization passes one by one. Any "depends_on" pass refers back to
+    // the most recent occurrence of that pass, skipped or executed.
+    std::bitset<static_cast<size_t>(OptimizationPass::kLast) + 1u> pass_changes;
+    pass_changes[static_cast<size_t>(OptimizationPass::kNone)] = true;
     bool change = false;
     for (size_t i = 0; i < length; ++i) {
-      PassScope scope(optimizations[i]->GetPassName(), pass_observer);
-      change |= optimizations[i]->Run();
+      if (pass_changes[static_cast<size_t>(definitions[i].depends_on)]) {
+        // Execute the pass and record whether it changed anything.
+        PassScope scope(optimizations[i]->GetPassName(), pass_observer);
+        bool pass_change = optimizations[i]->Run();
+        pass_changes[static_cast<size_t>(definitions[i].pass)] = pass_change;
+        change |= pass_change;
+      } else {
+        // Skip the pass and record that nothing changed.
+        pass_changes[static_cast<size_t>(definitions[i].pass)] = false;
+      }
     }
     return change;
   }
@@ -579,6 +590,7 @@
   if (pass_names != nullptr) {
     // If passes were defined on command-line, build the optimization
     // passes and run these instead of the built-in optimizations.
+    // TODO: a way to define depends_on via command-line?
     const size_t length = pass_names->size();
     std::vector<OptimizationDef> optimizations;
     for (const std::string& pass_name : *pass_names) {
@@ -596,36 +608,63 @@
   }
 
   OptimizationDef optimizations[] = {
+    // Initial optimizations.
     OptDef(OptimizationPass::kIntrinsicsRecognizer),
     OptDef(OptimizationPass::kSharpening),
     OptDef(OptimizationPass::kConstantFolding),
     OptDef(OptimizationPass::kInstructionSimplifier),
-    OptDef(OptimizationPass::kDeadCodeElimination, "dead_code_elimination$initial"),
+    OptDef(OptimizationPass::kDeadCodeElimination,
+           "dead_code_elimination$initial"),
+    // Inlining.
     OptDef(OptimizationPass::kInliner),
-    OptDef(OptimizationPass::kSideEffectsAnalysis,   "side_effects$before_gvn"),
+    // Simplification (only if inlining occurred).
+    OptDef(OptimizationPass::kConstantFolding,
+           "constant_folding$after_inlining",
+           OptimizationPass::kInliner),
+    OptDef(OptimizationPass::kInstructionSimplifier,
+           "instruction_simplifier$after_inlining",
+           OptimizationPass::kInliner),
+    OptDef(OptimizationPass::kDeadCodeElimination,
+           "dead_code_elimination$after_inlining",
+           OptimizationPass::kInliner),
+    // GVN.
+    OptDef(OptimizationPass::kSideEffectsAnalysis,
+           "side_effects$before_gvn"),
     OptDef(OptimizationPass::kGlobalValueNumbering),
+    // Simplification (TODO: only if GVN occurred).
     OptDef(OptimizationPass::kSelectGenerator),
-    OptDef(OptimizationPass::kConstantFolding,       "constant_folding$after_inlining"),
-    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_inlining"),
-    OptDef(OptimizationPass::kDeadCodeElimination,   "dead_code_elimination$after_inlining"),
-    OptDef(OptimizationPass::kSideEffectsAnalysis,   "side_effects$before_licm"),
+    OptDef(OptimizationPass::kConstantFolding,
+           "constant_folding$after_gvn"),
+    OptDef(OptimizationPass::kInstructionSimplifier,
+           "instruction_simplifier$after_gvn"),
+    OptDef(OptimizationPass::kDeadCodeElimination,
+           "dead_code_elimination$after_gvn"),
+    // High-level optimizations.
+    OptDef(OptimizationPass::kSideEffectsAnalysis,
+           "side_effects$before_licm"),
     OptDef(OptimizationPass::kInvariantCodeMotion),
     OptDef(OptimizationPass::kInductionVarAnalysis),
     OptDef(OptimizationPass::kBoundsCheckElimination),
     OptDef(OptimizationPass::kLoopOptimization),
-    // Evaluates code generated by dynamic bce.
-    OptDef(OptimizationPass::kConstantFolding,       "constant_folding$after_bce"),
-    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_bce"),
-    OptDef(OptimizationPass::kSideEffectsAnalysis,   "side_effects$before_lse"),
+    // Simplification.
+    OptDef(OptimizationPass::kConstantFolding,
+           "constant_folding$after_bce"),
+    OptDef(OptimizationPass::kInstructionSimplifier,
+           "instruction_simplifier$after_bce"),
+    // Other high-level optimizations.
+    OptDef(OptimizationPass::kSideEffectsAnalysis,
+           "side_effects$before_lse"),
     OptDef(OptimizationPass::kLoadStoreAnalysis),
     OptDef(OptimizationPass::kLoadStoreElimination),
     OptDef(OptimizationPass::kCHAGuardOptimization),
-    OptDef(OptimizationPass::kDeadCodeElimination,   "dead_code_elimination$final"),
+    OptDef(OptimizationPass::kDeadCodeElimination,
+           "dead_code_elimination$final"),
     OptDef(OptimizationPass::kCodeSinking),
     // The codegen has a few assumptions that only the instruction simplifier
     // can satisfy. For example, the code generator does not expect to see a
     // HTypeConversion from a type to the same type.
-    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$before_codegen"),
+    OptDef(OptimizationPass::kInstructionSimplifier,
+           "instruction_simplifier$before_codegen"),
     // Eliminate constructor fences after code sinking to avoid
     // complicated sinking logic to split a fence with many inputs.
     OptDef(OptimizationPass::kConstructorFenceRedundancyElimination)