Allow X86 QBE to be extended

Enhancements and updates to allow X86Mir2LIR Backend to be subclassed
for experimentation.  Add virtual in a whole bunch of places, and make
some other changes to get this to work.

Change-Id: I0980a19bc5d5725f91660f98c95f1f51c17ee9b6
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 52c870b..e717638 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -22,7 +22,7 @@
 
 namespace art {
 
-class X86Mir2Lir FINAL : public Mir2Lir {
+class X86Mir2Lir : public Mir2Lir {
   public:
     X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena, bool gen64bit);
 
@@ -175,8 +175,8 @@
       * @param op The DEX opcode for the operation.
       * @param is_commutative The sources can be swapped if needed.
       */
-    void GenLongArith(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
-                      Instruction::Code op, bool is_commutative);
+    virtual void GenLongArith(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                              Instruction::Code op, bool is_commutative);
 
     /**
       * @brief Generate a two operand long arithmetic operation.
@@ -192,7 +192,7 @@
       * @param rl_src The other operand.  May be in a register or in memory.
       * @param op The DEX opcode for the operation.
       */
-    void GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
+    virtual void GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
 
     /**
      * @brief Implement instanceof a final class with x86 specific code.
@@ -265,6 +265,12 @@
     bool InexpensiveConstantDouble(int64_t value);
 
     /*
+     * @brief Should try to optimize for two address instructions?
+     * @return true if we try to avoid generating three operand instructions.
+     */
+    virtual bool GenerateTwoOperandInstructions() const { return true; }
+
+    /*
      * @brief x86 specific codegen for int operations.
      * @param opcode Operation to perform.
      * @param rl_dest Destination for the result.
@@ -304,7 +310,7 @@
      * @param type How the method will be invoked.
      * @returns Call instruction
      */
-    LIR * CallWithLinkerFixup(const MethodReference& target_method, InvokeType type);
+    virtual LIR * CallWithLinkerFixup(const MethodReference& target_method, InvokeType type);
 
     /*
      * @brief Handle x86 specific literals
@@ -323,7 +329,7 @@
      */
     std::vector<uint8_t>* ReturnCallFrameInformation();
 
-  private:
+  protected:
     size_t ComputeSize(const X86EncodingMap* entry, int base, int displacement, bool has_sib);
     void EmitPrefix(const X86EncodingMap* entry);
     void EmitOpcode(const X86EncodingMap* entry);
@@ -398,6 +404,12 @@
     static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
 
     /*
+     * @brief Ensure that a temporary register is byte addressable.
+     * @returns a temporary guarenteed to be byte addressable.
+     */
+    virtual RegStorage AllocateByteRegister();
+
+    /*
      * @brief generate inline code for fast case of Strng.indexOf.
      * @param info Call parameters
      * @param zero_based 'true' if the index into the string is 0.
@@ -533,7 +545,7 @@
      * @param rl_src The source of the long.
      * @param is_double 'true' if dealing with double, 'false' for float.
      */
-    void GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double);
+    virtual void GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double);
 
     /*
      * @brief Perform MIR analysis before compiling method.
@@ -579,7 +591,7 @@
      * @param bb Basic block containing instruction.
      * @param mir Instruction to analyze.
      */
-    void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
+    virtual void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
 
     /*
      * @brief Analyze one MIR float/double instruction
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 71a3962..a6ccc99 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1292,8 +1292,12 @@
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
-      GenLongArith(rl_dest, rl_src2, op);
-      return;
+      if (GenerateTwoOperandInstructions()) {
+        GenLongArith(rl_dest, rl_src2, op);
+        return;
+      }
+      break;
+
     default:
       break;
   }
@@ -1532,7 +1536,7 @@
 
 RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                           RegLocation rl_src, int shift_amount) {
-  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
   switch (opcode) {
     case Instruction::SHL_LONG:
     case Instruction::SHL_LONG_2ADDR:
@@ -1641,7 +1645,11 @@
     case Instruction::XOR_LONG_2ADDR:
     case Instruction::AND_LONG_2ADDR:
       if (rl_src2.is_const) {
-        GenLongImm(rl_dest, rl_src2, opcode);
+        if (GenerateTwoOperandInstructions()) {
+          GenLongImm(rl_dest, rl_src2, opcode);
+        } else {
+          GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
+        }
       } else {
         DCHECK(rl_src1.is_const);
         GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
@@ -1869,7 +1877,7 @@
 
   // SETcc only works with EAX..EDX.
   if (result_reg == object.reg || result_reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
-    result_reg = AllocTypedTemp(false, kCoreReg);
+    result_reg = AllocateByteRegister();
     DCHECK_LT(result_reg.GetRegNum(), rs_rX86_SP.GetRegNum());
   }
 
@@ -2110,12 +2118,16 @@
       LOG(FATAL) << "Invalid word arith op: " << opcode;
   }
 
-    // Can we convert to a two address instruction?
+  // Can we convert to a two address instruction?
   if (!is_two_addr &&
         (mir_graph_->SRegToVReg(rl_dest.s_reg_low) ==
          mir_graph_->SRegToVReg(rl_lhs.s_reg_low))) {
-      is_two_addr = true;
-    }
+    is_two_addr = true;
+  }
+
+  if (!GenerateTwoOperandInstructions()) {
+    is_two_addr = false;
+  }
 
   // Get the div/rem stuff out of the way.
   if (is_div_rem) {
@@ -2212,6 +2224,8 @@
             if (mir_graph_->SRegToVReg(rl_dest.s_reg_low) == mir_graph_->SRegToVReg(rl_lhs.s_reg_low)) {
               rl_lhs = LoadValue(rl_lhs, kCoreReg);
               rl_result = EvalLoc(rl_dest, kCoreReg, true);
+              // No-op if these are the same.
+              OpRegCopy(rl_result.reg, rl_lhs.reg);
             } else {
               rl_result = EvalLoc(rl_dest, kCoreReg, true);
               LoadValueDirect(rl_lhs, rl_result.reg);
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 8f06791..9ddeb68 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -423,6 +423,10 @@
   UNIMPLEMENTED(FATAL) << "MarkPreservedDouble";
 }
 
+RegStorage X86Mir2Lir::AllocateByteRegister() {
+  return AllocTypedTemp(false, kCoreReg);
+}
+
 /* Clobber all regs that might be used by an external C call */
 void X86Mir2Lir::ClobberCallerSave() {
   Clobber(rs_rAX);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index e9592a6..fed31c1 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -161,6 +161,22 @@
       case kOpMul:
         opcode = byte_imm ? kX86Imul32RRI8 : kX86Imul32RRI;
         return NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), value);
+      case kOp2Byte:
+        opcode = kX86Mov32RI;
+        value = static_cast<int8_t>(value);
+        break;
+      case kOp2Short:
+        opcode = kX86Mov32RI;
+        value = static_cast<int16_t>(value);
+        break;
+      case kOp2Char:
+        opcode = kX86Mov32RI;
+        value = static_cast<uint16_t>(value);
+        break;
+      case kOpNeg:
+        opcode = kX86Mov32RI;
+        value = -value;
+        break;
       default:
         LOG(FATAL) << "Bad case in OpRegImm " << op;
     }
@@ -523,7 +539,7 @@
     int32_t val_hi = High32Bits(value);
     int32_t low_reg_val = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
     LIR *res;
-    bool is_fp = RegStorage::IsFloat(low_reg_val);
+    bool is_fp = r_dest.IsFloat();
     // TODO: clean this up once we fully recognize 64-bit storage containers.
     if (is_fp) {
       if (value == 0) {