[optimizing] Add support for x86 constant area

Use the Quick trick of finding the address of the method by calling the
next instruction and popping the return address into a register.  This
trick is used because of the lack of PC-relative addressing in 32 bit
mode on the X86.

Add a HX86ComputeBaseMethodAddress instruction to trigger generation
of the method address, which is referenced by instructions needing
access to the constant area.

Add a HX86LoadFromConstantTable instruction that takes a
HX86ComputeBaseMethodAddress and a HConstant that will be used to load
the value when needed.

Change Add/Sub/Mul/Div to detect a HX86LoadFromConstantTable right hand
side, and generate code that directly references the constant area.
Other uses will be added later.

Change the inputs to HReturn and HInvoke(s), replacing the FP constants
with HX86LoadFromConstantTable instead.  This allows values to be
loaded from the constant area into the right location.

Port the X86_64 assembler constant area handling to the X86.

Use the new per-backend optimization framework to do this conversion.

Change-Id: I6d235a72238262e4f9ec0f3c88319a187f865932
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 0c90f28..7d7b3d3 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -86,7 +86,7 @@
 
  protected:
   // Operand can be sub classed (e.g: Address).
-  Operand() : length_(0) { }
+  Operand() : length_(0), fixup_(nullptr) { }
 
   void SetModRM(int mod_in, Register rm_in) {
     CHECK_EQ(mod_in & ~3, 0);
@@ -113,11 +113,23 @@
     length_ += disp_size;
   }
 
+  AssemblerFixup* GetFixup() const {
+    return fixup_;
+  }
+
+  void SetFixup(AssemblerFixup* fixup) {
+    fixup_ = fixup;
+  }
+
  private:
   uint8_t length_;
   uint8_t encoding_[6];
 
-  explicit Operand(Register reg) { SetModRM(3, reg); }
+  // A fixup can be associated with the operand, in order to be applied after the
+  // code has been generated. This is used for constant area fixups.
+  AssemblerFixup* fixup_;
+
+  explicit Operand(Register reg) : fixup_(nullptr) { SetModRM(3, reg); }
 
   // Get the operand encoding byte at the given index.
   uint8_t encoding_at(int index_in) const {
@@ -136,6 +148,11 @@
     Init(base_in, disp);
   }
 
+  Address(Register base_in, int32_t disp, AssemblerFixup *fixup) {
+    Init(base_in, disp);
+    SetFixup(fixup);
+  }
+
   Address(Register base_in, Offset disp) {
     Init(base_in, disp.Int32Value());
   }
@@ -226,6 +243,50 @@
   DISALLOW_COPY_AND_ASSIGN(NearLabel);
 };
 
+/**
+ * Class to handle constant area values.
+ */
+class ConstantArea {
+ public:
+  ConstantArea() {}
+
+  // Add a double to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddDouble(double v);
+
+  // Add a float to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddFloat(float v);
+
+  // Add an int32_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt32(int32_t v);
+
+  // Add an int64_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt64(int64_t v);
+
+  bool IsEmpty() const {
+    return buffer_.size() == 0;
+  }
+
+  const std::vector<int32_t>& GetBuffer() const {
+    return buffer_;
+  }
+
+  void AddFixup(AssemblerFixup* fixup) {
+    fixups_.push_back(fixup);
+  }
+
+  const std::vector<AssemblerFixup*>& GetFixups() const {
+    return fixups_;
+  }
+
+ private:
+  static constexpr size_t kEntrySize = sizeof(int32_t);
+  std::vector<int32_t> buffer_;
+  std::vector<AssemblerFixup*> fixups_;
+};
 
 class X86Assembler FINAL : public Assembler {
  public:
@@ -667,6 +728,29 @@
     }
   }
 
+  // Add a double to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddDouble(double v) { return constant_area_.AddDouble(v); }
+
+  // Add a float to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddFloat(float v)   { return constant_area_.AddFloat(v); }
+
+  // Add an int32_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt32(int32_t v) { return constant_area_.AddInt32(v); }
+
+  // Add an int64_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
+
+  // Add the contents of the constant area to the assembler buffer.
+  void AddConstantArea();
+
+  // Is the constant area empty? Return true if there are no literals in the constant area.
+  bool IsConstantAreaEmpty() const { return constant_area_.IsEmpty(); }
+  void AddConstantAreaFixup(AssemblerFixup* fixup) { constant_area_.AddFixup(fixup); }
+
  private:
   inline void EmitUint8(uint8_t value);
   inline void EmitInt32(int32_t value);
@@ -685,6 +769,8 @@
   void EmitGenericShift(int rm, const Operand& operand, const Immediate& imm);
   void EmitGenericShift(int rm, const Operand& operand, Register shifter);
 
+  ConstantArea constant_area_;
+
   DISALLOW_COPY_AND_ASSIGN(X86Assembler);
 };