Add initial integrated assembler w/ some Xmm ops.

Add a flag to use the integrated assembler.

Handle simple XMM binary op instructions as an initial example of how
instructions might be handled. This tests fixups in a very limited sense --
Track buffer locations of fixups for floating point immediates.

Patchset one shows the original dart assembler code (revision 39313), so that
it can be diffed.

BUG=none
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/574133002
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index 93c193f..8c6b99a 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "assembler_ia32.h"
 #include "IceCfg.h"
 #include "IceCfgNode.h"
 #include "IceConditionCodesX8632.h"
@@ -331,6 +332,47 @@
 
 // ======================== Dump routines ======================== //
 
+namespace {
+
+void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm,
+                  intptr_t StartPosition) {
+  intptr_t EndPosition = Asm->GetPosition();
+  intptr_t LastFixupLoc = -1;
+  AssemblerFixup *LastFixup = NULL;
+  if (Asm->GetLatestFixup()) {
+    LastFixup = Asm->GetLatestFixup();
+    LastFixupLoc = LastFixup->position();
+  }
+  if (LastFixupLoc < StartPosition) {
+    // The fixup doesn't apply to this current block.
+    for (intptr_t i = 0; i < EndPosition - StartPosition; ++i) {
+      Str << "\t.byte "
+          << static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(StartPosition + i))
+          << "\n";
+    }
+    return;
+  }
+  const intptr_t FixupSize = 4;
+  assert(LastFixupLoc + FixupSize <= EndPosition);
+  // The fixup does apply to this current block.
+  for (intptr_t i = 0; i < LastFixupLoc - StartPosition; ++i) {
+    Str << "\t.byte "
+        << static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(StartPosition + i))
+        << "\n";
+  }
+  Str << "\t.long " << LastFixup->value()->getName();
+  if (LastFixup->value()->getOffset()) {
+    Str << " + " << LastFixup->value()->getOffset();
+  }
+  Str << "\n";
+  for (intptr_t i = LastFixupLoc + FixupSize; i < EndPosition; ++i) {
+    Str << "\t.byte " << static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(i))
+        << "\n";
+  }
+}
+
+} // end of anonymous namespace
+
 void InstX8632::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Str << "[X8632] ";
@@ -436,6 +478,38 @@
   Str << "\n";
 }
 
+void
+emitIASVarOperandTyXMM(const Cfg *Func, Type Ty, const Variable *Var,
+                       const Operand *Src,
+                       const x86::AssemblerX86::TypedXmmEmitters &Emitter) {
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  assert(Var->hasReg());
+  RegX8632::XmmRegister VarReg = RegX8632::getEncodedXmm(Var->getRegNum());
+  if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src)) {
+    if (SrcVar->hasReg()) {
+      RegX8632::XmmRegister SrcReg =
+          RegX8632::getEncodedXmm(SrcVar->getRegNum());
+      (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
+    } else {
+      x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget())
+                                      ->stackVarToAsmOperand(SrcVar);
+      (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
+    }
+  } else if (const OperandX8632Mem *Mem =
+                 llvm::dyn_cast<OperandX8632Mem>(Src)) {
+    x86::Address SrcAddr = Mem->toAsmAddress(Asm);
+    (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcAddr);
+  } else if (const Constant *Imm = llvm::dyn_cast<Constant>(Src)) {
+    (Asm->*(Emitter.XmmAddr))(
+        Ty, VarReg, x86::Address::ofConstPool(Func->getContext(), Asm, Imm));
+  } else {
+    llvm_unreachable("Unexpected operand type");
+  }
+  Ostream &Str = Func->getContext()->getStrEmit();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) {
   const Variable *Src = llvm::dyn_cast<const Variable>(Source);
   if (Src == NULL)
@@ -512,6 +586,56 @@
 template <> const char *InstX8632Pextr::Opcode = "pextr";
 template <> const char *InstX8632Pshufd::Opcode = "pshufd";
 
+// Binary XMM ops
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Addss::Emitter = {
+    &x86::AssemblerX86::addss, &x86::AssemblerX86::addss, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Addps::Emitter = {
+    &x86::AssemblerX86::addps, &x86::AssemblerX86::addps, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Divss::Emitter = {
+    &x86::AssemblerX86::divss, &x86::AssemblerX86::divss, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Divps::Emitter = {
+    &x86::AssemblerX86::divps, &x86::AssemblerX86::divps, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Mulss::Emitter = {
+    &x86::AssemblerX86::mulss, &x86::AssemblerX86::mulss, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Mulps::Emitter = {
+    &x86::AssemblerX86::mulps, &x86::AssemblerX86::mulps, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Padd::Emitter = {
+    &x86::AssemblerX86::padd, &x86::AssemblerX86::padd, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Pand::Emitter = {
+    &x86::AssemblerX86::pand, &x86::AssemblerX86::pand, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Pandn::Emitter = {
+    &x86::AssemblerX86::pandn, &x86::AssemblerX86::pandn, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Pmuludq::Emitter = {
+    &x86::AssemblerX86::pmuludq, &x86::AssemblerX86::pmuludq, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Por::Emitter = {
+    &x86::AssemblerX86::por, &x86::AssemblerX86::por, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Psub::Emitter = {
+    &x86::AssemblerX86::psub, &x86::AssemblerX86::psub, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Pxor::Emitter = {
+    &x86::AssemblerX86::pxor, &x86::AssemblerX86::pxor, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Sqrtss::Emitter = {
+    &x86::AssemblerX86::sqrtss, &x86::AssemblerX86::sqrtss, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Subss::Emitter = {
+    &x86::AssemblerX86::subss, &x86::AssemblerX86::subss, NULL};
+template <>
+const x86::AssemblerX86::TypedXmmEmitters InstX8632Subps::Emitter = {
+    &x86::AssemblerX86::subps, &x86::AssemblerX86::subps, NULL};
+
 template <> void InstX8632Sqrtss::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 1);
@@ -790,6 +914,28 @@
   Str << "\n";
 }
 
+void InstX8632Cmpps::emitIAS(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  assert(getSrcSize() == 2);
+  assert(Condition < CondX86::Cmpps_Invalid);
+  // Assuming there isn't any load folding for cmpps, and vector constants
+  // are not allowed in PNaCl.
+  assert(llvm::isa<Variable>(getSrc(1)));
+  const Variable *SrcVar = llvm::cast<Variable>(getSrc(1));
+  if (SrcVar->hasReg()) {
+    Asm->cmpps(RegX8632::getEncodedXmm(getDest()->getRegNum()),
+               RegX8632::getEncodedXmm(SrcVar->getRegNum()), Condition);
+  } else {
+    x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget())
+                                    ->stackVarToAsmOperand(SrcVar);
+    Asm->cmpps(RegX8632::getEncodedXmm(getDest()->getRegNum()), SrcStackAddr,
+               Condition);
+  }
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Cmpps::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   assert(Condition < CondX86::Cmpps_Invalid);
@@ -893,6 +1039,18 @@
   Str << "\n";
 }
 
+void InstX8632Ucomiss::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 2);
+  // Currently src0 is always a variable by convention, to avoid having
+  // two memory operands.
+  assert(llvm::isa<Variable>(getSrc(0)));
+  const Variable *Src0 = llvm::cast<Variable>(getSrc(0));
+  Type Ty = Src0->getType();
+  const static x86::AssemblerX86::TypedXmmEmitters Emitter = {
+      &x86::AssemblerX86::ucomiss, &x86::AssemblerX86::ucomiss, NULL};
+  emitIASVarOperandTyXMM(Func, Ty, Src0, getSrc(1), Emitter);
+}
+
 void InstX8632Ucomiss::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Str << "ucomiss." << getSrc(0)->getType() << " ";
@@ -1133,6 +1291,15 @@
   Str << "\tnop\t# variant = " << Variant << "\n";
 }
 
+void InstX8632Nop::emitIAS(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  // TODO: Emit the right code for the variant.
+  Asm->nop();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Nop::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Str << "nop (variant = " << Variant << ")";
@@ -1272,6 +1439,20 @@
   Str << "\n";
 }
 
+void InstX8632Pop::emitIAS(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 0);
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  if (getDest()->hasReg()) {
+    Asm->popl(RegX8632::getEncodedGPR(getDest()->getRegNum()));
+  } else {
+    Asm->popl(static_cast<TargetX8632 *>(Func->getTarget())
+                  ->stackVarToAsmOperand(getDest()));
+  }
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Pop::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   dumpDest(Func);
@@ -1284,6 +1465,15 @@
   Func->getTarget()->updateStackAdjustment(Amount);
 }
 
+void InstX8632AdjustStack::emitIAS(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  Asm->subl(RegX8632::Encoded_Reg_esp, x86::Immediate(Amount));
+  emitIASBytes(Str, Asm, StartPosition);
+  Func->getTarget()->updateStackAdjustment(Amount);
+}
+
 void InstX8632AdjustStack::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Str << "esp = sub.i32 esp, " << Amount;
@@ -1356,6 +1546,14 @@
   Str << "\tret\n";
 }
 
+void InstX8632Ret::emitIAS(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  Asm->ret();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Ret::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Type Ty = (getSrcSize() == 0 ? IceType_void : getSrc(0)->getType());
@@ -1498,6 +1696,41 @@
   Str << "]";
 }
 
+x86::Address OperandX8632Mem::toAsmAddress(Assembler *Asm) const {
+  int32_t Disp = 0;
+  AssemblerFixup *Fixup = NULL;
+  // Determine the offset (is it relocatable?)
+  if (getOffset()) {
+    if (ConstantInteger32 *CI =
+            llvm::dyn_cast<ConstantInteger32>(getOffset())) {
+      Disp = static_cast<int32_t>(CI->getValue());
+    } else if (ConstantRelocatable *CR =
+                   llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
+      // TODO(jvoung): CR + non-zero-offset isn't really tested yet,
+      // since the addressing mode optimization doesn't try to combine
+      // ConstantRelocatable with something else.
+      assert(CR->getOffset() == 0);
+      Fixup = x86::DisplacementRelocation::create(Asm, FK_Abs_4, CR);
+    } else {
+      llvm_unreachable("Unexpected offset type");
+    }
+  }
+
+  // Now convert to the various possible forms.
+  if (getBase() && getIndex()) {
+    return x86::Address(RegX8632::getEncodedGPR(getBase()->getRegNum()),
+                        RegX8632::getEncodedGPR(getIndex()->getRegNum()),
+                        x86::ScaleFactor(getShift()), Disp);
+  } else if (getBase()) {
+    return x86::Address(RegX8632::getEncodedGPR(getBase()->getRegNum()), Disp);
+  } else if (getIndex()) {
+    return x86::Address(RegX8632::getEncodedGPR(getIndex()->getRegNum()),
+                        x86::ScaleFactor(getShift()), Disp);
+  } else {
+    return x86::Address::Absolute(Disp, Fixup);
+  }
+}
+
 void VariableSplit::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(!Var->hasReg());