More compile-time tuning

Another round of compile-time tuning, this time yeilding in the
vicinity of 3% total reduction in compile time (which means about
double that for the Quick Compile portion).

Primary improvements are skipping the basic block combine optimization
pass when using Quick (because we already have big blocks), combining
the null check elimination and type inference passes, and limiting
expensive local value number analysis to only those blocks which
might benefit from it.

Following this CL, the actual compile phase consumes roughly 60%
of the total dex2oat time on the host, and 55% on the target (Note,
I'm subtracting out the Deduping time here, which the timing logger
normally counts against the compiler).

A sample breakdown of the compilation time follows (this taken on
PlusOne.apk w/ a Nexus 4):

39.00% -> MIR2LIR: 1374.90 (Note: includes local optimization & scheduling)
10.25% -> MIROpt:SSATransform: 361.31
 8.45% -> BuildMIRGraph: 297.80
 7.55% -> Assemble: 266.16
 6.87% -> MIROpt:NCE_TypeInference: 242.22
 5.56% -> Dedupe: 196.15
 3.45% -> MIROpt:BBOpt: 121.53
 3.20% -> RegisterAllocation: 112.69
 3.00% -> PcMappingTable: 105.65
 2.90% -> GcMap: 102.22
 2.68% -> Launchpads: 94.50
 1.16% -> MIROpt:InitRegLoc: 40.94
 1.16% -> Cleanup: 40.93
 1.10% -> MIROpt:CodeLayout: 38.80
 0.97% -> MIROpt:ConstantProp: 34.35
 0.96% -> MIROpt:UseCount: 33.75
 0.86% -> MIROpt:CheckFilters: 30.28
 0.44% -> SpecialMIR2LIR: 15.53
 0.44% -> MIROpt:BBCombine: 15.41

(cherry pick of 9e8e234af4430abe8d144414e272cd72d215b5f3)

Change-Id: I86c665fa7e88b75eb75629a99fd292ff8c449969
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index 32fac0b..bef966c 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -121,260 +121,251 @@
  * as it doesn't propagate.  We're guaranteed at least one pass through
  * the cfg.
  */
-bool MIRGraph::InferTypeAndSize(BasicBlock* bb) {
-  MIR *mir;
-  bool changed = false;   // Did anything change?
+bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) {
+  SSARepresentation *ssa_rep = mir->ssa_rep;
+  if (ssa_rep) {
+    uint64_t attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+    const int* uses = ssa_rep->uses;
+    const int* defs = ssa_rep->defs;
 
-  if (bb->data_flow_info == NULL) return false;
-  if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock)
-    return false;
+    // Handle defs
+    if (attrs & DF_DA) {
+      if (attrs & DF_CORE_A) {
+        changed |= SetCore(defs[0]);
+      }
+      if (attrs & DF_REF_A) {
+        changed |= SetRef(defs[0]);
+      }
+      if (attrs & DF_A_WIDE) {
+        reg_location_[defs[0]].wide = true;
+        reg_location_[defs[1]].wide = true;
+        reg_location_[defs[1]].high_word = true;
+        DCHECK_EQ(SRegToVReg(defs[0])+1,
+        SRegToVReg(defs[1]));
+      }
+    }
 
-  for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
-    SSARepresentation *ssa_rep = mir->ssa_rep;
-    if (ssa_rep) {
-      int attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
-      const int* uses = ssa_rep->uses;
-      const int* defs = ssa_rep->defs;
+    // Handles uses
+    int next = 0;
+    if (attrs & DF_UA) {
+      if (attrs & DF_CORE_A) {
+        changed |= SetCore(uses[next]);
+      }
+      if (attrs & DF_REF_A) {
+        changed |= SetRef(uses[next]);
+      }
+      if (attrs & DF_A_WIDE) {
+        reg_location_[uses[next]].wide = true;
+        reg_location_[uses[next + 1]].wide = true;
+        reg_location_[uses[next + 1]].high_word = true;
+        DCHECK_EQ(SRegToVReg(uses[next])+1,
+        SRegToVReg(uses[next + 1]));
+        next += 2;
+      } else {
+        next++;
+      }
+    }
+    if (attrs & DF_UB) {
+      if (attrs & DF_CORE_B) {
+        changed |= SetCore(uses[next]);
+      }
+      if (attrs & DF_REF_B) {
+        changed |= SetRef(uses[next]);
+      }
+      if (attrs & DF_B_WIDE) {
+        reg_location_[uses[next]].wide = true;
+        reg_location_[uses[next + 1]].wide = true;
+        reg_location_[uses[next + 1]].high_word = true;
+        DCHECK_EQ(SRegToVReg(uses[next])+1,
+                             SRegToVReg(uses[next + 1]));
+        next += 2;
+      } else {
+        next++;
+      }
+    }
+    if (attrs & DF_UC) {
+      if (attrs & DF_CORE_C) {
+        changed |= SetCore(uses[next]);
+      }
+      if (attrs & DF_REF_C) {
+        changed |= SetRef(uses[next]);
+      }
+      if (attrs & DF_C_WIDE) {
+        reg_location_[uses[next]].wide = true;
+        reg_location_[uses[next + 1]].wide = true;
+        reg_location_[uses[next + 1]].high_word = true;
+        DCHECK_EQ(SRegToVReg(uses[next])+1,
+        SRegToVReg(uses[next + 1]));
+      }
+    }
 
-      // Handle defs
-      if (attrs & DF_DA) {
-        if (attrs & DF_CORE_A) {
-          changed |= SetCore(defs[0]);
-        }
-        if (attrs & DF_REF_A) {
-          changed |= SetRef(defs[0]);
-        }
-        if (attrs & DF_A_WIDE) {
-          reg_location_[defs[0]].wide = true;
-          reg_location_[defs[1]].wide = true;
-          reg_location_[defs[1]].high_word = true;
-          DCHECK_EQ(SRegToVReg(defs[0])+1,
-          SRegToVReg(defs[1]));
+    // Special-case return handling
+    if ((mir->dalvikInsn.opcode == Instruction::RETURN) ||
+        (mir->dalvikInsn.opcode == Instruction::RETURN_WIDE) ||
+        (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) {
+      switch (cu_->shorty[0]) {
+          case 'I':
+            changed |= SetCore(uses[0]);
+            break;
+          case 'J':
+            changed |= SetCore(uses[0]);
+            changed |= SetCore(uses[1]);
+            reg_location_[uses[0]].wide = true;
+            reg_location_[uses[1]].wide = true;
+            reg_location_[uses[1]].high_word = true;
+            break;
+          case 'F':
+            changed |= SetFp(uses[0]);
+            break;
+          case 'D':
+            changed |= SetFp(uses[0]);
+            changed |= SetFp(uses[1]);
+            reg_location_[uses[0]].wide = true;
+            reg_location_[uses[1]].wide = true;
+            reg_location_[uses[1]].high_word = true;
+            break;
+          case 'L':
+            changed |= SetRef(uses[0]);
+            break;
+          default: break;
+      }
+    }
+
+    // Special-case handling for format 35c/3rc invokes
+    Instruction::Code opcode = mir->dalvikInsn.opcode;
+    int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes)
+        ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode);
+    if ((flags & Instruction::kInvoke) &&
+        (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
+      DCHECK_EQ(next, 0);
+      int target_idx = mir->dalvikInsn.vB;
+      const char* shorty = GetShortyFromTargetIdx(target_idx);
+      // Handle result type if floating point
+      if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
+        MIR* move_result_mir = FindMoveResult(bb, mir);
+        // Result might not be used at all, so no move-result
+        if (move_result_mir && (move_result_mir->dalvikInsn.opcode !=
+            Instruction::MOVE_RESULT_OBJECT)) {
+          SSARepresentation* tgt_rep = move_result_mir->ssa_rep;
+          DCHECK(tgt_rep != NULL);
+          tgt_rep->fp_def[0] = true;
+          changed |= SetFp(tgt_rep->defs[0]);
+          if (shorty[0] == 'D') {
+            tgt_rep->fp_def[1] = true;
+            changed |= SetFp(tgt_rep->defs[1]);
+          }
         }
       }
-
-      // Handles uses
-      int next = 0;
-      if (attrs & DF_UA) {
-        if (attrs & DF_CORE_A) {
-          changed |= SetCore(uses[next]);
-        }
-        if (attrs & DF_REF_A) {
-          changed |= SetRef(uses[next]);
-        }
-        if (attrs & DF_A_WIDE) {
-          reg_location_[uses[next]].wide = true;
-          reg_location_[uses[next + 1]].wide = true;
-          reg_location_[uses[next + 1]].high_word = true;
-          DCHECK_EQ(SRegToVReg(uses[next])+1,
-          SRegToVReg(uses[next + 1]));
-          next += 2;
-        } else {
-          next++;
-        }
+      int num_uses = mir->dalvikInsn.vA;
+      // If this is a non-static invoke, mark implicit "this"
+      if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) &&
+          (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) {
+        reg_location_[uses[next]].defined = true;
+        reg_location_[uses[next]].ref = true;
+        next++;
       }
-      if (attrs & DF_UB) {
-        if (attrs & DF_CORE_B) {
-          changed |= SetCore(uses[next]);
-        }
-        if (attrs & DF_REF_B) {
-          changed |= SetRef(uses[next]);
-        }
-        if (attrs & DF_B_WIDE) {
-          reg_location_[uses[next]].wide = true;
-          reg_location_[uses[next + 1]].wide = true;
-          reg_location_[uses[next + 1]].high_word = true;
-          DCHECK_EQ(SRegToVReg(uses[next])+1,
-                               SRegToVReg(uses[next + 1]));
-          next += 2;
-        } else {
-          next++;
-        }
-      }
-      if (attrs & DF_UC) {
-        if (attrs & DF_CORE_C) {
-          changed |= SetCore(uses[next]);
-        }
-        if (attrs & DF_REF_C) {
-          changed |= SetRef(uses[next]);
-        }
-        if (attrs & DF_C_WIDE) {
-          reg_location_[uses[next]].wide = true;
-          reg_location_[uses[next + 1]].wide = true;
-          reg_location_[uses[next + 1]].high_word = true;
-          DCHECK_EQ(SRegToVReg(uses[next])+1,
-          SRegToVReg(uses[next + 1]));
-        }
-      }
-
-      // Special-case return handling
-      if ((mir->dalvikInsn.opcode == Instruction::RETURN) ||
-          (mir->dalvikInsn.opcode == Instruction::RETURN_WIDE) ||
-          (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) {
-        switch (cu_->shorty[0]) {
-            case 'I':
-              changed |= SetCore(uses[0]);
+      uint32_t cpos = 1;
+      if (strlen(shorty) > 1) {
+        for (int i = next; i < num_uses;) {
+          DCHECK_LT(cpos, strlen(shorty));
+          switch (shorty[cpos++]) {
+            case 'D':
+              ssa_rep->fp_use[i] = true;
+              ssa_rep->fp_use[i+1] = true;
+              reg_location_[uses[i]].wide = true;
+              reg_location_[uses[i+1]].wide = true;
+              reg_location_[uses[i+1]].high_word = true;
+              DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1]));
+              i++;
               break;
             case 'J':
-              changed |= SetCore(uses[0]);
-              changed |= SetCore(uses[1]);
-              reg_location_[uses[0]].wide = true;
-              reg_location_[uses[1]].wide = true;
-              reg_location_[uses[1]].high_word = true;
+              reg_location_[uses[i]].wide = true;
+              reg_location_[uses[i+1]].wide = true;
+              reg_location_[uses[i+1]].high_word = true;
+              DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1]));
+              changed |= SetCore(uses[i]);
+              i++;
               break;
             case 'F':
-              changed |= SetFp(uses[0]);
-              break;
-            case 'D':
-              changed |= SetFp(uses[0]);
-              changed |= SetFp(uses[1]);
-              reg_location_[uses[0]].wide = true;
-              reg_location_[uses[1]].wide = true;
-              reg_location_[uses[1]].high_word = true;
+              ssa_rep->fp_use[i] = true;
               break;
             case 'L':
-              changed |= SetRef(uses[0]);
+              changed |= SetRef(uses[i]);
               break;
-            default: break;
+            default:
+              changed |= SetCore(uses[i]);
+              break;
+          }
+          i++;
         }
       }
+    }
 
-      // Special-case handling for format 35c/3rc invokes
-      Instruction::Code opcode = mir->dalvikInsn.opcode;
-      int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes)
-          ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode);
-      if ((flags & Instruction::kInvoke) &&
-          (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
-        DCHECK_EQ(next, 0);
-        int target_idx = mir->dalvikInsn.vB;
-        const char* shorty = GetShortyFromTargetIdx(target_idx);
-        // Handle result type if floating point
-        if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
-          MIR* move_result_mir = FindMoveResult(bb, mir);
-          // Result might not be used at all, so no move-result
-          if (move_result_mir && (move_result_mir->dalvikInsn.opcode !=
-              Instruction::MOVE_RESULT_OBJECT)) {
-            SSARepresentation* tgt_rep = move_result_mir->ssa_rep;
-            DCHECK(tgt_rep != NULL);
-            tgt_rep->fp_def[0] = true;
-            changed |= SetFp(tgt_rep->defs[0]);
-            if (shorty[0] == 'D') {
-              tgt_rep->fp_def[1] = true;
-              changed |= SetFp(tgt_rep->defs[1]);
-            }
-          }
-        }
-        int num_uses = mir->dalvikInsn.vA;
-        // If this is a non-static invoke, mark implicit "this"
-        if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) &&
-            (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) {
-          reg_location_[uses[next]].defined = true;
-          reg_location_[uses[next]].ref = true;
-          next++;
-        }
-        uint32_t cpos = 1;
-        if (strlen(shorty) > 1) {
-          for (int i = next; i < num_uses;) {
-            DCHECK_LT(cpos, strlen(shorty));
-            switch (shorty[cpos++]) {
-              case 'D':
-                ssa_rep->fp_use[i] = true;
-                ssa_rep->fp_use[i+1] = true;
-                reg_location_[uses[i]].wide = true;
-                reg_location_[uses[i+1]].wide = true;
-                reg_location_[uses[i+1]].high_word = true;
-                DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1]));
-                i++;
-                break;
-              case 'J':
-                reg_location_[uses[i]].wide = true;
-                reg_location_[uses[i+1]].wide = true;
-                reg_location_[uses[i+1]].high_word = true;
-                DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1]));
-                changed |= SetCore(uses[i]);
-                i++;
-                break;
-              case 'F':
-                ssa_rep->fp_use[i] = true;
-                break;
-              case 'L':
-                changed |= SetRef(uses[i]);
-                break;
-              default:
-                changed |= SetCore(uses[i]);
-                break;
-            }
-            i++;
-          }
-        }
+    for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) {
+      if (ssa_rep->fp_use[i])
+        changed |= SetFp(uses[i]);
       }
-
-      for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) {
-        if (ssa_rep->fp_use[i])
-          changed |= SetFp(uses[i]);
-        }
-      for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) {
-        if (ssa_rep->fp_def[i])
-          changed |= SetFp(defs[i]);
-        }
-      // Special-case handling for moves & Phi
-      if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
-        /*
-         * If any of our inputs or outputs is defined, set all.
-         * Some ugliness related to Phi nodes and wide values.
-         * The Phi set will include all low words or all high
-         * words, so we have to treat them specially.
-         */
-        bool is_phi = (static_cast<int>(mir->dalvikInsn.opcode) ==
-                      kMirOpPhi);
-        RegLocation rl_temp = reg_location_[defs[0]];
-        bool defined_fp = rl_temp.defined && rl_temp.fp;
-        bool defined_core = rl_temp.defined && rl_temp.core;
-        bool defined_ref = rl_temp.defined && rl_temp.ref;
-        bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0);
-        bool is_high = is_phi && rl_temp.wide && rl_temp.high_word;
-        for (int i = 0; i < ssa_rep->num_uses; i++) {
-          rl_temp = reg_location_[uses[i]];
-          defined_fp |= rl_temp.defined && rl_temp.fp;
-          defined_core |= rl_temp.defined && rl_temp.core;
-          defined_ref |= rl_temp.defined && rl_temp.ref;
-          is_wide |= rl_temp.wide;
-          is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
-        }
-        /*
-         * We don't normally expect to see a Dalvik register definition used both as a
-         * floating point and core value, though technically it could happen with constants.
-         * Until we have proper typing, detect this situation and disable register promotion
-         * (which relies on the distinction between core a fp usages).
-         */
-        if ((defined_fp && (defined_core | defined_ref)) &&
-            ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
-          LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file)
-                       << " op at block " << bb->id
-                       << " has both fp and core/ref uses for same def.";
-          cu_->disable_opt |= (1 << kPromoteRegs);
-        }
-        changed |= SetFp(defs[0], defined_fp);
-        changed |= SetCore(defs[0], defined_core);
-        changed |= SetRef(defs[0], defined_ref);
-        changed |= SetWide(defs[0], is_wide);
-        changed |= SetHigh(defs[0], is_high);
-        if (attrs & DF_A_WIDE) {
-          changed |= SetWide(defs[1]);
-          changed |= SetHigh(defs[1]);
-        }
-        for (int i = 0; i < ssa_rep->num_uses; i++) {
-          changed |= SetFp(uses[i], defined_fp);
-          changed |= SetCore(uses[i], defined_core);
-          changed |= SetRef(uses[i], defined_ref);
-          changed |= SetWide(uses[i], is_wide);
-          changed |= SetHigh(uses[i], is_high);
-        }
-        if (attrs & DF_A_WIDE) {
-          DCHECK_EQ(ssa_rep->num_uses, 2);
-          changed |= SetWide(uses[1]);
-          changed |= SetHigh(uses[1]);
-        }
+    for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) {
+      if (ssa_rep->fp_def[i])
+        changed |= SetFp(defs[i]);
+      }
+    // Special-case handling for moves & Phi
+    if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
+      /*
+       * If any of our inputs or outputs is defined, set all.
+       * Some ugliness related to Phi nodes and wide values.
+       * The Phi set will include all low words or all high
+       * words, so we have to treat them specially.
+       */
+      bool is_phi = (static_cast<int>(mir->dalvikInsn.opcode) ==
+                    kMirOpPhi);
+      RegLocation rl_temp = reg_location_[defs[0]];
+      bool defined_fp = rl_temp.defined && rl_temp.fp;
+      bool defined_core = rl_temp.defined && rl_temp.core;
+      bool defined_ref = rl_temp.defined && rl_temp.ref;
+      bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0);
+      bool is_high = is_phi && rl_temp.wide && rl_temp.high_word;
+      for (int i = 0; i < ssa_rep->num_uses; i++) {
+        rl_temp = reg_location_[uses[i]];
+        defined_fp |= rl_temp.defined && rl_temp.fp;
+        defined_core |= rl_temp.defined && rl_temp.core;
+        defined_ref |= rl_temp.defined && rl_temp.ref;
+        is_wide |= rl_temp.wide;
+        is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
+      }
+      /*
+       * We don't normally expect to see a Dalvik register definition used both as a
+       * floating point and core value, though technically it could happen with constants.
+       * Until we have proper typing, detect this situation and disable register promotion
+       * (which relies on the distinction between core a fp usages).
+       */
+      if ((defined_fp && (defined_core | defined_ref)) &&
+          ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
+        LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file)
+                     << " op at block " << bb->id
+                     << " has both fp and core/ref uses for same def.";
+        cu_->disable_opt |= (1 << kPromoteRegs);
+      }
+      changed |= SetFp(defs[0], defined_fp);
+      changed |= SetCore(defs[0], defined_core);
+      changed |= SetRef(defs[0], defined_ref);
+      changed |= SetWide(defs[0], is_wide);
+      changed |= SetHigh(defs[0], is_high);
+      if (attrs & DF_A_WIDE) {
+        changed |= SetWide(defs[1]);
+        changed |= SetHigh(defs[1]);
+      }
+      for (int i = 0; i < ssa_rep->num_uses; i++) {
+        changed |= SetFp(uses[i], defined_fp);
+        changed |= SetCore(uses[i], defined_core);
+        changed |= SetRef(uses[i], defined_ref);
+        changed |= SetWide(uses[i], is_wide);
+        changed |= SetHigh(uses[i], is_high);
+      }
+      if (attrs & DF_A_WIDE) {
+        DCHECK_EQ(ssa_rep->num_uses, 2);
+        changed |= SetWide(uses[1]);
+        changed |= SetHigh(uses[1]);
       }
     }
   }
@@ -417,13 +408,7 @@
                                      INVALID_REG, INVALID_REG, INVALID_SREG,
                                      INVALID_SREG};
 
-/*
- * Simple register allocation.  Some Dalvik virtual registers may
- * be promoted to physical registers.  Most of the work for temp
- * allocation is done on the fly.  We also do some initialization and
- * type inference here.
- */
-void MIRGraph::BuildRegLocations() {
+void MIRGraph::InitRegLocations() {
   /* Allocate the location map */
   RegLocation* loc = static_cast<RegLocation*>(arena_->Alloc(GetNumSSARegs() * sizeof(*loc),
                                                              ArenaAllocator::kAllocRegAlloc));
@@ -493,19 +478,14 @@
         s_reg++;
       }
   }
+}
 
-  /* Do type & size inference pass */
-  RepeatingPreOrderDfsIterator iter(this);
-  bool change = false;
-  for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) {
-    change = InferTypeAndSize(bb);
-  }
-
-  /*
-   * Set the s_reg_low field to refer to the pre-SSA name of the
-   * base Dalvik virtual register.  Once we add a better register
-   * allocator, remove this remapping.
-   */
+/*
+ * Set the s_reg_low field to refer to the pre-SSA name of the
+ * base Dalvik virtual register.  Once we add a better register
+ * allocator, remove this remapping.
+ */
+void MIRGraph::RemapRegLocations() {
   for (int i = 0; i < GetNumSSARegs(); i++) {
     if (reg_location_[i].location != kLocCompilerTemp) {
       int orig_sreg = reg_location_[i].s_reg_low;