Chromium Code Reviews| Index: src/IceInstX8632.cpp |
| diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp |
| index 373ab59e47503c4b3535edaaf87bc17a4aa015f5..fdd14fa579879bee919f5c56443e5eeeb25f93b4 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,51 @@ 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 ConstantInteger *CI) { |
| + int32_t V = static_cast<int32_t>(CI->getValue()); |
| + // Check that it's really 32-bit. |
| + // Sometimes Subzero stores negative values as sign-extended 64-bit |
| + // and sometimes it's zero-extended to 64-bit. |
| + // Should we just make a ConstantInteger32? |
|
Jim Stichnoth
2014/09/09 14:58:41
I was also thinking that maybe constant integers n
jvoung (off chromium)
2014/09/15 17:19:15
Hmm, we could add signed/unsigned, but I'm not yet
|
| + assert((CI->getValue() >> 32) == 0 || (CI->getValue() >> 32) == 0xffffffff); |
| + 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. |
| +// Modifies SymbolicOffset to contain the symbol. |
| +x86::Address convertFloatImmToAsmAddr(const Constant *Imm, |
| + IceString &SymbolicOffset) { |
| + 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(); |
| + SymbolicOffset = StrBuf.str(); |
| + return x86::Address::Absolute(0); |
| +} |
| + |
| } // end of anonymous namespace |
| const char *InstX8632::getWidthString(Type Ty) { |
| @@ -285,12 +331,207 @@ InstX8632Xchg::InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source) |
| // ======================== Dump routines ======================== // |
| +namespace { |
| + |
| +void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm, |
| + intptr_t StartPosition, |
| + const IceString &SymbolicOffset = IceString("")) { |
| + intptr_t EndPosition = Asm->GetPosition(); |
| + if (!SymbolicOffset.empty()) { |
| + const intptr_t OffsetSize = 4; |
| + EndPosition -= OffsetSize; |
| + } |
| + for (intptr_t i = 0; i < EndPosition - StartPosition; ++i) { |
| + Str << "\t.byte " |
| + << static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(StartPosition + i)) |
| + << "\n"; |
| + } |
| + if (!SymbolicOffset.empty()) { |
| + int32_t Disp = Asm->LoadBuffer<int32_t>(EndPosition); |
| + if (Disp) |
| + Str << "\t.long " << SymbolicOffset << " + " << Disp << "\n"; |
| + else |
| + Str << "\t.long " << SymbolicOffset << "\n"; |
| + } |
| +} |
| + |
| +void emitIASVarOperandInt(const Cfg *Func, const Variable *Var, |
| + const Operand *Src, |
| + x86::AssemblerX86::EmitTyRegReg EmitRegReg, |
| + x86::AssemblerX86::EmitTyRegAddr EmitRegAddr, |
| + x86::AssemblerX86::EmitTyRegImm EmitRegImm) { |
| + // For now, we assume Var is reg, since most of the time we use: |
| + // _add(T, foo) |
| + // _mov(Var, T) |
| + // where T is a register. |
| + // |
| + // Otherwise, if Var can be mem, use the emitIASTwoOperandInt function.. |
| + x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
| + intptr_t StartPosition = Asm->GetPosition(); |
| + IceString SymbolicOffset = ""; |
| + Type Ty = Var->getType(); |
| + // Classify Var. |
| + x86::Register VarReg; |
| + assert(Var->hasReg()); |
| + if (typeWidthInBytes(Ty) == 1) { |
| + // We fudge a bit, and use Register for ByteRegister. |
| + // This avoids having to add another assembler method, |
| + // just for ByteRegisters. The register encoding is the same. |
| + VarReg = convertToAsmGPR(convertToAsmByteRegister(Var->getRegNum())); |
| + } else { |
| + VarReg = convertToAsmGPR(Var->getRegNum()); |
| + } |
| + |
| + // Classify Src. |
| + if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + x86::Register SrcReg; |
| + if (typeWidthInBytes(Ty) == 1) { |
| + SrcReg = convertToAsmGPR(convertToAsmByteRegister(SrcVar->getRegNum())); |
| + } else { |
| + SrcReg = convertToAsmGPR(SrcVar->getRegNum()); |
| + } |
| + (Asm->*EmitRegReg)(Ty, VarReg, SrcReg); |
| + } else { |
| + x86::Address SrcAddr = static_cast<TargetX8632 *>(Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*EmitRegAddr)(Ty, VarReg, SrcAddr); |
| + } |
| + } else if (const OperandX8632Mem *Mem = |
| + llvm::dyn_cast<OperandX8632Mem>(Src)) { |
| + x86::Address SrcAddr = Mem->convertToAsmAddress(SymbolicOffset); |
| + (Asm->*EmitRegAddr)(Ty, VarReg, SrcAddr); |
| + } else if (const ConstantInteger *CI = llvm::dyn_cast<ConstantInteger>(Src)) { |
| + x86::Immediate Imm = convertIntImmToAsmImm(CI); |
| + (Asm->*EmitRegImm)(Ty, VarReg, Imm); |
| + } |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + emitIASBytes(Str, Asm, StartPosition, SymbolicOffset); |
| +} |
| + |
| +void emitIASTwoOperandInt(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, |
| + x86::AssemblerX86::EmitTyAddrImm EmitAddrImm) { |
| + x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); |
| + intptr_t StartPosition = Asm->GetPosition(); |
| + IceString SymbolicOffset = ""; |
| + Type Ty = Src0->getType(); |
| + |
| + // Classify Src0 (Reg or Mem). |
| + // Could use a lambda/functional to curry the first parameter. |
| + bool Src0IsReg = false; |
| + x86::Register Src0Reg = x86::kNoRegister; |
| + x86::Address Src0Addr = x86::Address::Absolute(0); |
| + 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)) { |
| + Src0Addr = Mem->convertToAsmAddress(SymbolicOffset); |
| + } |
| + |
| + // 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(SymbolicOffset); |
| + assert(Src0IsReg); |
| + (Asm->*EmitRegAddr)(Ty, Src0Reg, Src1Addr); |
| + } else if (const ConstantInteger *CI = |
| + llvm::dyn_cast<ConstantInteger>(Src1)) { |
| + x86::Immediate Imm = convertIntImmToAsmImm(CI); |
| + if (Src0IsReg) |
| + (Asm->*EmitRegImm)(Ty, Src0Reg, Imm); |
| + else |
| + (Asm->*EmitAddrImm)(Ty, Src0Addr, Imm); |
| + // TODO(jvoung): Record the buffer position containing the relocation, |
| + // instead of just assuming it's the last 4 bytes. That would not be |
| + // true if Src0 is Memory w/ a symbolic displacement, and Src1 |
| + // is an immediate. The immediate would take up the last few bytes |
| + // and the memory operand's displacement would come before those imm bytes. |
| + // |
| + // Perhaps the "Address" Operand type could indicate that it's a |
| + // relocatable, and then the emitOperand() methods will check |
| + // and create Fixups inline while the buffer is in the correct position. |
| + assert(SymbolicOffset.empty()); |
| + } |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + emitIASBytes(Str, Asm, StartPosition, SymbolicOffset); |
| +} |
| + |
| +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()); |
| + IceString SymbolicOffset = ""; |
| + 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(SymbolicOffset); |
| + (Asm->*EmitXmmAddr)(VarReg, SrcAddr); |
| + } else if (const Constant *Imm = llvm::dyn_cast<Constant>(Src)) { |
| + (Asm->*EmitXmmAddr)(VarReg, convertFloatImmToAsmAddr(Imm, SymbolicOffset)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + emitIASBytes(Str, Asm, StartPosition, SymbolicOffset); |
| +} |
| + |
| +} // 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 +596,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(); |
| + IceString SymbolicOffset = ""; |
| + 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(SymbolicOffset)); |
| + } else if (ConstantRelocatable *CR = |
| + llvm::dyn_cast<ConstantRelocatable>(Target)) { |
| + assert(CR->getOffset() == 0 && "We only support calling a function"); |
| + SymbolicOffset = CR->getName(); |
| + Asm->call(CR); |
| + } |
| + if (!SymbolicOffset.empty()) { |
| + // 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, SymbolicOffset); |
| + } |
| + Func->getTarget()->resetStackAdjustment(); |
| +} |
| + |
| void InstX8632Call::dump(const Cfg *Func) const { |
| Ostream &Str = Func->getContext()->getStrDump(); |
| if (getDest()) { |
| @@ -478,6 +756,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); |
| + emitIASVarOperandInt(Func, getDest(), getSrc(1), &x86::AssemblerX86::adc, |
| + &x86::AssemblerX86::adc, &x86::AssemblerX86::adc); |
| +} |
| + |
| +template <> void InstX8632Add::emitIAS(const Cfg *Func) const { |
| + assert(getSrcSize() == 2); |
| + emitIASVarOperandInt(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 +794,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); |
| + emitIASVarOperandInt(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", |
| @@ -509,6 +836,24 @@ template <> void InstX8632Pmull::emit(const Cfg *Func) const { |
| emitTwoAddress(buf, this, Func); |
| } |
| +template <> void InstX8632Sbb::emitIAS(const Cfg *Func) const { |
| + assert(getSrcSize() == 2); |
| + emitIASVarOperandInt(Func, getDest(), getSrc(1), &x86::AssemblerX86::sbb, |
| + &x86::AssemblerX86::sbb, &x86::AssemblerX86::sbb); |
| +} |
| + |
| +template <> void InstX8632Sub::emitIAS(const Cfg *Func) const { |
| + assert(getSrcSize() == 2); |
| + emitIASVarOperandInt(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 +861,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 +880,12 @@ template <> void InstX8632Psub::emit(const Cfg *Func) const { |
| emitTwoAddress(buf, this, Func); |
| } |
| +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 +893,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 +924,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 +1033,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 +1144,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 +1183,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 +1291,13 @@ void InstX8632Icmp::emit(const Cfg *Func) const { |
| Str << "\n"; |
| } |
| +void InstX8632Icmp::emitIAS(const Cfg *Func) const { |
| + assert(getSrcSize() == 2); |
| + emitIASTwoOperandInt(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 +1315,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 +1501,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 +1532,43 @@ 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(); |
| + IceString SymbolicOffset = ""; |
| + 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(SymbolicOffset); |
| + (Asm->*EmitAddress)(DestReg, SrcAddr); |
| + } else { |
| + llvm_unreachable("Unexpected operand type for Movzx"); |
| + } |
| + emitIASBytes(Str, Asm, StartPosition, SymbolicOffset); |
| +} |
| + |
| void InstX8632Movsx::emit(const Cfg *Func) const { |
| Ostream &Str = Func->getContext()->getStrEmit(); |
| assert(getSrcSize() == 1); |
| @@ -1054,6 +1579,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 +1612,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 +1641,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); |
| + emitIASVarOperandInt(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 +1790,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); |
| @@ -1311,6 +1895,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 +1948,12 @@ void InstX8632Xchg::dump(const Cfg *Func) const { |
| dumpSources(Func); |
| } |
| +template <> void InstX8632Xor::emitIAS(const Cfg *Func) const { |
| + assert(getSrcSize() == 2); |
| + emitIASVarOperandInt(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>"; |
| @@ -1447,6 +2045,49 @@ void OperandX8632Mem::dump(const Cfg *Func) const { |
| Str << "]"; |
| } |
| +x86::Address |
| +OperandX8632Mem::convertToAsmAddress(IceString &SymbolicOffset) const { |
| + int32_t Disp = 0; |
| + // Determine the offset (is it relocatable?) |
| + if (getOffset()) { |
| + if (ConstantInteger *CI = llvm::dyn_cast<ConstantInteger>(getOffset())) { |
| + Disp = static_cast<int32_t>(CI->getValue()); |
| + // Check that it's really 32-bit. |
| + // Sometimes Subzero stores negative values as sign-extended 64-bit |
| + // and sometimes it's zero-extended to 64-bit. |
| + // Should we just make a ConstantInteger32? |
| + assert((CI->getValue() >> 32) == 0 || |
| + (CI->getValue() >> 32) == 0xffffffff); |
| + } else if (ConstantRelocatable *CR = |
| + llvm::dyn_cast<ConstantRelocatable>(getOffset())) { |
| + SymbolicOffset = CR->getName(); |
| + // TODO(jvoung): this isn't really tested yet, since none of the |
| + // arithmetic, etc. ops have the addressing mode optimization |
| + // for ConstantRelocatable. |
| + assert(CR->getOffset() == 0); |
| + // Check that the int64_t only really has 32-bits. |
| + // Should we just the displacement 32-bit? |
| + assert((CR->getOffset() >> 32) == 0 || |
| + (CR->getOffset() >> 32) == 0xffffffff); |
| + Disp = CR->getOffset(); |
| + } |
| + } |
| + |
| + // 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); |
| + } |
| +} |
| + |
| void VariableSplit::emit(const Cfg *Func) const { |
| Ostream &Str = Func->getContext()->getStrEmit(); |
| assert(Var->getLocalUseNode() == NULL || |