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/IceCfg.cpp b/src/IceCfg.cpp index e1255df..d2548a6 100644 --- a/src/IceCfg.cpp +++ b/src/IceCfg.cpp
@@ -28,7 +28,10 @@ IsInternalLinkage(false), HasError(false), ErrorMessage(""), Entry(NULL), NextInstNumber(1), Live(NULL), Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)), - VMetadata(new VariablesMetadata(this)), CurrentNode(NULL) {} + VMetadata(new VariablesMetadata(this)), + TargetAssembler( + TargetLowering::createAssembler(Ctx->getTargetArch(), this)), + CurrentNode(NULL) {} Cfg::~Cfg() {}
diff --git a/src/IceCfg.h b/src/IceCfg.h index 73dd814..1de7795 100644 --- a/src/IceCfg.h +++ b/src/IceCfg.h
@@ -17,6 +17,9 @@ #include "IceDefs.h" #include "IceTypes.h" + +#include "assembler.h" +#include "IceClFlags.h" #include "IceGlobalContext.h" #include "llvm/ADT/OwningPtr.h" @@ -86,6 +89,12 @@ TargetLowering *getTarget() const { return Target.get(); } VariablesMetadata *getVMetadata() const { return VMetadata.get(); } Liveness *getLiveness() const { return Live.get(); } + template <typename T> T *getAssembler() const { + return static_cast<T *>(TargetAssembler.get()); + } + bool UseIntegratedAssembler() const { + return getContext()->getFlags().UseIntegratedAssembler; + } bool hasComputedFrame() const; // Passes over the CFG. @@ -166,6 +175,7 @@ llvm::OwningPtr<Liveness> Live; llvm::OwningPtr<TargetLowering> Target; llvm::OwningPtr<VariablesMetadata> VMetadata; + llvm::OwningPtr<Assembler> TargetAssembler; // CurrentNode is maintained during dumping/emitting just for // validating Variable::DefNode. Normally, a traversal over
diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp index 3277564..eff4e97 100644 --- a/src/IceCfgNode.cpp +++ b/src/IceCfgNode.cpp
@@ -492,7 +492,11 @@ // suppress them. if (Inst->isRedundantAssign()) continue; - (*I)->emit(Func); + if (Func->UseIntegratedAssembler()) { + (*I)->emitIAS(Func); + } else { + (*I)->emit(Func); + } // Update emitted instruction count, plus fill/spill count for // Variable operands without a physical register. if (uint32_t Count = (*I)->getEmitInstCount()) {
diff --git a/src/IceClFlags.h b/src/IceClFlags.h index 2d14a93..d6c232f 100644 --- a/src/IceClFlags.h +++ b/src/IceClFlags.h
@@ -24,13 +24,15 @@ ClFlags() : DisableInternal(false), SubzeroTimingEnabled(false), DisableTranslation(false), DisableGlobals(false), - FunctionSections(false), UseSandboxing(false), DumpStats(false), - DefaultGlobalPrefix(""), DefaultFunctionPrefix("") {} + FunctionSections(false), UseIntegratedAssembler(false), + UseSandboxing(false), DumpStats(false), DefaultGlobalPrefix(""), + DefaultFunctionPrefix("") {} bool DisableInternal; bool SubzeroTimingEnabled; bool DisableTranslation; bool DisableGlobals; bool FunctionSections; + bool UseIntegratedAssembler; bool UseSandboxing; bool DumpStats; IceString DefaultGlobalPrefix;
diff --git a/src/IceDefs.h b/src/IceDefs.h index 0f200bc..322e9b4 100644 --- a/src/IceDefs.h +++ b/src/IceDefs.h
@@ -130,11 +130,6 @@ Timer &operator=(const Timer &) LLVM_DELETED_FUNCTION; }; -template <typename T> bool WouldOverflowAdd(T X, T Y) { - return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) || - (X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - Y))); -} - } // end of namespace Ice #endif // SUBZERO_SRC_ICEDEFS_H
diff --git a/src/IceFixups.h b/src/IceFixups.h new file mode 100644 index 0000000..7144aa8 --- /dev/null +++ b/src/IceFixups.h
@@ -0,0 +1,32 @@ +//===- subzero/src/IceFixups.h - Assembler fixup kinds ----------*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares generic fixup types. +// +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ICEFIXUPS_H +#define SUBZERO_SRC_ICEFIXUPS_H + +#include "IceTypes.def" + +namespace Ice { + +enum FixupKind { + // Specify some of the most common relocation types. + FK_Abs_4 = 0, + FK_PcRel_4 = 1, + + // Target specific relocation types follow this. + FK_FirstTargetSpecific = 1 << 4 +}; + +} // end of namespace Ice + +#endif // SUBZERO_SRC_ICEFIXUPS_H
diff --git a/src/IceInst.cpp b/src/IceInst.cpp index 629c6bd..a88194e 100644 --- a/src/IceInst.cpp +++ b/src/IceInst.cpp
@@ -458,6 +458,8 @@ llvm_unreachable("emit() called on a non-lowered instruction"); } +void Inst::emitIAS(const Cfg *Func) const { emit(Func); } + void Inst::dump(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func);
diff --git a/src/IceInst.h b/src/IceInst.h index 6db4971..5c07dc0 100644 --- a/src/IceInst.h +++ b/src/IceInst.h
@@ -102,6 +102,7 @@ // instruction results in a single native instruction. virtual uint32_t getEmitInstCount() const { return 0; } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; virtual void dumpExtras(const Cfg *Func) const; void dumpDecorated(const Cfg *Func) const;
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());
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h index 7ab8592..514c374 100644 --- a/src/IceInstX8632.h +++ b/src/IceInstX8632.h
@@ -16,6 +16,7 @@ #ifndef SUBZERO_SRC_ICEINSTX8632_H #define SUBZERO_SRC_ICEINSTX8632_H +#include "assembler_ia32.h" #include "IceDefs.h" #include "IceInst.h" #include "IceConditionCodesX8632.h" @@ -75,6 +76,7 @@ Variable *getIndex() const { return Index; } uint16_t getShift() const { return Shift; } SegmentRegisters getSegmentRegister() const { return SegmentReg; } + x86::Address toAsmAddress(Assembler *Asm) const; virtual void emit(const Cfg *Func) const; using OperandX8632::dump; virtual void dump(const Cfg *Func, Ostream &Str) const; @@ -396,6 +398,7 @@ InstX8632AdjustStack(Func, Amount, Esp); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } @@ -478,6 +481,7 @@ getSrc(0)->emit(Func); Str << "\n"; } + virtual void emitIAS(const Cfg *Func) const { emit(Func); } virtual void dump(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); @@ -497,6 +501,52 @@ static const char *Opcode; }; +void emitIASVarOperandTyXMM(const Cfg *Func, Type Ty, const Variable *Var, + const Operand *Src, + const x86::AssemblerX86::TypedXmmEmitters &Emitter); + +template <InstX8632::InstKindX8632 K> +class InstX8632UnaryopXmm : public InstX8632 { +public: + static InstX8632UnaryopXmm *create(Cfg *Func, Variable *Dest, Operand *Src) { + return new (Func->allocate<InstX8632UnaryopXmm>()) + InstX8632UnaryopXmm(Func, Dest, Src); + } + virtual void emit(const Cfg *Func) const { + Ostream &Str = Func->getContext()->getStrEmit(); + assert(getSrcSize() == 1); + Str << "\t" << Opcode << "\t"; + getDest()->emit(Func); + Str << ", "; + getSrc(0)->emit(Func); + Str << "\n"; + } + virtual void emitIAS(const Cfg *Func) const { + Type Ty = getDest()->getType(); + assert(getSrcSize() == 1); + emitIASVarOperandTyXMM(Func, Ty, getDest(), getSrc(0), Emitter); + } + virtual void dump(const Cfg *Func) const { + Ostream &Str = Func->getContext()->getStrDump(); + dumpDest(Func); + Str << " = " << Opcode << "." << getDest()->getType() << " "; + dumpSources(Func); + } + static bool classof(const Inst *Inst) { return isClassof(Inst, K); } + +private: + InstX8632UnaryopXmm(Cfg *Func, Variable *Dest, Operand *Src) + : InstX8632(Func, K, 1, Dest) { + addSource(Src); + } + InstX8632UnaryopXmm(const InstX8632UnaryopXmm &) LLVM_DELETED_FUNCTION; + InstX8632UnaryopXmm & + operator=(const InstX8632UnaryopXmm &) LLVM_DELETED_FUNCTION; + virtual ~InstX8632UnaryopXmm() {} + static const char *Opcode; + static const x86::AssemblerX86::TypedXmmEmitters Emitter; +}; + // See the definition of emitTwoAddress() for a description of // ShiftHack. void emitTwoAddress(const char *Opcode, const Inst *Inst, const Cfg *Func, @@ -533,6 +583,46 @@ static const char *Opcode; }; +template <InstX8632::InstKindX8632 K, bool NeedsElementType> +class InstX8632BinopXmm : public InstX8632 { +public: + // Create an XMM binary-op instruction like addss or addps. + static InstX8632BinopXmm *create(Cfg *Func, Variable *Dest, Operand *Source) { + return new (Func->allocate<InstX8632BinopXmm>()) + InstX8632BinopXmm(Func, Dest, Source); + } + virtual void emit(const Cfg *Func) const { + const bool ShiftHack = false; + emitTwoAddress(Opcode, this, Func, ShiftHack); + } + virtual void emitIAS(const Cfg *Func) const { + Type Ty = getDest()->getType(); + if (NeedsElementType) + Ty = typeElementType(Ty); + assert(getSrcSize() == 2); + emitIASVarOperandTyXMM(Func, Ty, getDest(), getSrc(1), Emitter); + } + virtual void dump(const Cfg *Func) const { + Ostream &Str = Func->getContext()->getStrDump(); + dumpDest(Func); + Str << " = " << Opcode << "." << getDest()->getType() << " "; + dumpSources(Func); + } + static bool classof(const Inst *Inst) { return isClassof(Inst, K); } + +private: + InstX8632BinopXmm(Cfg *Func, Variable *Dest, Operand *Source) + : InstX8632(Func, K, 2, Dest) { + addSource(Dest); + addSource(Source); + } + InstX8632BinopXmm(const InstX8632BinopXmm &) LLVM_DELETED_FUNCTION; + InstX8632BinopXmm &operator=(const InstX8632BinopXmm &) LLVM_DELETED_FUNCTION; + virtual ~InstX8632BinopXmm() {} + static const char *Opcode; + static const x86::AssemblerX86::TypedXmmEmitters Emitter; +}; + template <InstX8632::InstKindX8632 K> class InstX8632Ternop : public InstX8632 { public: // Create a ternary-op instruction like div or idiv. @@ -657,7 +747,7 @@ typedef InstX8632Unaryop<InstX8632::Bsr> InstX8632Bsr; typedef InstX8632Unaryop<InstX8632::Lea> InstX8632Lea; typedef InstX8632Unaryop<InstX8632::Movd> InstX8632Movd; -typedef InstX8632Unaryop<InstX8632::Sqrtss> InstX8632Sqrtss; +typedef InstX8632UnaryopXmm<InstX8632::Sqrtss> InstX8632Sqrtss; // Cbwdq instruction - wrapper for cbw, cwd, and cdq typedef InstX8632Unaryop<InstX8632::Cbwdq> InstX8632Cbwdq; // Move/assignment instruction - wrapper for mov/movss/movsd. @@ -668,29 +758,29 @@ // Movq - copy between XMM registers, or mem64 and XMM registers. typedef InstX8632Movlike<InstX8632::Movq> InstX8632Movq; typedef InstX8632Binop<InstX8632::Add> InstX8632Add; -typedef InstX8632Binop<InstX8632::Addps> InstX8632Addps; +typedef InstX8632BinopXmm<InstX8632::Addps, true> InstX8632Addps; typedef InstX8632Binop<InstX8632::Adc> InstX8632Adc; -typedef InstX8632Binop<InstX8632::Addss> InstX8632Addss; -typedef InstX8632Binop<InstX8632::Padd> InstX8632Padd; +typedef InstX8632BinopXmm<InstX8632::Addss, false> InstX8632Addss; +typedef InstX8632BinopXmm<InstX8632::Padd, true> InstX8632Padd; typedef InstX8632Binop<InstX8632::Sub> InstX8632Sub; -typedef InstX8632Binop<InstX8632::Subps> InstX8632Subps; -typedef InstX8632Binop<InstX8632::Subss> InstX8632Subss; +typedef InstX8632BinopXmm<InstX8632::Subps, true> InstX8632Subps; +typedef InstX8632BinopXmm<InstX8632::Subss, false> InstX8632Subss; typedef InstX8632Binop<InstX8632::Sbb> InstX8632Sbb; -typedef InstX8632Binop<InstX8632::Psub> InstX8632Psub; +typedef InstX8632BinopXmm<InstX8632::Psub, true> InstX8632Psub; typedef InstX8632Binop<InstX8632::And> InstX8632And; -typedef InstX8632Binop<InstX8632::Pand> InstX8632Pand; -typedef InstX8632Binop<InstX8632::Pandn> InstX8632Pandn; +typedef InstX8632BinopXmm<InstX8632::Pand, false> InstX8632Pand; +typedef InstX8632BinopXmm<InstX8632::Pandn, false> InstX8632Pandn; typedef InstX8632Binop<InstX8632::Or> InstX8632Or; -typedef InstX8632Binop<InstX8632::Por> InstX8632Por; +typedef InstX8632BinopXmm<InstX8632::Por, false> InstX8632Por; typedef InstX8632Binop<InstX8632::Xor> InstX8632Xor; -typedef InstX8632Binop<InstX8632::Pxor> InstX8632Pxor; +typedef InstX8632BinopXmm<InstX8632::Pxor, false> InstX8632Pxor; typedef InstX8632Binop<InstX8632::Imul> InstX8632Imul; -typedef InstX8632Binop<InstX8632::Mulps> InstX8632Mulps; -typedef InstX8632Binop<InstX8632::Mulss> InstX8632Mulss; +typedef InstX8632BinopXmm<InstX8632::Mulps, true> InstX8632Mulps; +typedef InstX8632BinopXmm<InstX8632::Mulss, false> InstX8632Mulss; typedef InstX8632Binop<InstX8632::Pmull> InstX8632Pmull; -typedef InstX8632Binop<InstX8632::Pmuludq> InstX8632Pmuludq; -typedef InstX8632Binop<InstX8632::Divps> InstX8632Divps; -typedef InstX8632Binop<InstX8632::Divss> InstX8632Divss; +typedef InstX8632BinopXmm<InstX8632::Pmuludq, false> InstX8632Pmuludq; +typedef InstX8632BinopXmm<InstX8632::Divps, true> InstX8632Divps; +typedef InstX8632BinopXmm<InstX8632::Divss, false> InstX8632Divss; typedef InstX8632Binop<InstX8632::Rol, true> InstX8632Rol; typedef InstX8632Binop<InstX8632::Shl, true> InstX8632Shl; typedef InstX8632Binop<InstX8632::Psll> InstX8632Psll; @@ -828,6 +918,7 @@ InstX8632Cmpps(Func, Dest, Source, Condition); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Cmpps); } @@ -941,6 +1032,7 @@ InstX8632Ucomiss(Func, Src1, Src2); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Ucomiss); } @@ -1108,6 +1200,7 @@ return new (Func->allocate<InstX8632Nop>()) InstX8632Nop(Func, Variant); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Nop); } @@ -1160,6 +1253,7 @@ return new (Func->allocate<InstX8632Pop>()) InstX8632Pop(Func, Dest); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } @@ -1199,6 +1293,7 @@ return new (Func->allocate<InstX8632Ret>()) InstX8632Ret(Func, Source); } virtual void emit(const Cfg *Func) const; + virtual void emitIAS(const Cfg *Func) const; virtual void dump(const Cfg *Func) const; static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); }
diff --git a/src/IceMemoryRegion.cpp b/src/IceMemoryRegion.cpp new file mode 100644 index 0000000..9c42940 --- /dev/null +++ b/src/IceMemoryRegion.cpp
@@ -0,0 +1,32 @@ +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/IceMemoryRegion.cpp - Memory region --------------------===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MemoryRegion class. It tracks a pointer plus its +// bounds for bounds-checking in debug mode. +//===----------------------------------------------------------------------===// + +#include "IceMemoryRegion.h" + +namespace Ice { + +void MemoryRegion::CopyFrom(uintptr_t offset, const MemoryRegion &from) const { + assert(from.pointer() != NULL && from.size() > 0); + assert(this->size() >= from.size()); + assert(offset <= this->size() - from.size()); + memmove(reinterpret_cast<void *>(start() + offset), from.pointer(), + from.size()); +} + +} // end of namespace Ice
diff --git a/src/IceMemoryRegion.h b/src/IceMemoryRegion.h new file mode 100644 index 0000000..2a55a41 --- /dev/null +++ b/src/IceMemoryRegion.h
@@ -0,0 +1,93 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/IceMemoryRegion.h - Memory region ------------*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MemoryRegion class. It tracks a pointer +// plus its bounds for bounds-checking in debug mode. +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ICE_MEMORY_REGION_H_ +#define SUBZERO_SRC_ICE_MEMORY_REGION_H_ + +#include "IceDefs.h" +#include "IceUtils.h" + +namespace Ice { + +// Memory regions are useful for accessing memory with bounds check in +// debug mode. They can be safely passed by value and do not assume ownership +// of the region. +class MemoryRegion { +public: + MemoryRegion() : pointer_(NULL), size_(0) {} + MemoryRegion(void *pointer, size_t size) : pointer_(pointer), size_(size) {} + MemoryRegion(const MemoryRegion &other) { *this = other; } + MemoryRegion &operator=(const MemoryRegion &other) { + pointer_ = other.pointer_; + size_ = other.size_; + return *this; + } + + void *pointer() const { return pointer_; } + size_t size() const { return size_; } + + size_t start() const { return reinterpret_cast<size_t>(pointer_); } + size_t end() const { return start() + size_; } + + template <typename T> T Load(size_t offset) const { + return *ComputeInternalPointer<T>(offset); + } + + template <typename T> void Store(size_t offset, T value) const { + *ComputeInternalPointer<T>(offset) = value; + } + + template <typename T> T *PointerTo(size_t offset) const { + return ComputeInternalPointer<T>(offset); + } + + bool Contains(size_t address) const { + return (address >= start()) && (address < end()); + } + + void CopyFrom(size_t offset, const MemoryRegion &from) const; + + // Compute a sub memory region based on an existing one. + void Subregion(const MemoryRegion &from, size_t offset, size_t size) { + assert(from.size() >= size); + assert(offset <= (from.size() - size)); + pointer_ = reinterpret_cast<void *>(from.start() + offset); + size_ = size; + } + + // Compute an extended memory region based on an existing one. + void Extend(const MemoryRegion ®ion, size_t extra) { + pointer_ = region.pointer(); + size_ = (region.size() + extra); + } + +private: + template <typename T> T *ComputeInternalPointer(size_t offset) const { + assert(size() >= sizeof(T)); + assert(offset <= size() - sizeof(T)); + return reinterpret_cast<T *>(start() + offset); + } + + void *pointer_; + size_t size_; +}; + +} // end of namespace Ice + +#endif // SUBZERO_SRC_ICE_MEMORY_REGION_H_
diff --git a/src/IceRegistersX8632.h b/src/IceRegistersX8632.h index effbf36..3aa8178 100644 --- a/src/IceRegistersX8632.h +++ b/src/IceRegistersX8632.h
@@ -19,68 +19,72 @@ namespace Ice { -class RegX8632 { -public: - // An enum of every register. The enum value may not match the encoding - // used to binary encode register operands in instructions. - enum AllRegisters { +namespace RegX8632 { + +// An enum of every register. The enum value may not match the encoding +// used to binary encode register operands in instructions. +enum AllRegisters { #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ frameptr, isI8, isInt, isFP) \ val, - REGX8632_TABLE + REGX8632_TABLE #undef X - Reg_NUM, + Reg_NUM, #define X(val, init) val init, - REGX8632_TABLE_BOUNDS + REGX8632_TABLE_BOUNDS #undef X - }; - - // An enum of GPR Registers. The enum value does match encoding used - // to binary encode register operands in instructions. - enum GPRRegister { -#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ - frameptr, isI8, isInt, isFP) \ - Encoded_##val encode, - REGX8632_GPR_TABLE -#undef X - }; - - // An enum of XMM Registers. The enum value does match encoding used - // to binary encode register operands in instructions. - enum XmmRegister { -#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ - frameptr, isI8, isInt, isFP) \ - Encoded_##val encode, - REGX8632_XMM_TABLE -#undef X - }; - - // An enum of Byte Registers. The enum value does match encoding used - // to binary encode register operands in instructions. - enum ByteRegister { -#define X(val, encode) Encoded_##val encode, - REGX8632_BYTEREG_TABLE -#undef X - }; - - static GPRRegister getEncodedGPR(int32_t RegNum) { - assert(Reg_GPR_First <= RegNum && RegNum <= Reg_GPR_Last); - return GPRRegister(RegNum - Reg_GPR_First); - } - - static XmmRegister getEncodedXmm(int32_t RegNum) { - assert(Reg_XMM_First <= RegNum && RegNum <= Reg_XMM_Last); - return XmmRegister(RegNum - Reg_XMM_First); - } - - static ByteRegister getEncodedByteReg(int32_t RegNum) { - assert(RegNum == Reg_ah || (Reg_GPR_First <= RegNum && RegNum <= Reg_ebx)); - if (RegNum == Reg_ah) - return Encoded_Reg_ah; - return ByteRegister(RegNum - Reg_GPR_First); - } }; +// An enum of GPR Registers. The enum value does match encoding used +// to binary encode register operands in instructions. +enum GPRRegister { +#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ + frameptr, isI8, isInt, isFP) \ + Encoded_##val encode, + REGX8632_GPR_TABLE +#undef X + Encoded_Not_GPR = -1 +}; + +// An enum of XMM Registers. The enum value does match encoding used +// to binary encode register operands in instructions. +enum XmmRegister { +#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ + frameptr, isI8, isInt, isFP) \ + Encoded_##val encode, + REGX8632_XMM_TABLE +#undef X + Encoded_Not_Xmm = -1 +}; + +// An enum of Byte Registers. The enum value does match encoding used +// to binary encode register operands in instructions. +enum ByteRegister { +#define X(val, encode) Encoded_##val encode, + REGX8632_BYTEREG_TABLE +#undef X + Encoded_Not_ByteReg = -1 +}; + +static inline GPRRegister getEncodedGPR(int32_t RegNum) { + assert(Reg_GPR_First <= RegNum && RegNum <= Reg_GPR_Last); + return GPRRegister(RegNum - Reg_GPR_First); +} + +static inline XmmRegister getEncodedXmm(int32_t RegNum) { + assert(Reg_XMM_First <= RegNum && RegNum <= Reg_XMM_Last); + return XmmRegister(RegNum - Reg_XMM_First); +} + +static inline ByteRegister getEncodedByteReg(int32_t RegNum) { + assert(RegNum == Reg_ah || (Reg_GPR_First <= RegNum && RegNum <= Reg_ebx)); + if (RegNum == Reg_ah) + return Encoded_Reg_ah; + return ByteRegister(RegNum - Reg_GPR_First); +} + +} // end of namespace RegX8632 + } // end of namespace Ice #endif // SUBZERO_SRC_ICEREGISTERSX8632_H
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp index 3bae591..f663155 100644 --- a/src/IceTargetLowering.cpp +++ b/src/IceTargetLowering.cpp
@@ -15,6 +15,7 @@ // //===----------------------------------------------------------------------===// +#include "assembler_ia32.h" #include "IceCfg.h" // setError() #include "IceCfgNode.h" #include "IceOperand.h" @@ -97,6 +98,15 @@ return NULL; } +Assembler *TargetLowering::createAssembler(TargetArch Target, Cfg *Func) { + // These statements can be #ifdef'd to specialize the assembler + // to a subset of the available targets. TODO: use CRTP. + if (Target == Target_X8632) + return new x86::AssemblerX86(); + Func->setError("Unsupported target"); + return NULL; +} + void TargetLowering::doAddressOpt() { if (llvm::isa<InstLoad>(*Context.getCur())) doAddressOptLoad();
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h index 99716be..37e14df 100644 --- a/src/IceTargetLowering.h +++ b/src/IceTargetLowering.h
@@ -25,6 +25,8 @@ namespace Ice { +class Assembler; + // LoweringContext makes it easy to iterate through non-deleted // instructions in a node, and insert new (lowered) instructions at // the current point. Along with the instruction list container and @@ -87,6 +89,7 @@ class TargetLowering { public: static TargetLowering *createLowering(TargetArch Target, Cfg *Func); + static Assembler *createAssembler(TargetArch Target, Cfg *Func); void translate() { switch (Ctx->getOptLevel()) { case Opt_m1:
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp index 33a5741..6828940 100644 --- a/src/IceTargetLoweringX8632.cpp +++ b/src/IceTargetLoweringX8632.cpp
@@ -24,6 +24,7 @@ #include "IceRegistersX8632.h" #include "IceTargetLoweringX8632.def" #include "IceTargetLoweringX8632.h" +#include "IceUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/CommandLine.h" @@ -528,6 +529,14 @@ Str << "]"; } +x86::Address TargetX8632::stackVarToAsmOperand(const Variable *Var) const { + assert(!Var->hasReg()); + int32_t Offset = Var->getStackOffset(); + if (!hasFramePointer()) + Offset += getStackAdjustment(); + return x86::Address(RegX8632::getEncodedGPR(getFrameOrStackReg()), Offset); +} + void TargetX8632::lowerArguments() { VarList &Args = Func->getArgs(); // The first four arguments of vector type, regardless of their @@ -3710,7 +3719,7 @@ if (Var == NULL || Const == NULL || VMetadata->isMultiDef(Var)) return false; int32_t MoreOffset = IsAdd ? Const->getValue() : -Const->getValue(); - if (WouldOverflowAdd(Offset, MoreOffset)) + if (Utils::WouldOverflowAdd(Offset, MoreOffset)) return false; Base = Var; Offset += MoreOffset;
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h index 39609cf..71062cc 100644 --- a/src/IceTargetLoweringX8632.h +++ b/src/IceTargetLoweringX8632.h
@@ -18,6 +18,7 @@ #include "IceDefs.h" #include "IceTargetLowering.h" +#include "assembler_ia32.h" #include "IceInstX8632.h" #include "IceRegistersX8632.h" @@ -68,6 +69,7 @@ size_t BasicFrameOffset, size_t &InArgsSizeBytes); Operand *loOperand(Operand *Operand); Operand *hiOperand(Operand *Operand); + x86::Address stackVarToAsmOperand(const Variable *Var) const; enum X86InstructionSet { // SSE2 is the PNaCl baseline instruction set.
diff --git a/src/IceUtils.h b/src/IceUtils.h new file mode 100644 index 0000000..ffeb792 --- /dev/null +++ b/src/IceUtils.h
@@ -0,0 +1,59 @@ +//===- subzero/src/IceUtils.h - Utility functions ---------------*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares some utility functions +// +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ICEUTILS_H +#define SUBZERO_SRC_ICEUTILS_H + +#include <climits> + +namespace Ice { + +// Similar to bit_cast, but allows copying from types of unrelated +// sizes. This method was introduced to enable the strict aliasing +// optimizations of GCC 4.4. Basically, GCC mindlessly relies on +// obscure details in the C++ standard that make reinterpret_cast +// virtually useless. +template <class D, class S> inline D bit_copy(const S &source) { + D destination; + // This use of memcpy is safe: source and destination cannot overlap. + memcpy(&destination, reinterpret_cast<const void *>(&source), + sizeof(destination)); + return destination; +} + +class Utils { +public: + // Check whether an N-bit two's-complement representation can hold value. + template <typename T> static inline bool IsInt(int N, T value) { + assert((0 < N) && + (static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value)))); + T limit = static_cast<T>(1) << (N - 1); + return (-limit <= value) && (value < limit); + } + + template <typename T> static inline bool IsUint(int N, T value) { + assert((0 < N) && + (static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value)))); + T limit = static_cast<T>(1) << N; + return (0 <= value) && (value < limit); + } + + template <typename T> static inline bool WouldOverflowAdd(T X, T Y) { + return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) || + (X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - Y))); + } +}; + +} // end of namespace Ice + +#endif // SUBZERO_SRC_ICEUTILS_H
diff --git a/src/assembler.cpp b/src/assembler.cpp new file mode 100644 index 0000000..a169aff --- /dev/null +++ b/src/assembler.cpp
@@ -0,0 +1,129 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/assembler.cpp - Assembler base class -------------------===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Assembler class. +// +//===----------------------------------------------------------------------===// + +#include "assembler.h" +#include "IceMemoryRegion.h" + +namespace Ice { + +static uintptr_t NewContents(Assembler &assembler, intptr_t capacity) { + uintptr_t result = assembler.AllocateBytes(capacity); + return result; +} + +#if defined(DEBUG) +AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer *buffer) { + if (buffer->cursor() >= buffer->limit()) + buffer->ExtendCapacity(); + // In debug mode, we save the assembler buffer along with the gap + // size before we start emitting to the buffer. This allows us to + // check that any single generated instruction doesn't overflow the + // limit implied by the minimum gap size. + buffer_ = buffer; + gap_ = ComputeGap(); + // Make sure that extending the capacity leaves a big enough gap + // for any kind of instruction. + assert(gap_ >= kMinimumGap); + // Mark the buffer as having ensured the capacity. + assert(!buffer->HasEnsuredCapacity()); // Cannot nest. + buffer->has_ensured_capacity_ = true; +} + +AssemblerBuffer::EnsureCapacity::~EnsureCapacity() { + // Unmark the buffer, so we cannot emit after this. + buffer_->has_ensured_capacity_ = false; + // Make sure the generated instruction doesn't take up more + // space than the minimum gap. + intptr_t delta = gap_ - ComputeGap(); + assert(delta <= kMinimumGap); +} +#endif + +AssemblerBuffer::AssemblerBuffer(Assembler &assembler) : assembler_(assembler) { + const intptr_t OneKB = 1024; + static const intptr_t kInitialBufferCapacity = 4 * OneKB; + contents_ = NewContents(assembler_, kInitialBufferCapacity); + cursor_ = contents_; + limit_ = ComputeLimit(contents_, kInitialBufferCapacity); +#if defined(DEBUG) + has_ensured_capacity_ = false; + fixups_processed_ = false; +#endif + + // Verify internal state. + assert(Capacity() == kInitialBufferCapacity); + assert(Size() == 0); +} + +AssemblerBuffer::~AssemblerBuffer() {} + +AssemblerFixup *AssemblerBuffer::GetLatestFixup() const { + if (fixups_.empty()) + return NULL; + return fixups_.back(); +} + +void AssemblerBuffer::ProcessFixups(const MemoryRegion ®ion) { + for (SizeT I = 0; I < fixups_.size(); ++I) { + AssemblerFixup *fixup = fixups_[I]; + fixup->Process(region, fixup->position()); + } +} + +void AssemblerBuffer::FinalizeInstructions(const MemoryRegion &instructions) { + // Copy the instructions from the buffer. + MemoryRegion from(reinterpret_cast<void *>(contents()), Size()); + instructions.CopyFrom(0, from); + + // Process fixups in the instructions. + ProcessFixups(instructions); +#if defined(DEBUG) + fixups_processed_ = true; +#endif +} + +void AssemblerBuffer::ExtendCapacity() { + intptr_t old_size = Size(); + intptr_t old_capacity = Capacity(); + const intptr_t OneMB = 1 << 20; + intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB); + if (new_capacity < old_capacity) { + // FATAL + llvm_unreachable("Unexpected overflow in AssemblerBuffer::ExtendCapacity"); + } + + // Allocate the new data area and copy contents of the old one to it. + uintptr_t new_contents = NewContents(assembler_, new_capacity); + memmove(reinterpret_cast<void *>(new_contents), + reinterpret_cast<void *>(contents_), old_size); + + // Compute the relocation delta and switch to the new contents area. + intptr_t delta = new_contents - contents_; + contents_ = new_contents; + + // Update the cursor and recompute the limit. + cursor_ += delta; + limit_ = ComputeLimit(new_contents, new_capacity); + + // Verify internal state. + assert(Capacity() == new_capacity); + assert(Size() == old_size); +} + +} // end of namespace Ice
diff --git a/src/assembler.h b/src/assembler.h new file mode 100644 index 0000000..92cc98d --- /dev/null +++ b/src/assembler.h
@@ -0,0 +1,222 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/assembler.h - Integrated assembler -----------*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Assembler base class. Instructions are assembled +// by architecture-specific assemblers that derive from this base class. +// This base class manages buffers and fixups for emitting code, etc. +// +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ASSEMBLER_H +#define SUBZERO_SRC_ASSEMBLER_H + +#include "IceDefs.h" + +#include "IceFixups.h" +#include "llvm/Support/Allocator.h" + +namespace Ice { + +// Forward declarations. +class Assembler; +class AssemblerFixup; +class AssemblerBuffer; +class ConstantRelocatable; +class MemoryRegion; + +// Assembler fixups are positions in generated code that hold relocation +// information that needs to be processed before finalizing the code +// into executable memory. +class AssemblerFixup { +public: + virtual void Process(const MemoryRegion ®ion, intptr_t position) = 0; + + // It would be ideal if the destructor method could be made private, + // but the g++ compiler complains when this is subclassed. + virtual ~AssemblerFixup() { llvm_unreachable("~AssemblerFixup used"); } + + intptr_t position() const { return position_; } + + FixupKind kind() const { return kind_; } + + const ConstantRelocatable *value() const { return value_; } + +protected: + AssemblerFixup(FixupKind Kind, const ConstantRelocatable *Value) + : position_(0), kind_(Kind), value_(Value) {} + +private: + intptr_t position_; + FixupKind kind_; + const ConstantRelocatable *value_; + + void set_position(intptr_t position) { position_ = position; } + + AssemblerFixup(const AssemblerFixup &) LLVM_DELETED_FUNCTION; + AssemblerFixup &operator=(const AssemblerFixup &) LLVM_DELETED_FUNCTION; + friend class AssemblerBuffer; +}; + +// Assembler buffers are used to emit binary code. They grow on demand. +class AssemblerBuffer { +public: + AssemblerBuffer(Assembler &); + ~AssemblerBuffer(); + + // Basic support for emitting, loading, and storing. + template <typename T> void Emit(T value) { + assert(HasEnsuredCapacity()); + *reinterpret_cast<T *>(cursor_) = value; + cursor_ += sizeof(T); + } + + template <typename T> T Load(intptr_t position) const { + assert(position >= 0 && + position <= (Size() - static_cast<intptr_t>(sizeof(T)))); + return *reinterpret_cast<T *>(contents_ + position); + } + + template <typename T> void Store(intptr_t position, T value) { + assert(position >= 0 && + position <= (Size() - static_cast<intptr_t>(sizeof(T)))); + *reinterpret_cast<T *>(contents_ + position) = value; + } + + // Emit a fixup at the current location. + void EmitFixup(AssemblerFixup *fixup) { + fixup->set_position(Size()); + fixups_.push_back(fixup); + } + + // Get the size of the emitted code. + intptr_t Size() const { return cursor_ - contents_; } + uintptr_t contents() const { return contents_; } + + // Copy the assembled instructions into the specified memory block + // and apply all fixups. + // TODO(jvoung): This will be different. We'll be writing the text + // and reloc section to a file? + void FinalizeInstructions(const MemoryRegion ®ion); + +// To emit an instruction to the assembler buffer, the EnsureCapacity helper +// must be used to guarantee that the underlying data area is big enough to +// hold the emitted instruction. Usage: +// +// AssemblerBuffer buffer; +// AssemblerBuffer::EnsureCapacity ensured(&buffer); +// ... emit bytes for single instruction ... + +#if defined(DEBUG) + class EnsureCapacity { + public: + explicit EnsureCapacity(AssemblerBuffer *buffer); + ~EnsureCapacity(); + + private: + AssemblerBuffer *buffer_; + intptr_t gap_; + + intptr_t ComputeGap() { return buffer_->Capacity() - buffer_->Size(); } + }; + + bool has_ensured_capacity_; + bool HasEnsuredCapacity() const { return has_ensured_capacity_; } +#else + class EnsureCapacity { + public: + explicit EnsureCapacity(AssemblerBuffer *buffer) { + if (buffer->cursor() >= buffer->limit()) + buffer->ExtendCapacity(); + } + }; + + // When building the C++ tests, assertion code is enabled. To allow + // asserting that the user of the assembler buffer has ensured the + // capacity needed for emitting, we add a dummy method in non-debug mode. + bool HasEnsuredCapacity() const { return true; } +#endif + + // Returns the position in the instruction stream. + intptr_t GetPosition() const { return cursor_ - contents_; } + + // For bringup only. + AssemblerFixup *GetLatestFixup() const; + +private: + // The limit is set to kMinimumGap bytes before the end of the data area. + // This leaves enough space for the longest possible instruction and allows + // for a single, fast space check per instruction. + static const intptr_t kMinimumGap = 32; + + uintptr_t contents_; + uintptr_t cursor_; + uintptr_t limit_; + Assembler &assembler_; + std::vector<AssemblerFixup *> fixups_; +#if defined(DEBUG) + bool fixups_processed_; +#endif + + uintptr_t cursor() const { return cursor_; } + uintptr_t limit() const { return limit_; } + intptr_t Capacity() const { + assert(limit_ >= contents_); + return (limit_ - contents_) + kMinimumGap; + } + + // Process the fixup chain. + void ProcessFixups(const MemoryRegion ®ion); + + // Compute the limit based on the data area and the capacity. See + // description of kMinimumGap for the reasoning behind the value. + static uintptr_t ComputeLimit(uintptr_t data, intptr_t capacity) { + return data + capacity - kMinimumGap; + } + + void ExtendCapacity(); + + friend class AssemblerFixup; +}; + +class Assembler { +public: + Assembler() {} + ~Assembler() {} + + // Allocate a chunk of bytes using the per-Assembler allocator. + uintptr_t AllocateBytes(size_t bytes) { + // For now, alignment is not related to NaCl bundle alignment, since + // the buffer's GetPosition is relative to the base. So NaCl bundle + // alignment checks can be relative to that base. Later, the buffer + // will be copied out to a ".text" section (or an in memory-buffer + // that can be mprotect'ed with executable permission), and that + // second buffer should be aligned for NaCl. + const size_t Alignment = 16; + return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment)); + } + + // Allocate data of type T using the per-Assembler allocator. + template <typename T> T *Allocate() { return Allocator.Allocate<T>(); } + +private: + llvm::BumpPtrAllocator Allocator; + + Assembler(const Assembler &) LLVM_DELETED_FUNCTION; + Assembler &operator=(const Assembler &) LLVM_DELETED_FUNCTION; +}; + +} // end of namespace Ice + +#endif // SUBZERO_SRC_ASSEMBLER_H_
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp new file mode 100644 index 0000000..ceed1d1 --- /dev/null +++ b/src/assembler_ia32.cpp
@@ -0,0 +1,1822 @@ +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/assembler_ia32.cpp - Assembler for x86-32 -------------===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Assembler class for x86-32. +// +//===----------------------------------------------------------------------===// + +#include "assembler_ia32.h" +#include "IceCfg.h" +#include "IceMemoryRegion.h" +#include "IceOperand.h" + +namespace Ice { +namespace x86 { + +class DirectCallRelocation : public AssemblerFixup { +public: + static DirectCallRelocation *create(Assembler *Asm, FixupKind Kind, + const ConstantRelocatable *Sym) { + return new (Asm->Allocate<DirectCallRelocation>()) + DirectCallRelocation(Kind, Sym); + } + + void Process(const MemoryRegion ®ion, intptr_t position) { + // Direct calls are relative to the following instruction on x86. + int32_t pointer = region.Load<int32_t>(position); + int32_t delta = region.start() + position + sizeof(int32_t); + region.Store<int32_t>(position, pointer - delta); + } + +private: + DirectCallRelocation(FixupKind Kind, const ConstantRelocatable *Sym) + : AssemblerFixup(Kind, Sym) {} +}; + +Address Address::ofConstPool(GlobalContext *Ctx, Assembler *Asm, + const Constant *Imm) { + // We should make this much lighter-weight. E.g., just record the const pool + // entry ID. + std::string Buffer; + llvm::raw_string_ostream StrBuf(Buffer); + Type Ty = Imm->getType(); + assert(llvm::isa<ConstantFloat>(Imm) || llvm::isa<ConstantDouble>(Imm)); + StrBuf << "L$" << Ty << "$" << Imm->getPoolEntryID(); + const int64_t Offset = 0; + const bool SuppressMangling = true; + Constant *Sym = + Ctx->getConstantSym(Ty, Offset, StrBuf.str(), SuppressMangling); + AssemblerFixup *Fixup = x86::DisplacementRelocation::create( + Asm, FK_Abs_4, llvm::cast<ConstantRelocatable>(Sym)); + return x86::Address::Absolute(Offset, Fixup); +} + +void AssemblerX86::call(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitRegisterOperand(2, reg); +} + +void AssemblerX86::call(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(2, address); +} + +void AssemblerX86::call(Label *label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xE8); + static const int kSize = 5; + EmitLabel(label, kSize); +} + +void AssemblerX86::call(const ConstantRelocatable *label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + intptr_t call_start = buffer_.GetPosition(); + EmitUint8(0xE8); + EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); + EmitInt32(-4); + assert((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); +} + +void AssemblerX86::pushl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x50 + reg); +} + +void AssemblerX86::pushl(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(6, address); +} + +void AssemblerX86::pushl(const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x68); + EmitImmediate(imm); +} + +void AssemblerX86::popl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x58 + reg); +} + +void AssemblerX86::popl(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x8F); + EmitOperand(0, address); +} + +void AssemblerX86::pushal() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x60); +} + +void AssemblerX86::popal() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x61); +} + +void AssemblerX86::setcc(CondX86::BrCond condition, ByteRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x90 + condition); + EmitUint8(0xC0 + dst); +} + +void AssemblerX86::movl(GPRRegister dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xB8 + dst); + EmitImmediate(imm); +} + +void AssemblerX86::movl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x89); + EmitRegisterOperand(src, dst); +} + +void AssemblerX86::movl(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x8B); + EmitOperand(dst, src); +} + +void AssemblerX86::movl(const Address &dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x89); + EmitOperand(src, dst); +} + +void AssemblerX86::movl(const Address &dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC7); + EmitOperand(0, dst); + EmitImmediate(imm); +} + +void AssemblerX86::movzxb(GPRRegister dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB6); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::movzxb(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB6); + EmitOperand(dst, src); +} + +void AssemblerX86::movsxb(GPRRegister dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBE); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::movsxb(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBE); + EmitOperand(dst, src); +} + +void AssemblerX86::movb(ByteRegister dst, const Address &src) { + (void)dst; + (void)src; + // FATAL + llvm_unreachable("Use movzxb or movsxb instead."); +} + +void AssemblerX86::movb(const Address &dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x88); + EmitOperand(src, dst); +} + +void AssemblerX86::movb(const Address &dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC6); + EmitOperand(RegX8632::Encoded_Reg_eax, dst); + assert(imm.is_int8()); + EmitUint8(imm.value() & 0xFF); +} + +void AssemblerX86::movzxw(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB7); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::movzxw(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB7); + EmitOperand(dst, src); +} + +void AssemblerX86::movsxw(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBF); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::movsxw(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBF); + EmitOperand(dst, src); +} + +void AssemblerX86::movw(GPRRegister dst, const Address &src) { + (void)dst; + (void)src; + // FATAL + llvm_unreachable("Use movzxw or movsxw instead."); +} + +void AssemblerX86::movw(const Address &dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOperandSizeOverride(); + EmitUint8(0x89); + EmitOperand(src, dst); +} + +void AssemblerX86::leal(GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x8D); + EmitOperand(dst, src); +} + +void AssemblerX86::cmov(CondX86::BrCond cond, GPRRegister dst, + GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x40 + cond); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::rep_movsb() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0xA4); +} + +void AssemblerX86::movss(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x10); + EmitOperand(dst, src); +} + +void AssemblerX86::movss(const Address &dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitOperand(src, dst); +} + +void AssemblerX86::movss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitXmmRegisterOperand(src, dst); +} + +void AssemblerX86::movd(XmmRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x6E); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::movd(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x7E); + EmitOperand(src, Operand(dst)); +} + +void AssemblerX86::movq(const Address &dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xD6); + EmitOperand(src, Operand(dst)); +} + +void AssemblerX86::movq(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x7E); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::addss(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::addss(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitOperand(dst, src); +} + +void AssemblerX86::subss(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::subss(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitOperand(dst, src); +} + +void AssemblerX86::mulss(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::mulss(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitOperand(dst, src); +} + +void AssemblerX86::divss(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::divss(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitOperand(dst, src); +} + +void AssemblerX86::flds(const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(0, src); +} + +void AssemblerX86::fstps(const Address &dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(3, dst); +} + +void AssemblerX86::movsd(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x10); + EmitOperand(dst, src); +} + +void AssemblerX86::movsd(const Address &dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitOperand(src, dst); +} + +void AssemblerX86::movsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitXmmRegisterOperand(src, dst); +} + +void AssemblerX86::movaps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x28); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::movups(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x10); + EmitOperand(dst, src); +} + +void AssemblerX86::movups(const Address &dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitOperand(src, dst); +} + +void AssemblerX86::padd(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + if (Ty == IceType_i8 || Ty == IceType_i1) { + EmitUint8(0xFC); + } else if (Ty == IceType_i16) { + EmitUint8(0xFD); + } else { + EmitUint8(0xFE); + } + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::padd(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + if (Ty == IceType_i8 || Ty == IceType_i1) { + EmitUint8(0xFC); + } else if (Ty == IceType_i16) { + EmitUint8(0xFD); + } else { + EmitUint8(0xFE); + } + EmitOperand(dst, src); +} + +void AssemblerX86::pand(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xDB); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pand(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xDB); + EmitOperand(dst, src); +} + +void AssemblerX86::pandn(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xDF); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pandn(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xDF); + EmitOperand(dst, src); +} + +void AssemblerX86::pmuludq(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xF4); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pmuludq(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xF4); + EmitOperand(dst, src); +} + +void AssemblerX86::por(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xEB); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::por(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xEB); + EmitOperand(dst, src); +} + +void AssemblerX86::psub(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + if (Ty == IceType_i8 || Ty == IceType_i1) { + EmitUint8(0xF8); + } else if (Ty == IceType_i16) { + EmitUint8(0xF9); + } else { + EmitUint8(0xFA); + } + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::psub(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + if (Ty == IceType_i8 || Ty == IceType_i1) { + EmitUint8(0xF8); + } else if (Ty == IceType_i16) { + EmitUint8(0xF9); + } else { + EmitUint8(0xFA); + } + EmitOperand(dst, src); +} + +void AssemblerX86::pxor(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xEF); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pxor(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xEF); + EmitOperand(dst, src); +} + +// {add,sub,mul,div}ps are given a Ty parameter for consistency with +// {add,sub,mul,div}ss. In the future, when the PNaCl ABI allows +// addpd, etc., we can use the Ty parameter to decide on adding +// a 0x66 prefix. +void AssemblerX86::addps(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::addps(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitOperand(dst, src); +} + +void AssemblerX86::subps(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::subps(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitOperand(dst, src); +} + +void AssemblerX86::divps(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::divps(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitOperand(dst, src); +} + +void AssemblerX86::mulps(Type /* Ty */, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::mulps(Type /* Ty */, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitOperand(dst, src); +} + +void AssemblerX86::minps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5D); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::maxps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5F); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::andps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x54); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::andps(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x54); + EmitOperand(dst, src); +} + +void AssemblerX86::orps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x56); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cmpps(XmmRegister dst, XmmRegister src, + CondX86::CmppsCond CmpCondition) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xC2); + EmitXmmRegisterOperand(dst, src); + EmitUint8(CmpCondition); +} + +void AssemblerX86::cmpps(XmmRegister dst, const Address &src, + CondX86::CmppsCond CmpCondition) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xC2); + EmitOperand(dst, src); + EmitUint8(CmpCondition); +} + +void AssemblerX86::sqrtps(XmmRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitXmmRegisterOperand(dst, dst); +} + +void AssemblerX86::rsqrtps(XmmRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x52); + EmitXmmRegisterOperand(dst, dst); +} + +void AssemblerX86::reciprocalps(XmmRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x53); + EmitXmmRegisterOperand(dst, dst); +} + +void AssemblerX86::movhlps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x12); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::movlhps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x16); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::unpcklps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x14); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::unpckhps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x15); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::unpcklpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x14); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::unpckhpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x15); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::set1ps(XmmRegister dst, GPRRegister tmp1, + const Immediate &imm) { + // Load 32-bit immediate value into tmp1. + movl(tmp1, imm); + // Move value from tmp1 into dst. + movd(dst, tmp1); + // Broadcast low lane into other three lanes. + shufps(dst, dst, Immediate(0x0)); +} + +void AssemblerX86::shufps(XmmRegister dst, XmmRegister src, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xC6); + EmitXmmRegisterOperand(dst, src); + assert(imm.is_uint8()); + EmitUint8(imm.value()); +} + +void AssemblerX86::minpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x5D); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::maxpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x5F); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::sqrtpd(XmmRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitXmmRegisterOperand(dst, dst); +} + +void AssemblerX86::cvtps2pd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvtpd2ps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::shufpd(XmmRegister dst, XmmRegister src, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xC6); + EmitXmmRegisterOperand(dst, src); + assert(imm.is_uint8()); + EmitUint8(imm.value()); +} + +void AssemblerX86::cvtsi2ss(XmmRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2A); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::cvtsi2sd(XmmRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2A); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::cvtss2si(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2D); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvtss2sd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvtsd2si(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2D); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvttss2si(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2C); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvttsd2si(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2C); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvtsd2ss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::cvtdq2pd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0xE6); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::ucomiss(Type Ty, XmmRegister a, XmmRegister b) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (Ty == IceType_f64) + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x2E); + EmitXmmRegisterOperand(a, b); +} + +void AssemblerX86::ucomiss(Type Ty, XmmRegister a, const Address &b) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (Ty == IceType_f64) + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x2E); + EmitOperand(a, b); +} + +void AssemblerX86::movmskpd(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x50); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::movmskps(GPRRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x50); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::sqrtss(Type Ty, XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitOperand(dst, src); +} + +void AssemblerX86::sqrtss(Type Ty, XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(Ty == IceType_f32 ? 0xF3 : 0xF2); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::xorpd(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitOperand(dst, src); +} + +void AssemblerX86::xorpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::orpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x56); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::xorps(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitOperand(dst, src); +} + +void AssemblerX86::xorps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::andpd(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x54); + EmitOperand(dst, src); +} + +void AssemblerX86::andpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x54); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pextrd(GPRRegister dst, XmmRegister src, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x3A); + EmitUint8(0x16); + EmitOperand(src, Operand(dst)); + assert(imm.is_uint8()); + EmitUint8(imm.value()); +} + +void AssemblerX86::pmovsxdq(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x38); + EmitUint8(0x25); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::pcmpeqq(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x38); + EmitUint8(0x29); + EmitXmmRegisterOperand(dst, src); +} + +void AssemblerX86::roundsd(XmmRegister dst, XmmRegister src, + RoundingMode mode) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x3A); + EmitUint8(0x0B); + EmitXmmRegisterOperand(dst, src); + // Mask precision exeption. + EmitUint8(static_cast<uint8_t>(mode) | 0x8); +} + +void AssemblerX86::fldl(const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDD); + EmitOperand(0, src); +} + +void AssemblerX86::fstpl(const Address &dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDD); + EmitOperand(3, dst); +} + +void AssemblerX86::fnstcw(const Address &dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(7, dst); +} + +void AssemblerX86::fldcw(const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(5, src); +} + +void AssemblerX86::fistpl(const Address &dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDF); + EmitOperand(7, dst); +} + +void AssemblerX86::fistps(const Address &dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDB); + EmitOperand(3, dst); +} + +void AssemblerX86::fildl(const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDF); + EmitOperand(5, src); +} + +void AssemblerX86::filds(const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDB); + EmitOperand(0, src); +} + +void AssemblerX86::fincstp() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitUint8(0xF7); +} + +void AssemblerX86::xchgl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x87); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::cmpl(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(7, Operand(reg), imm); +} + +void AssemblerX86::cmpl(GPRRegister reg0, GPRRegister reg1) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x3B); + EmitOperand(reg0, Operand(reg1)); +} + +void AssemblerX86::cmpl(GPRRegister reg, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x3B); + EmitOperand(reg, address); +} + +void AssemblerX86::addl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x03); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::addl(GPRRegister reg, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x03); + EmitOperand(reg, address); +} + +void AssemblerX86::cmpl(const Address &address, GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x39); + EmitOperand(reg, address); +} + +void AssemblerX86::cmpl(const Address &address, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(7, address, imm); +} + +void AssemblerX86::cmpb(const Address &address, const Immediate &imm) { + assert(imm.is_int8()); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x80); + EmitOperand(7, address); + EmitUint8(imm.value() & 0xFF); +} + +void AssemblerX86::testl(GPRRegister reg1, GPRRegister reg2) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x85); + EmitRegisterOperand(reg1, reg2); +} + +void AssemblerX86::testl(GPRRegister reg, const Immediate &immediate) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + // For registers that have a byte variant (EAX, EBX, ECX, and EDX) + // we only test the byte register to keep the encoding short. + if (immediate.is_uint8() && reg < 4) { + // Use zero-extended 8-bit immediate. + if (reg == RegX8632::Encoded_Reg_eax) { + EmitUint8(0xA8); + } else { + EmitUint8(0xF6); + EmitUint8(0xC0 + reg); + } + EmitUint8(immediate.value() & 0xFF); + } else if (reg == RegX8632::Encoded_Reg_eax) { + // Use short form if the destination is EAX. + EmitUint8(0xA9); + EmitImmediate(immediate); + } else { + EmitUint8(0xF7); + EmitOperand(0, Operand(reg)); + EmitImmediate(immediate); + } +} + +void AssemblerX86::andl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x23); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::andl(GPRRegister dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(4, Operand(dst), imm); +} + +void AssemblerX86::andl(GPRRegister dst, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x23); + EmitOperand(dst, address); +} + +void AssemblerX86::orl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0B); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::orl(GPRRegister dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(1, Operand(dst), imm); +} + +void AssemblerX86::orl(GPRRegister dst, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0B); + EmitOperand(dst, address); +} + +void AssemblerX86::xorl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x33); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::xorl(GPRRegister dst, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(6, Operand(dst), imm); +} + +void AssemblerX86::xorl(GPRRegister dst, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x33); + EmitOperand(dst, address); +} + +void AssemblerX86::addl(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(0, Operand(reg), imm); +} + +void AssemblerX86::addl(const Address &address, GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x01); + EmitOperand(reg, address); +} + +void AssemblerX86::addl(const Address &address, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(0, address, imm); +} + +void AssemblerX86::adcl(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(2, Operand(reg), imm); +} + +void AssemblerX86::adcl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x13); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::adcl(GPRRegister dst, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x13); + EmitOperand(dst, address); +} + +void AssemblerX86::adcl(const Address &address, GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x11); + EmitOperand(reg, address); +} + +void AssemblerX86::subl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x2B); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::subl(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(5, Operand(reg), imm); +} + +void AssemblerX86::subl(GPRRegister reg, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x2B); + EmitOperand(reg, address); +} + +void AssemblerX86::subl(const Address &address, GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x29); + EmitOperand(reg, address); +} + +void AssemblerX86::cdq() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x99); +} + +void AssemblerX86::idivl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitUint8(0xF8 | reg); +} + +void AssemblerX86::imull(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAF); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::imull(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x69); + EmitOperand(reg, Operand(reg)); + EmitImmediate(imm); +} + +void AssemblerX86::imull(GPRRegister reg, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAF); + EmitOperand(reg, address); +} + +void AssemblerX86::imull(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(5, Operand(reg)); +} + +void AssemblerX86::imull(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(5, address); +} + +void AssemblerX86::mull(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(4, Operand(reg)); +} + +void AssemblerX86::mull(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(4, address); +} + +void AssemblerX86::sbbl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x1B); + EmitOperand(dst, Operand(src)); +} + +void AssemblerX86::sbbl(GPRRegister reg, const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(3, Operand(reg), imm); +} + +void AssemblerX86::sbbl(GPRRegister dst, const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x1B); + EmitOperand(dst, address); +} + +void AssemblerX86::sbbl(const Address &address, GPRRegister dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x19); + EmitOperand(dst, address); +} + +void AssemblerX86::incl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x40 + reg); +} + +void AssemblerX86::incl(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(0, address); +} + +void AssemblerX86::decl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48 + reg); +} + +void AssemblerX86::decl(const Address &address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(1, address); +} + +void AssemblerX86::shll(GPRRegister reg, const Immediate &imm) { + EmitGenericShift(4, reg, imm); +} + +void AssemblerX86::shll(GPRRegister operand, GPRRegister shifter) { + EmitGenericShift(4, Operand(operand), shifter); +} + +void AssemblerX86::shll(const Address &operand, GPRRegister shifter) { + EmitGenericShift(4, Operand(operand), shifter); +} + +void AssemblerX86::shrl(GPRRegister reg, const Immediate &imm) { + EmitGenericShift(5, reg, imm); +} + +void AssemblerX86::shrl(GPRRegister operand, GPRRegister shifter) { + EmitGenericShift(5, Operand(operand), shifter); +} + +void AssemblerX86::sarl(GPRRegister reg, const Immediate &imm) { + EmitGenericShift(7, reg, imm); +} + +void AssemblerX86::sarl(GPRRegister operand, GPRRegister shifter) { + EmitGenericShift(7, Operand(operand), shifter); +} + +void AssemblerX86::sarl(const Address &address, GPRRegister shifter) { + EmitGenericShift(7, Operand(address), shifter); +} + +void AssemblerX86::shld(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xA5); + EmitRegisterOperand(src, dst); +} + +void AssemblerX86::shld(GPRRegister dst, GPRRegister src, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(imm.is_int8()); + EmitUint8(0x0F); + EmitUint8(0xA4); + EmitRegisterOperand(src, dst); + EmitUint8(imm.value() & 0xFF); +} + +void AssemblerX86::shld(const Address &operand, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xA5); + EmitOperand(src, Operand(operand)); +} + +void AssemblerX86::shrd(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAD); + EmitRegisterOperand(src, dst); +} + +void AssemblerX86::shrd(GPRRegister dst, GPRRegister src, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(imm.is_int8()); + EmitUint8(0x0F); + EmitUint8(0xAC); + EmitRegisterOperand(src, dst); + EmitUint8(imm.value() & 0xFF); +} + +void AssemblerX86::shrd(const Address &dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAD); + EmitOperand(src, Operand(dst)); +} + +void AssemblerX86::negl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(3, Operand(reg)); +} + +void AssemblerX86::notl(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitUint8(0xD0 | reg); +} + +void AssemblerX86::bsrl(GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::bt(GPRRegister base, GPRRegister offset) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xA3); + EmitRegisterOperand(offset, base); +} + +void AssemblerX86::ret() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC3); +} + +void AssemblerX86::ret(const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC2); + assert(imm.is_uint16()); + EmitUint8(imm.value() & 0xFF); + EmitUint8((imm.value() >> 8) & 0xFF); +} + +void AssemblerX86::nop(int size) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + // There are nops up to size 15, but for now just provide up to size 8. + assert(0 < size && size <= MAX_NOP_SIZE); + switch (size) { + case 1: + EmitUint8(0x90); + break; + case 2: + EmitUint8(0x66); + EmitUint8(0x90); + break; + case 3: + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x00); + break; + case 4: + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x40); + EmitUint8(0x00); + break; + case 5: + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x44); + EmitUint8(0x00); + EmitUint8(0x00); + break; + case 6: + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x44); + EmitUint8(0x00); + EmitUint8(0x00); + break; + case 7: + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x80); + EmitUint8(0x00); + EmitUint8(0x00); + EmitUint8(0x00); + EmitUint8(0x00); + break; + case 8: + EmitUint8(0x0F); + EmitUint8(0x1F); + EmitUint8(0x84); + EmitUint8(0x00); + EmitUint8(0x00); + EmitUint8(0x00); + EmitUint8(0x00); + EmitUint8(0x00); + break; + default: + llvm_unreachable("Unimplemented"); + } +} + +void AssemblerX86::int3() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xCC); +} + +void AssemblerX86::hlt() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF4); +} + +void AssemblerX86::j(CondX86::BrCond condition, Label *label, bool near) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + static const int kLongSize = 6; + intptr_t offset = label->Position() - buffer_.Size(); + assert(offset <= 0); + if (Utils::IsInt(8, offset - kShortSize)) { + EmitUint8(0x70 + condition); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0x0F); + EmitUint8(0x80 + condition); + EmitInt32(offset - kLongSize); + } + } else if (near) { + EmitUint8(0x70 + condition); + EmitNearLabelLink(label); + } else { + EmitUint8(0x0F); + EmitUint8(0x80 + condition); + EmitLabelLink(label); + } +} + +void AssemblerX86::j(CondX86::BrCond condition, + const ConstantRelocatable *label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x80 + condition); + EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); + EmitInt32(-4); +} + +void AssemblerX86::jmp(GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitRegisterOperand(4, reg); +} + +void AssemblerX86::jmp(Label *label, bool near) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + static const int kLongSize = 5; + intptr_t offset = label->Position() - buffer_.Size(); + assert(offset <= 0); + if (Utils::IsInt(8, offset - kShortSize)) { + EmitUint8(0xEB); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xE9); + EmitInt32(offset - kLongSize); + } + } else if (near) { + EmitUint8(0xEB); + EmitNearLabelLink(label); + } else { + EmitUint8(0xE9); + EmitLabelLink(label); + } +} + +void AssemblerX86::jmp(const ConstantRelocatable *label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xE9); + EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); + EmitInt32(-4); +} + +void AssemblerX86::lock() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF0); +} + +void AssemblerX86::cmpxchgl(const Address &address, GPRRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB1); + EmitOperand(reg, address); +} + +void AssemblerX86::Align(intptr_t alignment, intptr_t offset) { + assert(llvm::isPowerOf2_32(alignment)); + intptr_t pos = offset + buffer_.GetPosition(); + intptr_t mod = pos & (alignment - 1); + if (mod == 0) { + return; + } + intptr_t bytes_needed = alignment - mod; + while (bytes_needed > MAX_NOP_SIZE) { + nop(MAX_NOP_SIZE); + bytes_needed -= MAX_NOP_SIZE; + } + if (bytes_needed) { + nop(bytes_needed); + } + assert(((offset + buffer_.GetPosition()) & (alignment - 1)) == 0); +} + +void AssemblerX86::Bind(Label *label) { + intptr_t bound = buffer_.Size(); + assert(!label->IsBound()); // Labels can only be bound once. + while (label->IsLinked()) { + intptr_t position = label->LinkPosition(); + intptr_t next = buffer_.Load<int32_t>(position); + buffer_.Store<int32_t>(position, bound - (position + 4)); + label->position_ = next; + } + while (label->HasNear()) { + intptr_t position = label->NearPosition(); + intptr_t offset = bound - (position + 1); + assert(Utils::IsInt(8, offset)); + buffer_.Store<int8_t>(position, offset); + } + label->BindTo(bound); +} + +void AssemblerX86::EmitOperand(int rm, const Operand &operand) { + assert(rm >= 0 && rm < 8); + const intptr_t length = operand.length_; + assert(length > 0); + // Emit the ModRM byte updated with the given RM value. + assert((operand.encoding_[0] & 0x38) == 0); + EmitUint8(operand.encoding_[0] + (rm << 3)); + if (operand.fixup()) { + EmitFixup(operand.fixup()); + } + // Emit the rest of the encoded operand. + for (intptr_t i = 1; i < length; i++) { + EmitUint8(operand.encoding_[i]); + } +} + +void AssemblerX86::EmitImmediate(const Immediate &imm) { + EmitInt32(imm.value()); +} + +void AssemblerX86::EmitComplexI8(int rm, const Operand &operand, + const Immediate &immediate) { + assert(rm >= 0 && rm < 8); + assert(immediate.is_int8()); + if (operand.IsRegister(RegX8632::Encoded_Reg_eax)) { + // Use short form if the destination is al. + EmitUint8(0x04 + (rm << 3)); + EmitUint8(immediate.value() & 0xFF); + } else { + // Use sign-extended 8-bit immediate. + EmitUint8(0x80); + EmitOperand(rm, operand); + EmitUint8(immediate.value() & 0xFF); + } +} + +void AssemblerX86::EmitComplex(int rm, const Operand &operand, + const Immediate &immediate) { + assert(rm >= 0 && rm < 8); + if (immediate.is_int8()) { + // Use sign-extended 8-bit immediate. + EmitUint8(0x83); + EmitOperand(rm, operand); + EmitUint8(immediate.value() & 0xFF); + } else if (operand.IsRegister(RegX8632::Encoded_Reg_eax)) { + // Use short form if the destination is eax. + EmitUint8(0x05 + (rm << 3)); + EmitImmediate(immediate); + } else { + EmitUint8(0x81); + EmitOperand(rm, operand); + EmitImmediate(immediate); + } +} + +void AssemblerX86::EmitLabel(Label *label, intptr_t instruction_size) { + if (label->IsBound()) { + intptr_t offset = label->Position() - buffer_.Size(); + assert(offset <= 0); + EmitInt32(offset - instruction_size); + } else { + EmitLabelLink(label); + } +} + +void AssemblerX86::EmitLabelLink(Label *label) { + assert(!label->IsBound()); + intptr_t position = buffer_.Size(); + EmitInt32(label->position_); + label->LinkTo(position); +} + +void AssemblerX86::EmitNearLabelLink(Label *label) { + assert(!label->IsBound()); + intptr_t position = buffer_.Size(); + EmitUint8(0); + label->NearLinkTo(position); +} + +void AssemblerX86::EmitGenericShift(int rm, GPRRegister reg, + const Immediate &imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(imm.is_int8()); + if (imm.value() == 1) { + EmitUint8(0xD1); + EmitOperand(rm, Operand(reg)); + } else { + EmitUint8(0xC1); + EmitOperand(rm, Operand(reg)); + EmitUint8(imm.value() & 0xFF); + } +} + +void AssemblerX86::EmitGenericShift(int rm, const Operand &operand, + GPRRegister shifter) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(shifter == RegX8632::Encoded_Reg_ecx); + EmitUint8(0xD3); + EmitOperand(rm, Operand(operand)); +} + +} // end of namespace x86 +} // end of namespace Ice
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h new file mode 100644 index 0000000..810fab3 --- /dev/null +++ b/src/assembler_ia32.h
@@ -0,0 +1,724 @@ +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Modified by the Subzero authors. +// +//===- subzero/src/assembler_ia32.h - Assembler for x86-32 ----------------===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Assembler class for x86-32. +// +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ASSEMBLER_IA32_H_ +#define SUBZERO_SRC_ASSEMBLER_IA32_H_ + +#include "IceDefs.h" +#include "IceConditionCodesX8632.h" +#include "IceRegistersX8632.h" +#include "IceTypes.h" +#include "IceUtils.h" + +#include "assembler.h" + +namespace Ice { + +class Assembler; +class ConstantRelocatable; + +using RegX8632::GPRRegister; +using RegX8632::XmmRegister; +using RegX8632::ByteRegister; + +namespace x86 { + +const int MAX_NOP_SIZE = 8; + +enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; + +class DisplacementRelocation : public AssemblerFixup { +public: + static DisplacementRelocation *create(Assembler *Asm, FixupKind Kind, + const ConstantRelocatable *Sym) { + return new (Asm->Allocate<DisplacementRelocation>()) + DisplacementRelocation(Kind, Sym); + } + + void Process(const MemoryRegion ®ion, intptr_t position) { + (void)region; + (void)position; + llvm_unreachable("We might not be using this Process() method later."); + } + +private: + DisplacementRelocation(FixupKind Kind, const ConstantRelocatable *Sym) + : AssemblerFixup(Kind, Sym) {} + DisplacementRelocation(const DisplacementRelocation &) LLVM_DELETED_FUNCTION; + DisplacementRelocation & + operator=(const DisplacementRelocation &) LLVM_DELETED_FUNCTION; +}; + +class Immediate { +public: + explicit Immediate(int32_t value) : value_(value) {} + + Immediate(const Immediate &other) : value_(other.value_) {} + + int32_t value() const { return value_; } + + bool is_int8() const { return Utils::IsInt(8, value_); } + bool is_uint8() const { return Utils::IsUint(8, value_); } + bool is_uint16() const { return Utils::IsUint(16, value_); } + +private: + const int32_t value_; +}; + +class Operand { +public: + uint8_t mod() const { return (encoding_at(0) >> 6) & 3; } + + GPRRegister rm() const { + return static_cast<GPRRegister>(encoding_at(0) & 7); + } + + ScaleFactor scale() const { + return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); + } + + GPRRegister index() const { + return static_cast<GPRRegister>((encoding_at(1) >> 3) & 7); + } + + GPRRegister base() const { + return static_cast<GPRRegister>(encoding_at(1) & 7); + } + + int8_t disp8() const { + assert(length_ >= 2); + return static_cast<int8_t>(encoding_[length_ - 1]); + } + + int32_t disp32() const { + assert(length_ >= 5); + return bit_copy<int32_t>(encoding_[length_ - 4]); + } + + AssemblerFixup *fixup() const { return fixup_; } + + Operand(const Operand &other) : length_(other.length_), fixup_(other.fixup_) { + memmove(&encoding_[0], &other.encoding_[0], other.length_); + } + + Operand &operator=(const Operand &other) { + length_ = other.length_; + fixup_ = other.fixup_; + memmove(&encoding_[0], &other.encoding_[0], other.length_); + return *this; + } + +protected: + Operand() : length_(0), fixup_(NULL) {} // Needed by subclass Address. + + void SetModRM(int mod, GPRRegister rm) { + assert((mod & ~3) == 0); + encoding_[0] = (mod << 6) | rm; + length_ = 1; + } + + void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) { + assert(length_ == 1); + assert((scale & ~3) == 0); + encoding_[1] = (scale << 6) | (index << 3) | base; + length_ = 2; + } + + void SetDisp8(int8_t disp) { + assert(length_ == 1 || length_ == 2); + encoding_[length_++] = static_cast<uint8_t>(disp); + } + + void SetDisp32(int32_t disp) { + assert(length_ == 1 || length_ == 2); + intptr_t disp_size = sizeof(disp); + memmove(&encoding_[length_], &disp, disp_size); + length_ += disp_size; + } + + void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; } + +private: + uint8_t length_; + uint8_t encoding_[6]; + uint8_t padding_; + AssemblerFixup *fixup_; + + explicit Operand(GPRRegister reg) : fixup_(NULL) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(intptr_t index) const { + assert(index >= 0 && index < length_); + return encoding_[index]; + } + + // Returns whether or not this operand is really the given register in + // disguise. Used from the assembler to generate better encodings. + bool IsRegister(GPRRegister reg) const { + return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. + && ((encoding_[0] & 0x07) == reg); // Register codes match. + } + + friend class AssemblerX86; +}; + +class Address : public Operand { +public: + Address(GPRRegister base, int32_t disp) { + if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) { + SetModRM(0, base); + if (base == RegX8632::Encoded_Reg_esp) + SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); + } else if (Utils::IsInt(8, disp)) { + SetModRM(1, base); + if (base == RegX8632::Encoded_Reg_esp) + SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); + SetDisp8(disp); + } else { + SetModRM(2, base); + if (base == RegX8632::Encoded_Reg_esp) + SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base); + SetDisp32(disp); + } + } + + Address(GPRRegister index, ScaleFactor scale, int32_t disp) { + assert(index != RegX8632::Encoded_Reg_esp); // Illegal addressing mode. + SetModRM(0, RegX8632::Encoded_Reg_esp); + SetSIB(scale, index, RegX8632::Encoded_Reg_ebp); + SetDisp32(disp); + } + + Address(GPRRegister base, GPRRegister index, ScaleFactor scale, + int32_t disp) { + assert(index != RegX8632::Encoded_Reg_esp); // Illegal addressing mode. + if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) { + SetModRM(0, RegX8632::Encoded_Reg_esp); + SetSIB(scale, index, base); + } else if (Utils::IsInt(8, disp)) { + SetModRM(1, RegX8632::Encoded_Reg_esp); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, RegX8632::Encoded_Reg_esp); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + Address(const Address &other) : Operand(other) {} + + Address &operator=(const Address &other) { + Operand::operator=(other); + return *this; + } + + static Address Absolute(const uintptr_t addr, AssemblerFixup *fixup) { + Address result; + result.SetModRM(0, RegX8632::Encoded_Reg_ebp); + result.SetDisp32(addr); + result.SetFixup(fixup); + return result; + } + + static Address ofConstPool(GlobalContext *Ctx, Assembler *Asm, + const Constant *Imm); + +private: + Address() {} // Needed by Address::Absolute. +}; + +class Label { +public: + Label() : position_(0), num_unresolved_(0) { +#ifdef DEBUG + for (int i = 0; i < kMaxUnresolvedBranches; i++) { + unresolved_near_positions_[i] = -1; + } +#endif // DEBUG + } + + ~Label() { + // Assert if label is being destroyed with unresolved branches pending. + assert(!IsLinked()); + assert(!HasNear()); + } + + // TODO(jvoung): why are labels offset by this? + static const uint32_t kWordSize = sizeof(uint32_t); + + // Returns the position for bound labels (branches that come after this + // are considered backward branches). Cannot be used for unused or linked + // labels. + intptr_t Position() const { + assert(IsBound()); + return -position_ - kWordSize; + } + + // Returns the position of an earlier branch instruction that was linked + // to this label (branches that use this are considered forward branches). + // The linked instructions form a linked list, of sorts, using the + // instruction's displacement field for the location of the next + // instruction that is also linked to this label. + intptr_t LinkPosition() const { + assert(IsLinked()); + return position_ - kWordSize; + } + + // Returns the position of an earlier branch instruction which + // assumes that this label is "near", and bumps iterator to the + // next near position. + intptr_t NearPosition() { + assert(HasNear()); + return unresolved_near_positions_[--num_unresolved_]; + } + + bool IsBound() const { return position_ < 0; } + bool IsLinked() const { return position_ > 0; } + bool IsUnused() const { return (position_ == 0) && (num_unresolved_ == 0); } + bool HasNear() const { return num_unresolved_ != 0; } + +private: + void BindTo(intptr_t position) { + assert(!IsBound()); + assert(!HasNear()); + position_ = -position - kWordSize; + assert(IsBound()); + } + + void LinkTo(intptr_t position) { + assert(!IsBound()); + position_ = position + kWordSize; + assert(IsLinked()); + } + + void NearLinkTo(intptr_t position) { + assert(!IsBound()); + assert(num_unresolved_ < kMaxUnresolvedBranches); + unresolved_near_positions_[num_unresolved_++] = position; + } + + static const int kMaxUnresolvedBranches = 20; + + intptr_t position_; + intptr_t num_unresolved_; + intptr_t unresolved_near_positions_[kMaxUnresolvedBranches]; + + friend class AssemblerX86; + Label(const Label &) LLVM_DELETED_FUNCTION; + Label &operator=(const Label &) LLVM_DELETED_FUNCTION; +}; + +class AssemblerX86 : public Assembler { +public: + explicit AssemblerX86(bool use_far_branches = false) : buffer_(*this) { + // This mode is only needed and implemented for MIPS and ARM. + assert(!use_far_branches); + } + ~AssemblerX86() {} + + static const bool kNearJump = true; + static const bool kFarJump = false; + + // Operations to emit XMM instructions (and dispatch on operand type). + typedef void (AssemblerX86::*TypedEmitXmmXmm)(Type, XmmRegister, XmmRegister); + typedef void (AssemblerX86::*TypedEmitXmmAddr)(Type, XmmRegister, + const Address &); + typedef void (AssemblerX86::*TypedEmitAddrXmm)(Type, const Address &, + XmmRegister); + struct TypedXmmEmitters { + TypedEmitXmmXmm XmmXmm; + TypedEmitXmmAddr XmmAddr; + TypedEmitAddrXmm AddrXmm; + }; + + /* + * Emit Machine Instructions. + */ + void call(GPRRegister reg); + void call(const Address &address); + void call(Label *label); + void call(const ConstantRelocatable *label); + + static const intptr_t kCallExternalLabelSize = 5; + + void pushl(GPRRegister reg); + void pushl(const Address &address); + void pushl(const Immediate &imm); + + void popl(GPRRegister reg); + void popl(const Address &address); + + void pushal(); + void popal(); + + void setcc(CondX86::BrCond condition, ByteRegister dst); + + void movl(GPRRegister dst, const Immediate &src); + void movl(GPRRegister dst, GPRRegister src); + + void movl(GPRRegister dst, const Address &src); + void movl(const Address &dst, GPRRegister src); + void movl(const Address &dst, const Immediate &imm); + + void movzxb(GPRRegister dst, ByteRegister src); + void movzxb(GPRRegister dst, const Address &src); + void movsxb(GPRRegister dst, ByteRegister src); + void movsxb(GPRRegister dst, const Address &src); + + void movb(ByteRegister dst, const Address &src); + void movb(const Address &dst, ByteRegister src); + void movb(const Address &dst, const Immediate &imm); + + void movzxw(GPRRegister dst, GPRRegister src); + void movzxw(GPRRegister dst, const Address &src); + void movsxw(GPRRegister dst, GPRRegister src); + void movsxw(GPRRegister dst, const Address &src); + void movw(GPRRegister dst, const Address &src); + void movw(const Address &dst, GPRRegister src); + + void leal(GPRRegister dst, const Address &src); + + void cmov(CondX86::BrCond cond, GPRRegister dst, GPRRegister src); + + void rep_movsb(); + + void movss(XmmRegister dst, const Address &src); + void movss(const Address &dst, XmmRegister src); + void movss(XmmRegister dst, XmmRegister src); + + void movd(XmmRegister dst, GPRRegister src); + void movd(GPRRegister dst, XmmRegister src); + + void movq(const Address &dst, XmmRegister src); + void movq(XmmRegister dst, const Address &src); + + void addss(Type Ty, XmmRegister dst, XmmRegister src); + void addss(Type Ty, XmmRegister dst, const Address &src); + void subss(Type Ty, XmmRegister dst, XmmRegister src); + void subss(Type Ty, XmmRegister dst, const Address &src); + void mulss(Type Ty, XmmRegister dst, XmmRegister src); + void mulss(Type Ty, XmmRegister dst, const Address &src); + void divss(Type Ty, XmmRegister dst, XmmRegister src); + void divss(Type Ty, XmmRegister dst, const Address &src); + + void movsd(XmmRegister dst, const Address &src); + void movsd(const Address &dst, XmmRegister src); + void movsd(XmmRegister dst, XmmRegister src); + + void movaps(XmmRegister dst, XmmRegister src); + + void movups(XmmRegister dst, const Address &src); + void movups(const Address &dst, XmmRegister src); + + void padd(Type Ty, XmmRegister dst, XmmRegister src); + void padd(Type Ty, XmmRegister dst, const Address &src); + void pand(Type Ty, XmmRegister dst, XmmRegister src); + void pand(Type Ty, XmmRegister dst, const Address &src); + void pandn(Type Ty, XmmRegister dst, XmmRegister src); + void pandn(Type Ty, XmmRegister dst, const Address &src); + void pmuludq(Type Ty, XmmRegister dst, XmmRegister src); + void pmuludq(Type Ty, XmmRegister dst, const Address &src); + void por(Type Ty, XmmRegister dst, XmmRegister src); + void por(Type Ty, XmmRegister dst, const Address &src); + void psub(Type Ty, XmmRegister dst, XmmRegister src); + void psub(Type Ty, XmmRegister dst, const Address &src); + void pxor(Type Ty, XmmRegister dst, XmmRegister src); + void pxor(Type Ty, XmmRegister dst, const Address &src); + + void addps(Type Ty, XmmRegister dst, XmmRegister src); + void addps(Type Ty, XmmRegister dst, const Address &src); + void subps(Type Ty, XmmRegister dst, XmmRegister src); + void subps(Type Ty, XmmRegister dst, const Address &src); + void divps(Type Ty, XmmRegister dst, XmmRegister src); + void divps(Type Ty, XmmRegister dst, const Address &src); + void mulps(Type Ty, XmmRegister dst, XmmRegister src); + void mulps(Type Ty, XmmRegister dst, const Address &src); + void minps(XmmRegister dst, XmmRegister src); + void maxps(XmmRegister dst, XmmRegister src); + void andps(XmmRegister dst, XmmRegister src); + void andps(XmmRegister dst, const Address &src); + void orps(XmmRegister dst, XmmRegister src); + + void cmpps(XmmRegister dst, XmmRegister src, CondX86::CmppsCond CmpCondition); + void cmpps(XmmRegister dst, const Address &src, + CondX86::CmppsCond CmpCondition); + + void sqrtps(XmmRegister dst); + void rsqrtps(XmmRegister dst); + void reciprocalps(XmmRegister dst); + void movhlps(XmmRegister dst, XmmRegister src); + void movlhps(XmmRegister dst, XmmRegister src); + void unpcklps(XmmRegister dst, XmmRegister src); + void unpckhps(XmmRegister dst, XmmRegister src); + void unpcklpd(XmmRegister dst, XmmRegister src); + void unpckhpd(XmmRegister dst, XmmRegister src); + + void set1ps(XmmRegister dst, GPRRegister tmp, const Immediate &imm); + void shufps(XmmRegister dst, XmmRegister src, const Immediate &mask); + + void minpd(XmmRegister dst, XmmRegister src); + void maxpd(XmmRegister dst, XmmRegister src); + void sqrtpd(XmmRegister dst); + void cvtps2pd(XmmRegister dst, XmmRegister src); + void cvtpd2ps(XmmRegister dst, XmmRegister src); + void shufpd(XmmRegister dst, XmmRegister src, const Immediate &mask); + + void cvtsi2ss(XmmRegister dst, GPRRegister src); + void cvtsi2sd(XmmRegister dst, GPRRegister src); + + void cvtss2si(GPRRegister dst, XmmRegister src); + void cvtss2sd(XmmRegister dst, XmmRegister src); + + void cvtsd2si(GPRRegister dst, XmmRegister src); + void cvtsd2ss(XmmRegister dst, XmmRegister src); + + void cvttss2si(GPRRegister dst, XmmRegister src); + void cvttsd2si(GPRRegister dst, XmmRegister src); + + void cvtdq2pd(XmmRegister dst, XmmRegister src); + + void ucomiss(Type Ty, XmmRegister a, XmmRegister b); + void ucomiss(Type Ty, XmmRegister a, const Address &b); + + void movmskpd(GPRRegister dst, XmmRegister src); + void movmskps(GPRRegister dst, XmmRegister src); + + void sqrtss(Type Ty, XmmRegister dst, const Address &src); + void sqrtss(Type Ty, XmmRegister dst, XmmRegister src); + + void xorpd(XmmRegister dst, const Address &src); + void xorpd(XmmRegister dst, XmmRegister src); + void xorps(XmmRegister dst, const Address &src); + void xorps(XmmRegister dst, XmmRegister src); + + void andpd(XmmRegister dst, const Address &src); + void andpd(XmmRegister dst, XmmRegister src); + + void orpd(XmmRegister dst, XmmRegister src); + + void pextrd(GPRRegister dst, XmmRegister src, const Immediate &imm); + void pmovsxdq(XmmRegister dst, XmmRegister src); + void pcmpeqq(XmmRegister dst, XmmRegister src); + + enum RoundingMode { + kRoundToNearest = 0x0, + kRoundDown = 0x1, + kRoundUp = 0x2, + kRoundToZero = 0x3 + }; + void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode); + + void flds(const Address &src); + void fstps(const Address &dst); + + void fldl(const Address &src); + void fstpl(const Address &dst); + + void fnstcw(const Address &dst); + void fldcw(const Address &src); + + void fistpl(const Address &dst); + void fistps(const Address &dst); + void fildl(const Address &src); + void filds(const Address &src); + + void fincstp(); + + void xchgl(GPRRegister dst, GPRRegister src); + + void cmpl(GPRRegister reg, const Immediate &imm); + void cmpl(GPRRegister reg0, GPRRegister reg1); + void cmpl(GPRRegister reg, const Address &address); + void cmpl(const Address &address, GPRRegister reg); + void cmpl(const Address &address, const Immediate &imm); + void cmpb(const Address &address, const Immediate &imm); + + void testl(GPRRegister reg1, GPRRegister reg2); + void testl(GPRRegister reg, const Immediate &imm); + + void andl(GPRRegister dst, const Immediate &imm); + void andl(GPRRegister dst, GPRRegister src); + void andl(GPRRegister dst, const Address &address); + + void orl(GPRRegister dst, const Immediate &imm); + void orl(GPRRegister dst, GPRRegister src); + void orl(GPRRegister dst, const Address &address); + + void xorl(GPRRegister dst, const Immediate &imm); + void xorl(GPRRegister dst, GPRRegister src); + void xorl(GPRRegister dst, const Address &address); + + void addl(GPRRegister dst, GPRRegister src); + void addl(GPRRegister reg, const Immediate &imm); + void addl(GPRRegister reg, const Address &address); + + void addl(const Address &address, GPRRegister reg); + void addl(const Address &address, const Immediate &imm); + + void adcl(GPRRegister dst, GPRRegister src); + void adcl(GPRRegister reg, const Immediate &imm); + void adcl(GPRRegister dst, const Address &address); + void adcl(const Address &dst, GPRRegister src); + + void subl(GPRRegister dst, GPRRegister src); + void subl(GPRRegister reg, const Immediate &imm); + void subl(GPRRegister reg, const Address &address); + void subl(const Address &address, GPRRegister reg); + + void cdq(); + + void idivl(GPRRegister reg); + + void imull(GPRRegister dst, GPRRegister src); + void imull(GPRRegister reg, const Immediate &imm); + void imull(GPRRegister reg, const Address &address); + + void imull(GPRRegister reg); + void imull(const Address &address); + + void mull(GPRRegister reg); + void mull(const Address &address); + + void sbbl(GPRRegister dst, GPRRegister src); + void sbbl(GPRRegister reg, const Immediate &imm); + void sbbl(GPRRegister reg, const Address &address); + void sbbl(const Address &address, GPRRegister reg); + + void incl(GPRRegister reg); + void incl(const Address &address); + + void decl(GPRRegister reg); + void decl(const Address &address); + + void shll(GPRRegister reg, const Immediate &imm); + void shll(GPRRegister operand, GPRRegister shifter); + void shll(const Address &operand, GPRRegister shifter); + void shrl(GPRRegister reg, const Immediate &imm); + void shrl(GPRRegister operand, GPRRegister shifter); + void sarl(GPRRegister reg, const Immediate &imm); + void sarl(GPRRegister operand, GPRRegister shifter); + void sarl(const Address &address, GPRRegister shifter); + void shld(GPRRegister dst, GPRRegister src); + void shld(GPRRegister dst, GPRRegister src, const Immediate &imm); + void shld(const Address &operand, GPRRegister src); + void shrd(GPRRegister dst, GPRRegister src); + void shrd(GPRRegister dst, GPRRegister src, const Immediate &imm); + void shrd(const Address &dst, GPRRegister src); + + void negl(GPRRegister reg); + void notl(GPRRegister reg); + + void bsrl(GPRRegister dst, GPRRegister src); + + void bt(GPRRegister base, GPRRegister offset); + + void ret(); + void ret(const Immediate &imm); + + // 'size' indicates size in bytes and must be in the range 1..8. + void nop(int size = 1); + void int3(); + void hlt(); + + void j(CondX86::BrCond condition, Label *label, bool near = kFarJump); + void j(CondX86::BrCond condition, const ConstantRelocatable *label); + + void jmp(GPRRegister reg); + void jmp(Label *label, bool near = kFarJump); + void jmp(const ConstantRelocatable *label); + + void lock(); + void cmpxchgl(const Address &address, GPRRegister reg); + + void LockCmpxchgl(const Address &address, GPRRegister reg) { + lock(); + cmpxchgl(address, reg); + } + + intptr_t PreferredLoopAlignment() { return 16; } + void Align(intptr_t alignment, intptr_t offset); + void Bind(Label *label); + + intptr_t CodeSize() const { return buffer_.Size(); } + + void FinalizeInstructions(const MemoryRegion ®ion) { + buffer_.FinalizeInstructions(region); + } + + // Expose the buffer, for bringup... + intptr_t GetPosition() const { return buffer_.GetPosition(); } + template <typename T> T LoadBuffer(intptr_t position) const { + return buffer_.Load<T>(position); + } + AssemblerFixup *GetLatestFixup() const { return buffer_.GetLatestFixup(); } + +private: + inline void EmitUint8(uint8_t value); + inline void EmitInt32(int32_t value); + inline void EmitRegisterOperand(int rm, int reg); + inline void EmitXmmRegisterOperand(int rm, XmmRegister reg); + inline void EmitFixup(AssemblerFixup *fixup); + inline void EmitOperandSizeOverride(); + + void EmitOperand(int rm, const Operand &operand); + void EmitImmediate(const Immediate &imm); + void EmitComplexI8(int rm, const Operand &operand, + const Immediate &immediate); + void EmitComplex(int rm, const Operand &operand, const Immediate &immediate); + void EmitLabel(Label *label, intptr_t instruction_size); + void EmitLabelLink(Label *label); + void EmitNearLabelLink(Label *label); + + void EmitGenericShift(int rm, GPRRegister reg, const Immediate &imm); + void EmitGenericShift(int rm, const Operand &operand, GPRRegister shifter); + + AssemblerBuffer buffer_; + + AssemblerX86(const AssemblerX86 &) LLVM_DELETED_FUNCTION; + AssemblerX86 &operator=(const AssemblerX86 &) LLVM_DELETED_FUNCTION; +}; + +inline void AssemblerX86::EmitUint8(uint8_t value) { + buffer_.Emit<uint8_t>(value); +} + +inline void AssemblerX86::EmitInt32(int32_t value) { + buffer_.Emit<int32_t>(value); +} + +inline void AssemblerX86::EmitRegisterOperand(int rm, int reg) { + assert(rm >= 0 && rm < 8); + buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg); +} + +inline void AssemblerX86::EmitXmmRegisterOperand(int rm, XmmRegister reg) { + EmitRegisterOperand(rm, static_cast<GPRRegister>(reg)); +} + +inline void AssemblerX86::EmitFixup(AssemblerFixup *fixup) { + buffer_.EmitFixup(fixup); +} + +inline void AssemblerX86::EmitOperandSizeOverride() { EmitUint8(0x66); } + +} // end of namespace x86 +} // end of namespace Ice + +#endif // SUBZERO_SRC_ASSEMBLER_IA32_H_
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp index f147877..3da3f4f 100644 --- a/src/llvm2ice.cpp +++ b/src/llvm2ice.cpp
@@ -130,6 +130,11 @@ cl::desc("Build ICE instructions when reading bitcode"), cl::init(false)); +static cl::opt<bool> + UseIntegratedAssembler("integrated-as", + cl::desc("Use integrated assembler (default yes)"), + cl::init(true)); + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); @@ -158,6 +163,7 @@ Flags.DisableTranslation = DisableTranslation; Flags.DisableGlobals = DisableGlobals; Flags.FunctionSections = FunctionSections; + Flags.UseIntegratedAssembler = UseIntegratedAssembler; Flags.UseSandboxing = UseSandboxing; Flags.DumpStats = DumpStats; Flags.DefaultGlobalPrefix = DefaultGlobalPrefix;