Merge "Support Literal pools for x86"
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index debcb5c..f8706c4 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -647,7 +647,7 @@
   }
 
   RegLocation GetRegLocation(int index) {
-    DCHECK((index >= 0) && (index > num_ssa_regs_));
+    DCHECK((index >= 0) && (index < num_ssa_regs_));
     return reg_location_[index];
   }
 
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 916bc7a..3058b0c 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -1154,6 +1154,17 @@
           break;
         }
         default:
+          if (lir->flags.fixup == kFixupLoad) {
+            LIR *target_lir = lir->target;
+            DCHECK(target_lir != NULL);
+            CodeOffset target = target_lir->offset;
+            lir->operands[2] = target;
+            int newSize = GetInsnSize(lir);
+            if (newSize != lir->flags.size) {
+              lir->flags.size = newSize;
+              res = kRetryAll;
+            }
+          }
           break;
       }
     }
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 4267b5b..93875c9 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -84,10 +84,19 @@
 
   // Get the switch value
   rl_src = LoadValue(rl_src, kCoreReg);
-  int start_of_method_reg = AllocTemp();
-  // Materialize a pointer to the switch table
   // NewLIR0(kX86Bkpt);
-  NewLIR1(kX86StartOfMethod, start_of_method_reg);
+
+  // Materialize a pointer to the switch table
+  int start_of_method_reg;
+  if (base_of_code_ != nullptr) {
+    // We can use the saved value.
+    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+    rl_method = LoadValue(rl_method, kCoreReg);
+    start_of_method_reg = rl_method.low_reg;
+  } else {
+    start_of_method_reg = AllocTemp();
+    NewLIR1(kX86StartOfMethod, start_of_method_reg);
+  }
   int low_key = s4FromSwitchData(&table[2]);
   int keyReg;
   // Remove the bias, if necessary
@@ -142,7 +151,13 @@
   FlushAllRegs();   /* Everything to home location */
   LoadValueDirectFixed(rl_src, rX86_ARG0);
   // Materialize a pointer to the fill data image
-  NewLIR1(kX86StartOfMethod, rX86_ARG2);
+  if (base_of_code_ != nullptr) {
+    // We can use the saved value.
+    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+    LoadValueDirect(rl_method, rX86_ARG2);
+  } else {
+    NewLIR1(kX86StartOfMethod, rX86_ARG2);
+  }
   NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec));
   NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2);
   CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayData), rX86_ARG0,
@@ -211,6 +226,13 @@
 
   FlushIns(ArgLocs, rl_method);
 
+  if (base_of_code_ != nullptr) {
+    // We have been asked to save the address of the method start for later use.
+    NewLIR1(kX86StartOfMethod, rX86_ARG0);
+    int displacement = SRegOffset(base_of_code_->s_reg_low);
+    StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
+  }
+
   FreeTemp(rX86_ARG0);
   FreeTemp(rX86_ARG1);
   FreeTemp(rX86_ARG2);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index a864117..6896504 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -407,6 +407,61 @@
      * @returns 'true' if the operation can proceed without needing temporary regs.
      */
     bool IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs);
+
+    /*
+     * @brief Perform MIR analysis before compiling method.
+     * @note Invokes Mir2LiR::Materialize after analysis.
+     */
+    void Materialize();
+
+    /*
+     * @brief Analyze MIR before generating code, to prepare for the code generation.
+     */
+    void AnalyzeMIR();
+
+    /*
+     * @brief Analyze one basic block.
+     * @param bb Basic block to analyze.
+     */
+    void AnalyzeBB(BasicBlock * bb);
+
+    /*
+     * @brief Analyze one extended MIR instruction
+     * @param opcode MIR instruction opcode.
+     * @param bb Basic block containing instruction.
+     * @param mir Extended instruction to analyze.
+     */
+    void AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir);
+
+    /*
+     * @brief Analyze one MIR instruction
+     * @param opcode MIR instruction opcode.
+     * @param bb Basic block containing instruction.
+     * @param mir Instruction to analyze.
+     */
+    void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
+
+    /*
+     * @brief Analyze one MIR float/double instruction
+     * @param opcode MIR instruction opcode.
+     * @param bb Basic block containing instruction.
+     * @param mir Instruction to analyze.
+     */
+    void AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir);
+
+    /*
+     * @brief Analyze one use of a double operand.
+     * @param rl_use Double RegLocation for the operand.
+     */
+    void AnalyzeDoubleUse(RegLocation rl_use);
+
+    // Information derived from analysis of MIR
+
+    // Have we decided to compute a ptr to code and store in temporary VR?
+    bool store_method_addr_;
+
+    // The compiler temporary for the code address of the method.
+    CompilerTemp *base_of_code_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index f223548..a347d8b 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -808,4 +808,12 @@
              << ", orig: " << loc.orig_sreg;
 }
 
+void X86Mir2Lir::Materialize() {
+  // A good place to put the analysis before starting.
+  AnalyzeMIR();
+
+  // Now continue with regular code generation.
+  Mir2Lir::Materialize();
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index a77e921..18c5ca8 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_x86.h"
 #include "dex/quick/mir_to_lir-inl.h"
+#include "dex/dataflow_iterator-inl.h"
 #include "x86_lir.h"
 
 namespace art {
@@ -61,7 +62,7 @@
 }
 
 bool X86Mir2Lir::InexpensiveConstantDouble(int64_t value) {
-  return false;  // TUNING
+  return value == 0;
 }
 
 /*
@@ -394,6 +395,27 @@
       DCHECK_EQ(r_dest_lo, r_dest_hi);
       if (value == 0) {
         return NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
+      } else if (base_of_code_ != nullptr) {
+        // We will load the value from the literal area.
+        LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
+        if (data_target == NULL) {
+          data_target = AddWideData(&literal_list_, val_lo, val_hi);
+        }
+
+        // Address the start of the method
+        RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+        rl_method = LoadValue(rl_method, kCoreReg);
+
+        // Load the proper value from the literal area.
+        // We don't know the proper offset for the value, so pick one that will force
+        // 4 byte offset.  We will fix this up in the assembler later to have the right
+        // value.
+        res = LoadBaseDisp(rl_method.low_reg, 256 /* bogus */, r_dest_lo, kDouble, INVALID_SREG);
+        res->target = data_target;
+        res->flags.fixup = kFixupLoad;
+        SetMemRefType(res, true, kLiteral);
+        // Redo after we assign target to ensure size is correct.
+        SetupResourceMasks(res);
       } else {
         if (val_lo == 0) {
           res = NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
@@ -662,4 +684,121 @@
     return branch;
 }
 
+void X86Mir2Lir::AnalyzeMIR() {
+  // Assume we don't need a pointer to the base of the code.
+  cu_->NewTimingSplit("X86 MIR Analysis");
+  store_method_addr_ = false;
+
+  // Walk the MIR looking for interesting items.
+  PreOrderDfsIterator iter(mir_graph_);
+  BasicBlock* curr_bb = iter.Next();
+  while (curr_bb != NULL) {
+    AnalyzeBB(curr_bb);
+    curr_bb = iter.Next();
+  }
+
+  // Did we need a pointer to the method code?
+  if (store_method_addr_) {
+    base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, false);
+  } else {
+    base_of_code_ = nullptr;
+  }
+}
+
+void X86Mir2Lir::AnalyzeBB(BasicBlock * bb) {
+  if (bb->block_type == kDead) {
+    // Ignore dead blocks
+    return;
+  }
+
+  for (MIR *mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+    int opcode = mir->dalvikInsn.opcode;
+    if (opcode >= kMirOpFirst) {
+      AnalyzeExtendedMIR(opcode, bb, mir);
+    } else {
+      AnalyzeMIR(opcode, bb, mir);
+    }
+  }
+}
+
+
+void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir) {
+  switch (opcode) {
+    // Instructions referencing doubles.
+    case kMirOpFusedCmplDouble:
+    case kMirOpFusedCmpgDouble:
+      AnalyzeFPInstruction(opcode, bb, mir);
+      break;
+    default:
+      // Ignore the rest.
+      break;
+  }
+}
+
+void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir) {
+  // Looking for
+  // - Do we need a pointer to the code (used for packed switches and double lits)?
+
+  switch (opcode) {
+    // Instructions referencing doubles.
+    case Instruction::CMPL_DOUBLE:
+    case Instruction::CMPG_DOUBLE:
+    case Instruction::NEG_DOUBLE:
+    case Instruction::ADD_DOUBLE:
+    case Instruction::SUB_DOUBLE:
+    case Instruction::MUL_DOUBLE:
+    case Instruction::DIV_DOUBLE:
+    case Instruction::REM_DOUBLE:
+    case Instruction::ADD_DOUBLE_2ADDR:
+    case Instruction::SUB_DOUBLE_2ADDR:
+    case Instruction::MUL_DOUBLE_2ADDR:
+    case Instruction::DIV_DOUBLE_2ADDR:
+    case Instruction::REM_DOUBLE_2ADDR:
+      AnalyzeFPInstruction(opcode, bb, mir);
+      break;
+    // Packed switches and array fills need a pointer to the base of the method.
+    case Instruction::FILL_ARRAY_DATA:
+    case Instruction::PACKED_SWITCH:
+      store_method_addr_ = true;
+      break;
+    default:
+      // Other instructions are not interesting yet.
+      break;
+  }
+}
+
+void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) {
+  // Look at all the uses, and see if they are double constants.
+  uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+  int next_sreg = 0;
+  if (attrs & DF_UA) {
+    if (attrs & DF_A_WIDE) {
+      AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+      next_sreg += 2;
+    } else {
+      next_sreg++;
+    }
+  }
+  if (attrs & DF_UB) {
+    if (attrs & DF_B_WIDE) {
+      AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+      next_sreg += 2;
+    } else {
+      next_sreg++;
+    }
+  }
+  if (attrs & DF_UC) {
+    if (attrs & DF_C_WIDE) {
+      AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+    }
+  }
+}
+
+void X86Mir2Lir::AnalyzeDoubleUse(RegLocation use) {
+  // If this is a double literal, we will want it in the literal pool.
+  if (use.is_const) {
+    store_method_addr_ = true;
+  }
+}
+
 }  // namespace art