Index: src/IceInstX8632.cpp |
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp |
index 373ab59e47503c4b3535edaaf87bc17a4aa015f5..25db6c73cdf967fbb7a33deac071b80c019d3e1c 100644 |
--- a/src/IceInstX8632.cpp |
+++ b/src/IceInstX8632.cpp |
@@ -12,6 +12,7 @@ |
// |
//===----------------------------------------------------------------------===// |
+#include "assembler_ia32.h" |
#include "IceCfg.h" |
#include "IceCfgNode.h" |
#include "IceInst.h" |
@@ -63,6 +64,50 @@ const char *InstX8632SegmentRegNames[] = { |
#undef X |
}; |
+x86::Condition convertToAsmCondition(InstX8632::BrCond Cond) { |
+ return x86::Condition(Cond); |
+} |
+ |
+x86::Register convertToAsmGPR(int32_t RegNum) { |
+ assert(TargetX8632::Reg_eax <= RegNum && RegNum <= TargetX8632::Reg_edi); |
+ return x86::Register(RegNum); |
+} |
+ |
+x86::ByteRegister convertToAsmByteRegister(int32_t RegNum) { |
+ if (RegNum == TargetX8632::Reg_ah) { |
+ return x86::AH; |
+ } |
+ assert(TargetX8632::Reg_eax <= RegNum && RegNum <= TargetX8632::Reg_ebx); |
+ return x86::ByteRegister(RegNum); |
+} |
+ |
+x86::Immediate convertIntImmToAsmImm(const ConstantInteger32 *CI) { |
+ int32_t V = static_cast<int32_t>(CI->getValue()); |
+ return x86::Immediate(V); |
+} |
+ |
+x86::XmmRegister convertToAsmXMMReg(int32_t RegNum) { |
+ assert(TargetX8632::Reg_xmm0 <= RegNum && RegNum <= TargetX8632::Reg_xmm7); |
+ return x86::XmmRegister(RegNum - TargetX8632::Reg_xmm0); |
+} |
+ |
+// Convert a float or double immediate to an Address Operand. |
+x86::Address convertFloatImmToAsmAddr(GlobalContext *Ctx, Assembler *Asm, |
+ const Constant *Imm) { |
+ 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); |
+} |
+ |
} // end of anonymous namespace |
const char *InstX8632::getWidthString(Type Ty) { |
@@ -285,12 +330,216 @@ InstX8632Xchg::InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source) |
// ======================== 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"; |
+ } |
+} |
+ |
+void emitIASTwoOperandGPR(const Cfg *Func, const Operand *Src0, |
+ const Operand *Src1, |
+ x86::AssemblerX86::EmitTyRegReg EmitRegReg, |
+ x86::AssemblerX86::EmitTyRegAddr EmitRegAddr, |
+ x86::AssemblerX86::EmitTyRegImm EmitRegImm, |
+ x86::AssemblerX86::EmitTyAddrReg EmitAddrReg = NULL, |
+ x86::AssemblerX86::EmitTyAddrImm EmitAddrImm = NULL) { |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ Type Ty = Src0->getType(); |
+ |
+ // Classify Src0 (Reg or Mem). |
+ bool Src0IsReg = false; |
+ x86::Register Src0Reg = x86::kNoRegister; |
+ x86::Address Src0Addr = x86::Address::Absolute(0, NULL); |
+ if (const Variable *Src0Var = llvm::dyn_cast<Variable>(Src0)) { |
+ if (Src0Var->hasReg()) { |
+ Src0IsReg = true; |
+ if (typeWidthInBytes(Ty) == 1) { |
+ Src0Reg = |
+ convertToAsmGPR(convertToAsmByteRegister(Src0Var->getRegNum())); |
+ } else { |
+ Src0Reg = convertToAsmGPR(Src0Var->getRegNum()); |
+ } |
+ } else { |
+ Src0Addr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(Src0Var); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src0)) { |
+ assert(EmitAddrReg != NULL && EmitAddrImm != NULL); |
+ Src0Addr = Mem->convertToAsmAddress(Asm); |
+ } |
+ |
+ // Classify Src1 (Reg, Mem, or Imm). |
+ if (const Variable *Src1Var = llvm::dyn_cast<Variable>(Src1)) { |
+ if (Src1Var->hasReg()) { |
+ x86::Register Src1Reg; |
+ if (typeWidthInBytes(Ty) == 1) { |
+ Src1Reg = |
+ convertToAsmGPR(convertToAsmByteRegister(Src1Var->getRegNum())); |
+ } else { |
+ Src1Reg = convertToAsmGPR(Src1Var->getRegNum()); |
+ } |
+ if (Src0IsReg) |
+ (Asm->*EmitRegReg)(Ty, Src0Reg, Src1Reg); |
+ else |
+ (Asm->*EmitAddrReg)(Ty, Src0Addr, Src1Reg); |
+ } else { |
+ x86::Address Src1Addr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(Src1Var); |
+ assert(Src0IsReg); |
+ (Asm->*EmitRegAddr)(Ty, Src0Reg, Src1Addr); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src1)) { |
+ x86::Address Src1Addr = Mem->convertToAsmAddress(Asm); |
+ assert(Src0IsReg); |
+ (Asm->*EmitRegAddr)(Ty, Src0Reg, Src1Addr); |
+ } else if (const ConstantInteger32 *CI = |
+ llvm::dyn_cast<ConstantInteger32>(Src1)) { |
+ x86::Immediate Imm = convertIntImmToAsmImm(CI); |
+ if (Src0IsReg) |
+ (Asm->*EmitRegImm)(Ty, Src0Reg, Imm); |
+ else |
+ (Asm->*EmitAddrImm)(Ty, Src0Addr, Imm); |
+ } else { |
+ llvm_unreachable("Unexpected operand type"); |
+ } |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
+void emitIASVarOperandXMM(const Cfg *Func, const Variable *Var, |
+ const Operand *Src, |
+ x86::AssemblerX86::EmitXmmXmm EmitXmmXmm, |
+ x86::AssemblerX86::EmitXmmAddr EmitXmmAddr) { |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ assert(Var->hasReg()); |
+ x86::XmmRegister VarReg = convertToAsmXMMReg(Var->getRegNum()); |
+ if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src)) { |
+ if (SrcVar->hasReg()) { |
+ x86::XmmRegister SrcReg = convertToAsmXMMReg(SrcVar->getRegNum()); |
+ (Asm->*EmitXmmXmm)(VarReg, SrcReg); |
+ } else { |
+ x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(SrcVar); |
+ (Asm->*EmitXmmAddr)(VarReg, SrcStackAddr); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src)) { |
+ x86::Address SrcAddr = Mem->convertToAsmAddress(Asm); |
+ (Asm->*EmitXmmAddr)(VarReg, SrcAddr); |
+ } else if (const Constant *Imm = llvm::dyn_cast<Constant>(Src)) { |
+ (Asm->*EmitXmmAddr)(VarReg, |
+ convertFloatImmToAsmAddr(Func->getContext(), Asm, Imm)); |
+ } else { |
+ llvm_unreachable("Unexpected operand type"); |
+ } |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
+void |
+emitIASTwoOperandTyXMM(const Cfg *Func, Type Ty, const Operand *Src0, |
+ const Operand *Src1, |
+ x86::AssemblerX86::EmitTyXmmXmm EmitXmmXmm, |
+ x86::AssemblerX86::EmitTyXmmAddr EmitXmmAddr, |
+ x86::AssemblerX86::EmitTyAddrXmm EmitAddrXmm = NULL) { |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ |
+ // Classify Src0 (Reg or Mem). |
+ bool Src0IsReg = false; |
+ x86::XmmRegister Src0Reg = x86::kNoXmmRegister; |
+ x86::Address Src0Addr = x86::Address::Absolute(0, NULL); |
+ if (const Variable *Src0Var = llvm::dyn_cast<Variable>(Src0)) { |
+ if (Src0Var->hasReg()) { |
+ Src0IsReg = true; |
+ Src0Reg = convertToAsmXMMReg(Src0Var->getRegNum()); |
+ } else { |
+ Src0Addr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(Src0Var); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src0)) { |
+ assert(EmitAddrXmm != NULL); |
+ Src0Addr = Mem->convertToAsmAddress(Asm); |
+ } |
+ |
+ if (const Variable *Src1Var = llvm::dyn_cast<Variable>(Src1)) { |
+ if (Src1Var->hasReg()) { |
+ x86::XmmRegister Src1Reg = convertToAsmXMMReg(Src1Var->getRegNum()); |
+ if (Src0IsReg) { |
+ (Asm->*EmitXmmXmm)(Ty, Src0Reg, Src1Reg); |
+ } else { |
+ (Asm->*EmitAddrXmm)(Ty, Src0Addr, Src1Reg); |
+ } |
+ } else { |
+ x86::Address Src1StackAddr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(Src1Var); |
+ assert(Src0IsReg); |
+ (Asm->*EmitXmmAddr)(Ty, Src0Reg, Src1StackAddr); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src1)) { |
+ x86::Address Src1Addr = Mem->convertToAsmAddress(Asm); |
+ assert(Src0IsReg); |
+ (Asm->*EmitXmmAddr)(Ty, Src0Reg, Src1Addr); |
+ } else if (const Constant *Imm = llvm::dyn_cast<Constant>(Src1)) { |
+ assert(Src0IsReg); |
+ (Asm->*EmitXmmAddr)(Ty, Src0Reg, |
+ convertFloatImmToAsmAddr(Func->getContext(), Asm, Imm)); |
+ } else { |
+ llvm_unreachable("Unexpected operand type"); |
+ } |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
+} // end of anonymous namespace |
+ |
void InstX8632::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "[X8632] "; |
Inst::dump(Func); |
} |
+void InstX8632::emitIAS(const Cfg *Func) const { emit(Func); } |
+ |
void InstX8632Label::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
Str << getName(Func) << ":\n"; |
@@ -355,6 +604,43 @@ void InstX8632Call::emit(const Cfg *Func) const { |
Func->getTarget()->resetStackAdjustment(); |
} |
+void InstX8632Call::emitIAS(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ Operand *Target = getCallTarget(); |
+ bool NeedsFallback = false; |
+ if (Variable *Var = llvm::dyn_cast<Variable>(Target)) { |
+ if (Var->hasReg()) { |
+ Asm->call(convertToAsmGPR(Var->getRegNum())); |
+ } else { |
+ Asm->call(static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(Var)); |
+ } |
+ } else if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Target)) { |
+ Asm->call(Mem->convertToAsmAddress(Asm)); |
+ } else if (ConstantRelocatable *CR = |
+ llvm::dyn_cast<ConstantRelocatable>(Target)) { |
+ assert(CR->getOffset() == 0 && "We only support calling a function"); |
+ Asm->call(CR); |
+ NeedsFallback = true; |
+ } |
+ if (NeedsFallback) { |
+ // TODO(jvoung): This .byte and .long hack doesn't work, since we need |
+ // a pc-rel relocation, and we also need the section contents to be |
+ // -4 instead of 0. |
+ // |
+ // Still, we have at least filled the assembler buffer so that the |
+ // instruction sizes/positions are correct for jumps. |
+ // |
+ // For now, fall back to the regular .s emission. |
+ emit(Func); |
+ } else { |
+ emitIASBytes(Str, Asm, StartPosition); |
+ } |
+ Func->getTarget()->resetStackAdjustment(); |
+} |
+ |
void InstX8632Call::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
if (getDest()) { |
@@ -478,6 +764,37 @@ template <> void InstX8632Sqrtss::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+template <> void InstX8632Sqrtss::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(getSrcSize() == 1); |
+ assert(Ty == IceType_f32 || Ty == IceType_f64); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(0), &x86::AssemblerX86::sqrtsd, |
+ &x86::AssemblerX86::sqrtsd); |
+ } else { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(0), &x86::AssemblerX86::sqrtss, |
+ &x86::AssemblerX86::sqrtss); |
+ } |
+} |
+ |
+template <> void InstX8632Adc::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::adc, |
+ &x86::AssemblerX86::adc, &x86::AssemblerX86::adc); |
+} |
+ |
+template <> void InstX8632Add::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::add, |
+ &x86::AssemblerX86::add, &x86::AssemblerX86::add); |
+} |
+ |
+template <> void InstX8632Addps::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::addps, |
+ &x86::AssemblerX86::addps); |
+} |
+ |
template <> void InstX8632Addss::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "add%s", |
@@ -485,6 +802,24 @@ template <> void InstX8632Addss::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Addss::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(getSrcSize() == 2); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::addsd, |
+ &x86::AssemblerX86::addsd); |
+ } else { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::addss, |
+ &x86::AssemblerX86::addss); |
+ } |
+} |
+ |
+template <> void InstX8632And::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::_and, |
+ &x86::AssemblerX86::_and, &x86::AssemblerX86::_and); |
+} |
+ |
template <> void InstX8632Padd::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "padd%s", |
@@ -492,6 +827,15 @@ template <> void InstX8632Padd::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Padd::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(isVectorType(Ty)); |
+ Type ElTy = typeElementType(Ty); |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandTyXMM(Func, ElTy, getDest(), getSrc(1), |
+ &x86::AssemblerX86::padd, &x86::AssemblerX86::padd); |
+} |
+ |
template <> void InstX8632Pmull::emit(const Cfg *Func) const { |
char buf[30]; |
bool TypesAreValid = getDest()->getType() == IceType_v4i32 || |
@@ -509,6 +853,24 @@ template <> void InstX8632Pmull::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Sbb::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::sbb, |
+ &x86::AssemblerX86::sbb, &x86::AssemblerX86::sbb); |
+} |
+ |
+template <> void InstX8632Sub::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::sub, |
+ &x86::AssemblerX86::sub, &x86::AssemblerX86::sub); |
+} |
+ |
+template <> void InstX8632Subps::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::subps, |
+ &x86::AssemblerX86::subps); |
+} |
+ |
template <> void InstX8632Subss::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "sub%s", |
@@ -516,6 +878,18 @@ template <> void InstX8632Subss::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Subss::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(getSrcSize() == 2); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::subsd, |
+ &x86::AssemblerX86::subsd); |
+ } else { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::subss, |
+ &x86::AssemblerX86::subss); |
+ } |
+} |
+ |
template <> void InstX8632Psub::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "psub%s", |
@@ -523,6 +897,21 @@ template <> void InstX8632Psub::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Psub::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(isVectorType(Ty)); |
+ Type ElTy = typeElementType(Ty); |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandTyXMM(Func, ElTy, getDest(), getSrc(1), |
+ &x86::AssemblerX86::psub, &x86::AssemblerX86::psub); |
+} |
+ |
+template <> void InstX8632Mulps::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::mulps, |
+ &x86::AssemblerX86::mulps); |
+} |
+ |
template <> void InstX8632Mulss::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "mul%s", |
@@ -530,12 +919,30 @@ template <> void InstX8632Mulss::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Mulss::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(getSrcSize() == 2); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::mulsd, |
+ &x86::AssemblerX86::mulsd); |
+ } else { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::mulss, |
+ &x86::AssemblerX86::mulss); |
+ } |
+} |
+ |
template <> void InstX8632Pmuludq::emit(const Cfg *Func) const { |
assert(getSrc(0)->getType() == IceType_v4i32 && |
getSrc(1)->getType() == IceType_v4i32); |
emitTwoAddress(Opcode, this, Func); |
} |
+template <> void InstX8632Divps::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::divps, |
+ &x86::AssemblerX86::divps); |
+} |
+ |
template <> void InstX8632Divss::emit(const Cfg *Func) const { |
char buf[30]; |
snprintf(buf, llvm::array_lengthof(buf), "div%s", |
@@ -543,6 +950,18 @@ template <> void InstX8632Divss::emit(const Cfg *Func) const { |
emitTwoAddress(buf, this, Func); |
} |
+template <> void InstX8632Divss::emitIAS(const Cfg *Func) const { |
+ Type Ty = getDest()->getType(); |
+ assert(getSrcSize() == 2); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::divsd, |
+ &x86::AssemblerX86::divsd); |
+ } else { |
+ emitIASVarOperandXMM(Func, getDest(), getSrc(1), &x86::AssemblerX86::divss, |
+ &x86::AssemblerX86::divss); |
+ } |
+} |
+ |
template <> void InstX8632Div::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 3); |
@@ -640,6 +1059,34 @@ template <> void InstX8632Cbwdq::emit(const Cfg *Func) const { |
} |
} |
+template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ assert(getSrcSize() == 1); |
+ Operand *Src0 = getSrc(0); |
+ assert(llvm::isa<Variable>(Src0)); |
+ assert(llvm::cast<Variable>(Src0)->getRegNum() == TargetX8632::Reg_eax); |
+ switch (Src0->getType()) { |
+ default: |
+ llvm_unreachable("unexpected source type!"); |
+ break; |
+ case IceType_i8: |
+ assert(getDest()->getRegNum() == TargetX8632::Reg_eax); |
+ Asm->cbw(); |
+ break; |
+ case IceType_i16: |
+ assert(getDest()->getRegNum() == TargetX8632::Reg_edx); |
+ Asm->cwd(); |
+ break; |
+ case IceType_i32: |
+ assert(getDest()->getRegNum() == TargetX8632::Reg_edx); |
+ Asm->cdq(); |
+ break; |
+ } |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
void InstX8632Mul::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 2); |
@@ -723,6 +1170,23 @@ void InstX8632Cmov::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+void InstX8632Cmov::emitIAS(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(Condition != Br_None); |
+ assert(getDest()->hasReg()); |
+ assert(getSrcSize() == 2); |
+ const Variable *Src = llvm::cast<Variable>(getSrc(1)); |
+ // Only need the 32-bit register form right now. |
+ assert(Src->hasReg()); |
+ assert(Src->getType() == IceType_i32); |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ Asm->cmov(convertToAsmCondition(Condition), |
+ convertToAsmGPR(getDest()->getRegNum()), |
+ convertToAsmGPR(Src->getRegNum())); |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
void InstX8632Cmov::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "cmov" << InstX8632BrAttributes[Condition].DisplayString << "."; |
@@ -745,6 +1209,28 @@ void InstX8632Cmpps::emit(const Cfg *Func) const { |
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 < 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(convertToAsmXMMReg(getDest()->getRegNum()), |
+ convertToAsmXMMReg(SrcVar->getRegNum()), Condition); |
+ } else { |
+ x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(SrcVar); |
+ Asm->cmpps(convertToAsmXMMReg(getDest()->getRegNum()), SrcStackAddr, |
+ Condition); |
+ } |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
void InstX8632Cmpps::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
assert(Condition < Cmpps_Invalid); |
@@ -831,6 +1317,13 @@ void InstX8632Icmp::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+void InstX8632Icmp::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getSrc(0), getSrc(1), &x86::AssemblerX86::cmp, |
+ &x86::AssemblerX86::cmp, &x86::AssemblerX86::cmp, |
+ &x86::AssemblerX86::cmp, &x86::AssemblerX86::cmp); |
+} |
+ |
void InstX8632Icmp::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "cmp." << getSrc(0)->getType() << " "; |
@@ -848,6 +1341,22 @@ void InstX8632Ucomiss::emit(const Cfg *Func) const { |
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(); |
+ if (Ty == IceType_f64) { |
+ emitIASVarOperandXMM(Func, Src0, getSrc(1), &x86::AssemblerX86::ucomisd, |
+ &x86::AssemblerX86::ucomisd); |
+ } else { |
+ emitIASVarOperandXMM(Func, Src0, getSrc(1), &x86::AssemblerX86::ucomiss, |
+ &x86::AssemblerX86::ucomiss); |
+ } |
+} |
+ |
void InstX8632Ucomiss::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "ucomiss." << getSrc(0)->getType() << " "; |
@@ -1018,6 +1527,11 @@ template <> void InstX8632Mov::emit(const Cfg *Func) const { |
} |
} |
+template <> void InstX8632Mov::emitIAS(const Cfg *Func) const { |
+ // Could be movss/sd, or movb/movw/movl. |
+ emit(Func); |
+} |
+ |
template <> void InstX8632Movp::emit(const Cfg *Func) const { |
// TODO(wala,stichnot): movups works with all vector operands, but |
// there exist other instructions (movaps, movdqa, movdqu) that may |
@@ -1044,6 +1558,42 @@ template <> void InstX8632Movq::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+static void emitIASSignZeroExt(const Cfg *Func, const Variable *Dest, |
+ const Operand *Src0, |
+ x86::AssemblerX86::EmitRegByteR EmitByte, |
+ x86::AssemblerX86::EmitRegReg EmitWord, |
+ x86::AssemblerX86::EmitRegAddr EmitAddress) { |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(Dest->hasReg()); |
+ x86::Register DestReg = convertToAsmGPR(Dest->getRegNum()); |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ Type SrcType = Src0->getType(); |
+ // Source is ByteReg, WordReg, or stack slot, or other memory operand. |
+ if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src0)) { |
+ if (SrcVar->hasReg()) { |
+ if (SrcType == IceType_i8 || SrcType == IceType_i1) { |
+ (Asm->*EmitByte)(DestReg, |
+ convertToAsmByteRegister(SrcVar->getRegNum())); |
+ } else { |
+ assert(SrcType == IceType_i16); |
+ (Asm->*EmitWord)(DestReg, convertToAsmGPR(SrcVar->getRegNum())); |
+ } |
+ } else { |
+ x86::Address StackAddr = static_cast<TargetX8632 *>(Func->getTarget()) |
+ ->stackVarToAsmOperand(SrcVar); |
+ (Asm->*EmitAddress)(DestReg, StackAddr); |
+ } |
+ } else if (const OperandX8632Mem *Mem = |
+ llvm::dyn_cast<OperandX8632Mem>(Src0)) { |
+ x86::Address SrcAddr = Mem->convertToAsmAddress(Asm); |
+ (Asm->*EmitAddress)(DestReg, SrcAddr); |
+ } else { |
+ llvm_unreachable("Unexpected operand type for Movzx"); |
+ } |
+ emitIASBytes(Str, Asm, StartPosition); |
+} |
+ |
void InstX8632Movsx::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 1); |
@@ -1054,6 +1604,20 @@ void InstX8632Movsx::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+void InstX8632Movsx::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 1); |
+ const Operand *Src0 = getSrc(0); |
+ Type SrcType = Src0->getType(); |
+ if (SrcType == IceType_i8 || SrcType == IceType_i1) { |
+ emitIASSignZeroExt(Func, getDest(), Src0, &x86::AssemblerX86::movsxb, |
+ &x86::AssemblerX86::movsxw, &x86::AssemblerX86::movsxb); |
+ } else { |
+ assert(SrcType == IceType_i16); |
+ emitIASSignZeroExt(Func, getDest(), Src0, &x86::AssemblerX86::movsxb, |
+ &x86::AssemblerX86::movsxw, &x86::AssemblerX86::movsxw); |
+ } |
+} |
+ |
void InstX8632Movsx::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "movsx." << getDest()->getType() << "." << getSrc(0)->getType(); |
@@ -1073,6 +1637,20 @@ void InstX8632Movzx::emit(const Cfg *Func) const { |
Str << "\n"; |
} |
+void InstX8632Movzx::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 1); |
+ const Operand *Src0 = getSrc(0); |
+ Type SrcType = Src0->getType(); |
+ if (SrcType == IceType_i8 || SrcType == IceType_i1) { |
+ emitIASSignZeroExt(Func, getDest(), Src0, &x86::AssemblerX86::movzxb, |
+ &x86::AssemblerX86::movzxw, &x86::AssemblerX86::movzxb); |
+ } else { |
+ assert(SrcType == IceType_i16); |
+ emitIASSignZeroExt(Func, getDest(), Src0, &x86::AssemblerX86::movzxb, |
+ &x86::AssemblerX86::movzxw, &x86::AssemblerX86::movzxw); |
+ } |
+} |
+ |
void InstX8632Movzx::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "movzx." << getDest()->getType() << "." << getSrc(0)->getType(); |
@@ -1088,11 +1666,26 @@ void InstX8632Nop::emit(const Cfg *Func) const { |
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 << ")"; |
} |
+template <> void InstX8632Or::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::_or, |
+ &x86::AssemblerX86::_or, &x86::AssemblerX86::_or); |
+} |
+ |
void InstX8632Fld::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 1); |
@@ -1222,11 +1815,27 @@ template <> void InstX8632Pinsr::emit(const Cfg *Func) const { |
void InstX8632Pop::emit(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 0); |
+ assert(getDest()->getType() == IceType_i32); |
Str << "\tpop\t"; |
getDest()->emit(Func); |
Str << "\n"; |
} |
+void InstX8632Pop::emitIAS(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 0); |
+ assert(getDest()->getType() == IceType_i32); |
+ x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
+ intptr_t StartPosition = Asm->GetPosition(); |
+ if (getDest()->hasReg()) { |
+ Asm->popl(convertToAsmGPR(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); |
@@ -1239,6 +1848,16 @@ void InstX8632AdjustStack::emit(const Cfg *Func) const { |
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->sub(IceType_i32, convertToAsmGPR(TargetX8632::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; |
@@ -1311,6 +1930,14 @@ void InstX8632Ret::emit(const Cfg *Func) const { |
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()); |
@@ -1356,6 +1983,12 @@ void InstX8632Xchg::dump(const Cfg *Func) const { |
dumpSources(Func); |
} |
+template <> void InstX8632Xor::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ emitIASTwoOperandGPR(Func, getDest(), getSrc(1), &x86::AssemblerX86::_xor, |
+ &x86::AssemblerX86::_xor, &x86::AssemblerX86::_xor); |
+} |
+ |
void OperandX8632::dump(const Cfg *Func) const { |
Ostream &Str = Func->getContext()->getStrDump(); |
Str << "<OperandX8632>"; |
@@ -1388,9 +2021,12 @@ void OperandX8632Mem::emit(const Cfg *Func) const { |
bool OffsetIsNegative = false; |
if (Offset == NULL) { |
OffsetIsZero = true; |
- } else if (ConstantInteger *CI = llvm::dyn_cast<ConstantInteger>(Offset)) { |
+ } else if (ConstantInteger32 *CI = |
+ llvm::dyn_cast<ConstantInteger32>(Offset)) { |
OffsetIsZero = (CI->getValue() == 0); |
- OffsetIsNegative = (static_cast<int64_t>(CI->getValue()) < 0); |
+ OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0); |
+ } else if (llvm::isa<ConstantInteger64>(Offset)) { |
+ llvm_unreachable("Unexpected offset type (64-bit)"); |
} |
if (Dumped) { |
if (!OffsetIsZero) { // Suppress if Offset is known to be 0 |
@@ -1430,9 +2066,12 @@ void OperandX8632Mem::dump(const Cfg *Func) const { |
bool OffsetIsNegative = false; |
if (Offset == NULL) { |
OffsetIsZero = true; |
- } else if (ConstantInteger *CI = llvm::dyn_cast<ConstantInteger>(Offset)) { |
+ } else if (ConstantInteger32 *CI = |
+ llvm::dyn_cast<ConstantInteger32>(Offset)) { |
OffsetIsZero = (CI->getValue() == 0); |
- OffsetIsNegative = (static_cast<int64_t>(CI->getValue()) < 0); |
+ OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0); |
+ } else if (llvm::isa<ConstantInteger64>(Offset)) { |
+ llvm_unreachable("Unexpected offset type (64-bit)"); |
} |
if (Dumped) { |
if (!OffsetIsZero) { // Suppress if Offset is known to be 0 |
@@ -1447,6 +2086,41 @@ void OperandX8632Mem::dump(const Cfg *Func) const { |
Str << "]"; |
} |
+x86::Address OperandX8632Mem::convertToAsmAddress(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(convertToAsmGPR(getBase()->getRegNum()), |
+ convertToAsmGPR(getIndex()->getRegNum()), |
+ x86::ScaleFactor(getShift()), Disp); |
+ } else if (getBase()) { |
+ return x86::Address(convertToAsmGPR(getBase()->getRegNum()), Disp); |
+ } else if (getIndex()) { |
+ return x86::Address(convertToAsmGPR(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->getLocalUseNode() == NULL || |