GenSpecialCase support for x86

Moved GenSpecialCase from being ARM specific to common code to allow
it to be used by x86 quick as well.

Change-Id: I728733e8f4c4da99af6091ef77e5c76ae0fee850
Signed-off-by: Razvan A Lupusoru <razvan.a.lupusoru@intel.com>
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index a30e80a..b36dde9 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -18,225 +18,11 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
-#include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 
 namespace art {
 
-// TODO: generalize & move to RegUtil.cc
-// The number of dalvik registers passed in core registers.
-constexpr int kInArgsInCoreRegs = 3;
-// The core register corresponding to the first (index 0) input argument.
-constexpr int kInArg0CoreReg = r1;  // r0 is Method*.
-// Offset, in words, for getting args from stack (even core reg args have space on stack).
-constexpr int kInArgToStackOffset = 1;
-
-/* Lock argument if it's in register. */
-void ArmMir2Lir::LockArg(int in_position, bool wide) {
-  if (in_position < kInArgsInCoreRegs) {
-    LockTemp(kInArg0CoreReg + in_position);
-  }
-  if (wide && in_position + 1 < kInArgsInCoreRegs) {
-    LockTemp(kInArg0CoreReg + in_position + 1);
-  }
-}
-
-/* Load argument into register. LockArg(in_position, wide) must have been previously called. */
-int ArmMir2Lir::LoadArg(int in_position, bool wide) {
-  if (in_position < kInArgsInCoreRegs) {
-    int low_reg = kInArg0CoreReg + in_position;
-    if (!wide) {
-      return low_reg;
-    }
-    int high_reg = (in_position != kInArgsInCoreRegs - 1) ? low_reg + 1 : LoadArg(in_position + 1);
-    return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
-  }
-  int low_reg = AllocTemp();
-  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
-  if (!wide) {
-    LoadWordDisp(rARM_SP, offset, low_reg);
-    return low_reg;
-  }
-  int high_reg = AllocTemp();
-  LoadBaseDispWide(rARM_SP, offset, low_reg, high_reg, INVALID_SREG);
-  return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
-}
-
-void ArmMir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
-  int reg = kInArg0CoreReg + in_position;
-  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
-  if (!rl_dest.wide) {
-    if (in_position < kInArgsInCoreRegs) {
-      OpRegCopy(rl_dest.low_reg, reg);
-    } else {
-      LoadWordDisp(rARM_SP, offset, rl_dest.low_reg);
-    }
-  } else {
-    if (in_position < kInArgsInCoreRegs - 1) {
-      OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg, reg, reg + 1);
-    } else if (in_position == kInArgsInCoreRegs - 1) {
-      OpRegCopy(rl_dest.low_reg, reg);
-      LoadWordDisp(rARM_SP, offset + sizeof(uint32_t), rl_dest.high_reg);
-    } else {
-      LoadBaseDispWide(rARM_SP, offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
-    }
-  }
-}
-
-/* Find the next MIR, which may be in a following basic block */
-// TODO: make this a utility in mir_graph.
-MIR* ArmMir2Lir::GetNextMir(BasicBlock** p_bb, MIR* mir) {
-  BasicBlock* bb = *p_bb;
-  MIR* orig_mir = mir;
-  while (bb != NULL) {
-    if (mir != NULL) {
-      mir = mir->next;
-    }
-    if (mir != NULL) {
-      return mir;
-    } else {
-      bb = mir_graph_->GetBasicBlock(bb->fall_through);
-      *p_bb = bb;
-      if (bb) {
-         mir = bb->first_mir_insn;
-         if (mir != NULL) {
-           return mir;
-         }
-      }
-    }
-  }
-  return orig_mir;
-}
-
-/* Used for the "verbose" listing */
-// TODO:  move to common code
-void ArmMir2Lir::GenPrintLabel(MIR* mir) {
-  /* Mark the beginning of a Dalvik instruction for line tracking */
-  if (cu_->verbose) {
-    char* inst_str = mir_graph_->GetDalvikDisassembly(mir);
-    MarkBoundary(mir->offset, inst_str);
-  }
-}
-
-MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
-  // FastInstance() already checked by DexFileMethodInliner.
-  const InlineIGetIPutData& data = special.d.ifield_data;
-  if (data.method_is_static || data.object_arg != 0) {
-    return NULL;  // The object is not "this" and has to be null-checked.
-  }
-
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.object_arg);
-  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
-  int reg_obj = LoadArg(data.object_arg);
-  if (wide) {
-    LoadBaseDispWide(reg_obj, data.field_offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
-  } else {
-    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.low_reg, kWord, INVALID_SREG);
-  }
-  if (data.is_volatile) {
-    GenMemBarrier(kLoadLoad);
-  }
-  return GetNextMir(bb, mir);
-}
-
-MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
-  // FastInstance() already checked by DexFileMethodInliner.
-  const InlineIGetIPutData& data = special.d.ifield_data;
-  if (data.method_is_static || data.object_arg != 0) {
-    return NULL;  // The object is not "this" and has to be null-checked.
-  }
-
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.object_arg);
-  LockArg(data.src_arg, wide);
-  int reg_obj = LoadArg(data.object_arg);
-  int reg_src = LoadArg(data.src_arg, wide);
-  if (data.is_volatile) {
-    GenMemBarrier(kStoreStore);
-  }
-  if (wide) {
-    StoreBaseDispWide(reg_obj, data.field_offset, reg_src & 0xff, reg_src >> 8);
-  } else {
-    StoreBaseDisp(reg_obj, data.field_offset, reg_src, kWord);
-  }
-  if (data.is_volatile) {
-    GenMemBarrier(kLoadLoad);
-  }
-  if (data.is_object) {
-    MarkGCCard(reg_src, reg_obj);
-  }
-  return GetNextMir(bb, mir);
-}
-
-MIR* ArmMir2Lir::SpecialIdentity(MIR* mir, const InlineMethod& special) {
-  const InlineReturnArgData& data = special.d.return_data;
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.arg, wide);
-  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
-  LoadArgDirect(data.arg, rl_dest);
-  return mir;
-}
-
-/*
- * Special-case code genration for simple non-throwing leaf methods.
- */
-void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
-                                const InlineMethod& special) {
-  DCHECK(special.flags & kInlineSpecial);
-  current_dalvik_offset_ = mir->offset;
-  MIR* next_mir = NULL;
-  switch (special.opcode) {
-    case kInlineOpNop:
-      DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
-      next_mir = mir;
-      break;
-    case kInlineOpConst:
-      ArmMir2Lir::GenPrintLabel(mir);
-      LoadConstant(rARM_RET0, static_cast<int>(special.d.data));
-      next_mir = GetNextMir(&bb, mir);
-      break;
-    case kInlineOpIGet:
-      next_mir = SpecialIGet(&bb, mir, special);
-      break;
-    case kInlineOpIPut:
-      next_mir = SpecialIPut(&bb, mir, special);
-      break;
-    case kInlineOpReturnArg:
-      next_mir = SpecialIdentity(mir, special);
-      break;
-    default:
-      return;
-  }
-  if (next_mir != NULL) {
-    current_dalvik_offset_ = next_mir->offset;
-    if (special.opcode != kInlineOpReturnArg) {
-      ArmMir2Lir::GenPrintLabel(next_mir);
-    }
-    NewLIR1(kThumbBx, rARM_LR);
-    core_spill_mask_ = 0;
-    num_core_spills_ = 0;
-    fp_spill_mask_ = 0;
-    num_fp_spills_ = 0;
-    frame_size_ = 0;
-    core_vmap_table_.clear();
-    fp_vmap_table_.clear();
-  }
-}
-
 /*
  * The sparse table in the literal pool is an array of <key,displacement>
  * pairs.  For each set, we'll load them as a pair using ldmia.
@@ -610,4 +396,8 @@
   }
 }
 
+void ArmMir2Lir::GenSpecialExitSequence() {
+  NewLIR1(kThumbBx, rARM_LR);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 7ee241c..65dee80 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -52,6 +52,7 @@
     int AllocTypedTempPair(bool fp_hint, int reg_class);
     int S2d(int low_reg, int high_reg);
     int TargetReg(SpecialTargetRegister reg);
+    int GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -122,6 +123,7 @@
     void GenDivZeroCheck(int reg_lo, int reg_hi);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
+    void GenSpecialExitSequence();
     void GenFillArrayData(DexOffset table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
@@ -136,7 +138,6 @@
     void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
     void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
-    void GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
 
     // Required for target - single operation generators.
     LIR* OpUnconditionalBranch(LIR* target);
@@ -170,7 +171,6 @@
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
                           int s_reg);
     LIR* StoreBaseDispBody(int rBase, int displacement, int r_src, int r_src_hi, OpSize size);
-    void GenPrintLabel(MIR* mir);
     LIR* OpRegRegRegShift(OpKind op, int r_dest, int r_src1, int r_src2, int shift);
     LIR* OpRegRegShift(OpKind op, int r_dest_src1, int r_src2, int shift);
     static const ArmEncodingMap EncodingMap[kArmLast];
@@ -185,13 +185,6 @@
   private:
     void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, int64_t val,
                                   ConditionCode ccode);
-    void LockArg(int in_position, bool wide = false);
-    int LoadArg(int in_position, bool wide = false);
-    void LoadArgDirect(int in_position, RegLocation rl_dest);
-    MIR* GetNextMir(BasicBlock** p_bb, MIR* mir);
-    MIR* SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special);
-    MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
-    MIR* SpecialIdentity(MIR* mir, const InlineMethod& special);
     LIR* LoadFPConstantValue(int r_dest, int value);
     void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
     void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index ceec7d5..83431ad 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -83,6 +83,19 @@
   return res;
 }
 
+int ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
+  switch (arg_num) {
+    case 0:
+      return rARM_ARG1;
+    case 1:
+      return rARM_ARG2;
+    case 2:
+      return rARM_ARG3;
+    default:
+      return INVALID_REG;
+  }
+}
 
 // Create a double from a pair of singles.
 int ArmMir2Lir::S2d(int low_reg, int high_reg) {