HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
external
swiftshader
third_party
subzero
src
IceInstX86BaseImpl.h
//===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// // // The Subzero Code Generator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Implements the InstX86Base class and its descendants. /// //===----------------------------------------------------------------------===// #ifndef SUBZERO_SRC_ICEINSTX86BASEIMPL_H #define SUBZERO_SRC_ICEINSTX86BASEIMPL_H #include "IceInstX86Base.h" #include "IceAssemblerX86Base.h" #include "IceCfg.h" #include "IceCfgNode.h" #include "IceDefs.h" #include "IceInst.h" #include "IceOperand.h" #include "IceTargetLowering.h" #include "IceTargetLoweringX86Base.h" namespace Ice { namespace X86NAMESPACE { template
const char *InstImpl
::InstX86Base::getWidthString(Type Ty) { return Traits::TypeAttributes[Ty].WidthString; } template
const char *InstImpl
::InstX86Base::getFldString(Type Ty) { return Traits::TypeAttributes[Ty].FldString; } template
typename InstImpl
::Cond::BrCond InstImpl
::InstX86Base::getOppositeCondition(BrCond Cond) { return Traits::InstBrAttributes[Cond].Opposite; } template
InstImpl
::InstX86FakeRMW::InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr, InstArithmetic::OpKind Op, Variable *Beacon) : InstX86Base(Func, InstX86Base::FakeRMW, 3, nullptr), Op(Op) { this->addSource(Data); this->addSource(Addr); this->addSource(Beacon); } template
InstImpl
::InstX86GetIP::InstX86GetIP(Cfg *Func, Variable *Dest) : InstX86Base(Func, InstX86Base::GetIP, 0, Dest) {} template
InstImpl
::InstX86Mul::InstX86Mul(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2) : InstX86Base(Func, InstX86Base::Mul, 2, Dest) { this->addSource(Source1); this->addSource(Source2); } template
InstImpl
::InstX86Shld::InstX86Shld(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2) : InstX86Base(Func, InstX86Base::Shld, 3, Dest) { this->addSource(Dest); this->addSource(Source1); this->addSource(Source2); } template
InstImpl
::InstX86Shrd::InstX86Shrd(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2) : InstX86Base(Func, InstX86Base::Shrd, 3, Dest) { this->addSource(Dest); this->addSource(Source1); this->addSource(Source2); } template
InstImpl
::InstX86Label::InstX86Label(Cfg *Func, TargetLowering *Target) : InstX86Base(Func, InstX86Base::Label, 0, nullptr), LabelNumber(Target->makeNextLabelNumber()) { if (BuildDefs::dump()) { Name = GlobalString::createWithString( Func->getContext(), ".L" + Func->getFunctionName() + "$local$__" + std::to_string(LabelNumber)); } else { Name = GlobalString::createWithoutString(Func->getContext()); } } template
InstImpl
::InstX86Br::InstX86Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, const InstX86Label *Label, BrCond Condition, Mode Kind) : InstX86Base(Func, InstX86Base::Br, 0, nullptr), Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label), Kind(Kind) {} template
bool InstImpl
::InstX86Br::optimizeBranch(const CfgNode *NextNode) { // If there is no next block, then there can be no fallthrough to optimize. if (NextNode == nullptr) return false; // Intra-block conditional branches can't be optimized. if (Label) return false; // If there is no fallthrough node, such as a non-default case label for a // switch instruction, then there is no opportunity to optimize. if (getTargetFalse() == nullptr) return false; // Unconditional branch to the next node can be removed. if (Condition == Cond::Br_None && getTargetFalse() == NextNode) { assert(getTargetTrue() == nullptr); this->setDeleted(); return true; } // If the fallthrough is to the next node, set fallthrough to nullptr to // indicate. if (getTargetFalse() == NextNode) { TargetFalse = nullptr; return true; } // If TargetTrue is the next node, and TargetFalse is not nullptr (which was // already tested above), then invert the branch condition, swap the targets, // and set new fallthrough to nullptr. if (getTargetTrue() == NextNode) { assert(Condition != Cond::Br_None); Condition = this->getOppositeCondition(Condition); TargetTrue = getTargetFalse(); TargetFalse = nullptr; return true; } return false; } template
bool InstImpl
::InstX86Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { bool Found = false; if (TargetFalse == OldNode) { TargetFalse = NewNode; Found = true; } if (TargetTrue == OldNode) { TargetTrue = NewNode; Found = true; } return Found; } template
InstImpl
::InstX86Jmp::InstX86Jmp(Cfg *Func, Operand *Target) : InstX86Base(Func, InstX86Base::Jmp, 1, nullptr) { this->addSource(Target); } template
InstImpl
::InstX86Call::InstX86Call(Cfg *Func, Variable *Dest, Operand *CallTarget) : InstX86Base(Func, InstX86Base::Call, 1, Dest) { this->HasSideEffects = true; this->addSource(CallTarget); } template
InstImpl
::InstX86Movmsk::InstX86Movmsk(Cfg *Func, Variable *Dest, Operand *Source) : InstX86Base(Func, InstX86Base::Movmsk, 1, Dest) { this->addSource(Source); } template
InstImpl
::InstX86Cmov::InstX86Cmov(Cfg *Func, Variable *Dest, Operand *Source, BrCond Condition) : InstX86Base(Func, InstX86Base::Cmov, 2, Dest), Condition(Condition) { // The final result is either the original Dest, or Source, so mark both as // sources. this->addSource(Dest); this->addSource(Source); } template
InstImpl
::InstX86Cmpps::InstX86Cmpps(Cfg *Func, Variable *Dest, Operand *Source, CmppsCond Condition) : InstX86Base(Func, InstX86Base::Cmpps, 2, Dest), Condition(Condition) { this->addSource(Dest); this->addSource(Source); } template
InstImpl
::InstX86Cmpxchg::InstX86Cmpxchg(Cfg *Func, Operand *DestOrAddr, Variable *Eax, Variable *Desired, bool Locked) : InstImpl
::InstX86BaseLockable( Func, InstX86Base::Cmpxchg, 3, llvm::dyn_cast
(DestOrAddr), Locked) { constexpr uint16_t Encoded_rAX = 0; (void)Encoded_rAX; assert(Traits::getEncodedGPR(Eax->getRegNum()) == Encoded_rAX); this->addSource(DestOrAddr); this->addSource(Eax); this->addSource(Desired); } template
InstImpl
::InstX86Cmpxchg8b::InstX86Cmpxchg8b( Cfg *Func, X86OperandMem *Addr, Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked) : InstImpl
::InstX86BaseLockable(Func, InstX86Base::Cmpxchg, 5, nullptr, Locked) { assert(Edx->getRegNum() == RegisterSet::Reg_edx); assert(Eax->getRegNum() == RegisterSet::Reg_eax); assert(Ecx->getRegNum() == RegisterSet::Reg_ecx); assert(Ebx->getRegNum() == RegisterSet::Reg_ebx); this->addSource(Addr); this->addSource(Edx); this->addSource(Eax); this->addSource(Ecx); this->addSource(Ebx); } template
InstImpl
::InstX86Cvt::InstX86Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant) : InstX86Base(Func, InstX86Base::Cvt, 1, Dest), Variant(Variant) { this->addSource(Source); } template
InstImpl
::InstX86Icmp::InstX86Icmp(Cfg *Func, Operand *Src0, Operand *Src1) : InstX86Base(Func, InstX86Base::Icmp, 2, nullptr) { this->addSource(Src0); this->addSource(Src1); } template
InstImpl
::InstX86Ucomiss::InstX86Ucomiss(Cfg *Func, Operand *Src0, Operand *Src1) : InstX86Base(Func, InstX86Base::Ucomiss, 2, nullptr) { this->addSource(Src0); this->addSource(Src1); } template
InstImpl
::InstX86UD2::InstX86UD2(Cfg *Func) : InstX86Base(Func, InstX86Base::UD2, 0, nullptr) {} template
InstImpl
::InstX86Int3::InstX86Int3(Cfg *Func) : InstX86Base(Func, InstX86Base::Int3, 0, nullptr) {} template
InstImpl
::InstX86Test::InstX86Test(Cfg *Func, Operand *Src1, Operand *Src2) : InstX86Base(Func, InstX86Base::Test, 2, nullptr) { this->addSource(Src1); this->addSource(Src2); } template
InstImpl
::InstX86Mfence::InstX86Mfence(Cfg *Func) : InstX86Base(Func, InstX86Base::Mfence, 0, nullptr) { this->HasSideEffects = true; } template
InstImpl
::InstX86Store::InstX86Store(Cfg *Func, Operand *Value, X86Operand *Mem) : InstX86Base(Func, InstX86Base::Store, 2, nullptr) { this->addSource(Value); this->addSource(Mem); } template
InstImpl
::InstX86StoreP::InstX86StoreP(Cfg *Func, Variable *Value, X86OperandMem *Mem) : InstX86Base(Func, InstX86Base::StoreP, 2, nullptr) { this->addSource(Value); this->addSource(Mem); } template
InstImpl
::InstX86StoreQ::InstX86StoreQ(Cfg *Func, Operand *Value, X86OperandMem *Mem) : InstX86Base(Func, InstX86Base::StoreQ, 2, nullptr) { this->addSource(Value); this->addSource(Mem); } template
InstImpl
::InstX86StoreD::InstX86StoreD(Cfg *Func, Operand *Value, X86OperandMem *Mem) : InstX86Base(Func, InstX86Base::StoreD, 2, nullptr) { this->addSource(Value); this->addSource(Mem); } template
InstImpl
::InstX86Nop::InstX86Nop(Cfg *Func, NopVariant Variant) : InstX86Base(Func, InstX86Base::Nop, 0, nullptr), Variant(Variant) {} template
InstImpl
::InstX86Fld::InstX86Fld(Cfg *Func, Operand *Src) : InstX86Base(Func, InstX86Base::Fld, 1, nullptr) { this->addSource(Src); } template
InstImpl
::InstX86Fstp::InstX86Fstp(Cfg *Func, Variable *Dest) : InstX86Base(Func, InstX86Base::Fstp, 0, Dest) {} template
InstImpl
::InstX86Pop::InstX86Pop(Cfg *Func, Variable *Dest) : InstX86Base(Func, InstX86Base::Pop, 0, Dest) { // A pop instruction affects the stack pointer and so it should not be // allowed to be automatically dead-code eliminated. (The corresponding push // instruction doesn't need this treatment because it has no dest variable // and therefore won't be dead-code eliminated.) This is needed for // late-stage liveness analysis (e.g. asm-verbose mode). this->HasSideEffects = true; } template
InstImpl
::InstX86Push::InstX86Push(Cfg *Func, Operand *Source) : InstX86Base(Func, InstX86Base::Push, 1, nullptr) { this->addSource(Source); } template
InstImpl
::InstX86Push::InstX86Push(Cfg *Func, InstX86Label *L) : InstX86Base(Func, InstX86Base::Push, 0, nullptr), Label(L) {} template
InstImpl
::InstX86Ret::InstX86Ret(Cfg *Func, Variable *Source) : InstX86Base(Func, InstX86Base::Ret, Source ? 1 : 0, nullptr) { if (Source) this->addSource(Source); } template
InstImpl
::InstX86Setcc::InstX86Setcc(Cfg *Func, Variable *Dest, BrCond Cond) : InstX86Base(Func, InstX86Base::Setcc, 0, Dest), Condition(Cond) {} template
InstImpl
::InstX86Xadd::InstX86Xadd(Cfg *Func, Operand *Dest, Variable *Source, bool Locked) : InstImpl
::InstX86BaseLockable( Func, InstX86Base::Xadd, 2, llvm::dyn_cast
(Dest), Locked) { this->addSource(Dest); this->addSource(Source); } template
InstImpl
::InstX86Xchg::InstX86Xchg(Cfg *Func, Operand *Dest, Variable *Source) : InstX86Base(Func, InstX86Base::Xchg, 2, llvm::dyn_cast
(Dest)) { this->addSource(Dest); this->addSource(Source); } template
InstImpl
::InstX86IacaStart::InstX86IacaStart(Cfg *Func) : InstX86Base(Func, InstX86Base::IacaStart, 0, nullptr) { assert(getFlags().getAllowIacaMarks()); } template
InstImpl
::InstX86IacaEnd::InstX86IacaEnd(Cfg *Func) : InstX86Base(Func, InstX86Base::IacaEnd, 0, nullptr) { assert(getFlags().getAllowIacaMarks()); } // ======================== Dump routines ======================== // template
void InstImpl
::InstX86Base::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); Str << "[" << Traits::TargetName << "] "; Inst::dump(Func); } template
void InstImpl
::InstX86FakeRMW::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); Type Ty = getData()->getType(); Str << "rmw " << InstArithmetic::getOpName(getOp()) << " " << Ty << " *"; getAddr()->dump(Func); Str << ", "; getData()->dump(Func); Str << ", beacon="; getBeacon()->dump(Func); } template
void InstImpl
::InstX86GetIP::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; const auto *Dest = this->getDest(); assert(Dest->hasReg()); Ostream &Str = Func->getContext()->getStrEmit(); Str << "\t" "call" "\t"; auto *Target = static_cast
(Func->getTarget()); Target->emitWithoutPrefix(Target->createGetIPForRegister(Dest)); } template
void InstImpl
::InstX86GetIP::emitIAS(const Cfg *Func) const { const auto *Dest = this->getDest(); Assembler *Asm = Func->getAssembler
(); assert(Dest->hasReg()); Asm->call(static_cast
(Func->getTarget()) ->createGetIPForRegister(Dest)); } template
void InstImpl
::InstX86GetIP::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); this->getDest()->dump(Func); Str << " = call getIP"; } template
void InstImpl
::InstX86Label::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << getLabelName() << ":"; } template
void InstImpl
::InstX86Label::emitIAS(const Cfg *Func) const { Assembler *Asm = Func->getAssembler
(); Asm->bindLocalLabel(LabelNumber); if (OffsetReloc != nullptr) { Asm->bindRelocOffset(OffsetReloc); } } template
void InstImpl
::InstX86Label::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); Str << getLabelName() << ":"; } template
void InstImpl
::InstX86Br::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); Str << "\t"; if (Condition == Cond::Br_None) { Str << "jmp"; } else { Str << Traits::InstBrAttributes[Condition].EmitString; } if (Label) { Str << "\t" << Label->getLabelName(); } else { if (Condition == Cond::Br_None) { Str << "\t" << getTargetFalse()->getAsmName(); } else { Str << "\t" << getTargetTrue()->getAsmName(); if (getTargetFalse()) { Str << "\n\t" "jmp\t" << getTargetFalse()->getAsmName(); } } } } template
void InstImpl
::InstX86Br::emitIAS(const Cfg *Func) const { Assembler *Asm = Func->getAssembler
(); if (Label) { auto *L = Asm->getOrCreateLocalLabel(Label->getLabelNumber()); if (Condition == Cond::Br_None) { Asm->jmp(L, isNear()); } else { Asm->j(Condition, L, isNear()); } } else { if (Condition == Cond::Br_None) { auto *L = Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); assert(!getTargetTrue()); Asm->jmp(L, isNear()); } else { auto *L = Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex()); Asm->j(Condition, L, isNear()); if (getTargetFalse()) { auto *L2 = Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); Asm->jmp(L2, isNear()); } } } } template
void InstImpl
::InstX86Br::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); Str << "br "; if (Condition == Cond::Br_None) { if (Label) { Str << "label %" << Label->getLabelName(); } else { Str << "label %" << getTargetFalse()->getName(); } return; } Str << Traits::InstBrAttributes[Condition].DisplayString; if (Label) { Str << ", label %" << Label->getLabelName(); } else { Str << ", label %" << getTargetTrue()->getName(); if (getTargetFalse()) { Str << ", label %" << getTargetFalse()->getName(); } } Str << " // (" << (isNear() ? "near" : "far") << " jump)"; } template
void InstImpl
::InstX86Jmp::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 1); const Operand *Src = this->getSrc(0); if (Traits::Is64Bit) { if (const auto *CR = llvm::dyn_cast
(Src)) { Str << "\t" "jmp" "\t" << CR->getName(); return; } } Str << "\t" "jmp" "\t*"; getJmpTarget()->emit(Func); } template
void InstImpl
::InstX86Jmp::emitIAS(const Cfg *Func) const { // Note: Adapted (mostly copied) from // InstImpl
::InstX86Call::emitIAS(). Assembler *Asm = Func->getAssembler
(); Operand *Target = getJmpTarget(); if (const auto *Var = llvm::dyn_cast
(Target)) { if (Var->hasReg()) { Asm->jmp(Traits::getEncodedGPR(Var->getRegNum())); } else { // The jmp instruction with a memory operand should be possible to // encode, but it isn't a valid sandboxed instruction, and there // shouldn't be a register allocation issue to jump through a scratch // register, so we don't really need to bother implementing it. llvm::report_fatal_error("Assembler can't jmp to memory operand"); } } else if (const auto *Mem = llvm::dyn_cast
(Target)) { (void)Mem; assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); llvm::report_fatal_error("Assembler can't jmp to memory operand"); } else if (const auto *CR = llvm::dyn_cast
(Target)) { Asm->jmp(CR); } else if (const auto *Imm = llvm::dyn_cast
(Target)) { // NaCl trampoline calls refer to an address within the sandbox directly. // This is usually only needed for non-IRT builds and otherwise not very // portable or stable. Usually this is only done for "calls" and not jumps. Asm->jmp(AssemblerImmediate(Imm->getValue())); } else { llvm::report_fatal_error("Unexpected operand type"); } } template
void InstImpl
::InstX86Jmp::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); Str << "jmp "; getJmpTarget()->dump(Func); } template
void InstImpl
::InstX86Call::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 1); Str << "\t" "call\t"; Operand *CallTarget = getCallTarget(); auto *Target = InstX86Base::getTarget(Func); if (const auto *CI = llvm::dyn_cast
(CallTarget)) { // Emit without a leading '$'. Str << CI->getValue(); } else if (const auto DirectCallTarget = llvm::dyn_cast
(CallTarget)) { DirectCallTarget->emitWithoutPrefix(Target); } else { Str << "*"; CallTarget->emit(Func); } } template
void InstImpl
::InstX86Call::emitIAS(const Cfg *Func) const { Assembler *Asm = Func->getAssembler
(); Operand *CallTarget = getCallTarget(); auto *Target = InstX86Base::getTarget(Func); if (const auto *Var = llvm::dyn_cast
(CallTarget)) { if (Var->hasReg()) { Asm->call(Traits::getEncodedGPR(Var->getRegNum())); } else { Asm->call(Target->stackVarToAsmOperand(Var)); } } else if (const auto *Mem = llvm::dyn_cast
(CallTarget)) { assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); Asm->call(Mem->toAsmAddress(Asm, Target)); } else if (const auto *CR = llvm::dyn_cast
(CallTarget)) { Asm->call(CR); } else if (const auto *Imm = llvm::dyn_cast
(CallTarget)) { Asm->call(AssemblerImmediate(Imm->getValue())); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::InstX86Call::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); if (this->getDest()) { this->dumpDest(Func); Str << " = "; } Str << "call "; getCallTarget()->dump(Func); } // The this->Opcode parameter needs to be char* and not std::string because of // template issues. template
void InstImpl
::InstX86Base::emitTwoAddress( const Cfg *Func, const char *Opcode, const char *Suffix) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(getSrcSize() == 2); Operand *Dest = getDest(); if (Dest == nullptr) Dest = getSrc(0); assert(Dest == getSrc(0)); Operand *Src1 = getSrc(1); Str << "\t" << Opcode << Suffix << InstX86Base::getWidthString(Dest->getType()) << "\t"; Src1->emit(Func); Str << ", "; Dest->emit(Func); } template
void InstImpl
::emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op, const GPREmitterOneOp &Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); if (const auto *Var = llvm::dyn_cast
(Op)) { if (Var->hasReg()) { // We cheat a little and use GPRRegister even for byte operations. GPRRegister VarReg = Traits::getEncodedGPR(Var->getRegNum()); (Asm->*(Emitter.Reg))(Ty, VarReg); } else { Address StackAddr(Target->stackVarToAsmOperand(Var)); (Asm->*(Emitter.Addr))(Ty, StackAddr); } } else if (const auto *Mem = llvm::dyn_cast
(Op)) { Mem->emitSegmentOverride(Asm); (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target)); } else { llvm_unreachable("Unexpected operand type"); } } template
template
void InstImpl
::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea, Type Ty, const Variable *Var, const Operand *Src, const GPREmitterRegOp &Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); assert(Var->hasReg()); // We cheat a little and use GPRRegister even for byte operations. GPRRegister VarReg = VarCanBeByte ? Traits::getEncodedGPR(Var->getRegNum()) : Traits::getEncodedGPR(Var->getRegNum()); if (const auto *SrcVar = llvm::dyn_cast
(Src)) { if (SrcVar->hasReg()) { GPRRegister SrcReg = SrcCanBeByte ? Traits::getEncodedGPR(SrcVar->getRegNum()) : Traits::getEncodedGPR(SrcVar->getRegNum()); (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); } else { Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); } } else if (const auto *Mem = llvm::dyn_cast
(Src)) { Mem->emitSegmentOverride(Asm); (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target, IsLea)); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { assert(Traits::Is64Bit); assert(Utils::IsInt(32, Imm->getValue())); (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); } else if (const auto *Reloc = llvm::dyn_cast
(Src)) { const auto FixupKind = (Reloc->getName().hasStdString() && Reloc->getName().toString() == GlobalOffsetTable) ? Traits::FK_GotPC : Traits::TargetLowering::getAbsFixup(); AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc); (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Fixup)); } else if (const auto *Split = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASAddrOpTyGPR(const Cfg *Func, Type Ty, const Address &Addr, const Operand *Src, const GPREmitterAddrOp &Emitter) { Assembler *Asm = Func->getAssembler
(); // Src can only be Reg or AssemblerImmediate. if (const auto *SrcVar = llvm::dyn_cast
(Src)) { assert(SrcVar->hasReg()); GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar->getRegNum()); (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue())); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { assert(Traits::Is64Bit); assert(Utils::IsInt(32, Imm->getValue())); (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue())); } else if (const auto *Reloc = llvm::dyn_cast
(Src)) { const auto FixupKind = (Reloc->getName().hasStdString() && Reloc->getName().toString() == GlobalOffsetTable) ? Traits::FK_GotPC : Traits::TargetLowering::getAbsFixup(); AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc); (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Fixup)); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASAsAddrOpTyGPR( const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1, const GPREmitterAddrOp &Emitter) { auto *Target = InstX86Base::getTarget(Func); if (const auto *Op0Var = llvm::dyn_cast
(Op0)) { assert(!Op0Var->hasReg()); Address StackAddr(Target->stackVarToAsmOperand(Op0Var)); emitIASAddrOpTyGPR(Func, Ty, StackAddr, Op1, Emitter); } else if (const auto *Op0Mem = llvm::dyn_cast
(Op0)) { Assembler *Asm = Func->getAssembler
(); Op0Mem->emitSegmentOverride(Asm); emitIASAddrOpTyGPR(Func, Ty, Op0Mem->toAsmAddress(Asm, Target), Op1, Emitter); } else if (const auto *Split = llvm::dyn_cast
(Op0)) { emitIASAddrOpTyGPR(Func, Ty, Split->toAsmAddress(Func), Op1, Emitter); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASGPRShift(const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const GPREmitterShiftOp &Emitter) { Assembler *Asm = Func->getAssembler
(); // Technically, the Dest Var can be mem as well, but we only use Reg. We can // extend this to check Dest if we decide to use that form. assert(Var->hasReg()); // We cheat a little and use GPRRegister even for byte operations. GPRRegister VarReg = Traits::getEncodedGPR(Var->getRegNum()); // Src must be reg == ECX or an Imm8. This is asserted by the assembler. if (const auto *SrcVar = llvm::dyn_cast
(Src)) { assert(SrcVar->hasReg()); GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar->getRegNum()); (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { assert(Traits::Is64Bit); assert(Utils::IsInt(32, Imm->getValue())); (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASGPRShiftDouble( const Cfg *Func, const Variable *Dest, const Operand *Src1Op, const Operand *Src2Op, const GPREmitterShiftD &Emitter) { Assembler *Asm = Func->getAssembler
(); // Dest can be reg or mem, but we only use the reg variant. assert(Dest->hasReg()); GPRRegister DestReg = Traits::getEncodedGPR(Dest->getRegNum()); // SrcVar1 must be reg. const auto *SrcVar1 = llvm::cast
(Src1Op); assert(SrcVar1->hasReg()); GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar1->getRegNum()); Type Ty = SrcVar1->getType(); // Src2 can be the implicit CL register or an immediate. if (const auto *Imm = llvm::dyn_cast
(Src2Op)) { (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg, AssemblerImmediate(Imm->getValue())); } else { assert(llvm::cast
(Src2Op)->getRegNum() == RegisterSet::Reg_cl); (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg); } } template
void InstImpl
::emitIASXmmShift(const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const XmmEmitterShiftOp &Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); assert(Var->hasReg()); XmmRegister VarReg = Traits::getEncodedXmm(Var->getRegNum()); if (const auto *SrcVar = llvm::dyn_cast
(Src)) { if (SrcVar->hasReg()) { XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum()); (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); } else { Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); } } else if (const auto *Mem = llvm::dyn_cast
(Src)) { assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target)); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.XmmImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASRegOpTyXMM(const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, const XmmEmitterRegOp &Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); assert(Var->hasReg()); XmmRegister VarReg = Traits::getEncodedXmm(Var->getRegNum()); if (const auto *SrcVar = llvm::dyn_cast
(Src)) { if (SrcVar->hasReg()) { XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum()); (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); } else { Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); } } else if (const auto *Mem = llvm::dyn_cast
(Src)) { assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target)); } else if (const auto *Imm = llvm::dyn_cast
(Src)) { (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Traits::Address::ofConstPool(Asm, Imm)); } else { llvm_unreachable("Unexpected operand type"); } } template
template
void InstImpl
::emitIASCastRegOp( const Cfg *Func, Type DestTy, const Variable *Dest, Type SrcTy, const Operand *Src, const CastEmitterRegOp
&Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); assert(Dest->hasReg()); DReg_t DestReg = destEnc(Dest->getRegNum()); if (const auto *SrcVar = llvm::dyn_cast
(Src)) { if (SrcVar->hasReg()) { SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); (Asm->*(Emitter.RegReg))(DestTy, DestReg, SrcTy, SrcReg); } else { Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr); } } else if (const auto *Mem = llvm::dyn_cast
(Src)) { Mem->emitSegmentOverride(Asm); (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, Mem->toAsmAddress(Asm, Target)); } else { llvm_unreachable("Unexpected operand type"); } } template
template
void InstImpl
::emitIASThreeOpImmOps( const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0, const Operand *Src1, const ThreeOpImmEmitter
Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); // This only handles Dest being a register, and Src1 being an immediate. assert(Dest->hasReg()); DReg_t DestReg = destEnc(Dest->getRegNum()); AssemblerImmediate Imm(llvm::cast
(Src1)->getValue()); if (const auto *SrcVar = llvm::dyn_cast
(Src0)) { if (SrcVar->hasReg()) { SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm); } else { Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm); } } else if (const auto *Mem = llvm::dyn_cast
(Src0)) { Mem->emitSegmentOverride(Asm); (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, Mem->toAsmAddress(Asm, Target), Imm); } else { llvm_unreachable("Unexpected operand type"); } } template
void InstImpl
::emitIASMovlikeXMM(const Cfg *Func, const Variable *Dest, const Operand *Src, const XmmEmitterMovOps Emitter) { auto *Target = InstX86Base::getTarget(Func); Assembler *Asm = Func->getAssembler
(); if (Dest->hasReg()) { XmmRegister DestReg = Traits::getEncodedXmm(Dest->getRegNum()); if (const auto *SrcVar = llvm::dyn_cast
(Src)) { if (SrcVar->hasReg()) { (Asm->*(Emitter.XmmXmm))(DestReg, Traits::getEncodedXmm(SrcVar->getRegNum())); } else { Address StackAddr(Target->stackVarToAsmOperand(SrcVar)); (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr); } } else if (const auto *SrcMem = llvm::dyn_cast
(Src)) { assert(SrcMem->getSegmentRegister() == X86OperandMem::DefaultSegment); (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm, Target)); } else { llvm_unreachable("Unexpected operand type"); } } else { Address StackAddr(Target->stackVarToAsmOperand(Dest)); // Src must be a register in this case. const auto *SrcVar = llvm::cast
(Src); assert(SrcVar->hasReg()); (Asm->*(Emitter.AddrXmm))(StackAddr, Traits::getEncodedXmm(SrcVar->getRegNum())); } } template
void InstImpl
::InstX86Movmsk::dump(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrDump(); this->dumpDest(Func); Str << " = movmsk." << this->getSrc(0)->getType() << " "; this->dumpSources(Func); } template
void InstImpl
::InstX86Movmsk::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 1); Type SrcTy = this->getSrc(0)->getType(); assert(isVectorType(SrcTy)); switch (SrcTy) { case IceType_v16i8: Str << "\t" "pmovmskb" "\t"; break; case IceType_v4i32: case IceType_v4f32: Str << "\t" "movmskps" "\t"; break; default: llvm_unreachable("Unexpected operand type"); } this->getSrc(0)->emit(Func); Str << ", "; this->getDest()->emit(Func); } template
void InstImpl
::InstX86Movmsk::emitIAS(const Cfg *Func) const { assert(this->getSrcSize() == 1); Assembler *Asm = Func->getAssembler
(); const Variable *Dest = this->getDest(); const Variable *Src = llvm::cast
(this->getSrc(0)); const Type DestTy = Dest->getType(); (void)DestTy; const Type SrcTy = Src->getType(); assert(isVectorType(SrcTy)); assert(isScalarIntegerType(DestTy)); if (Traits::Is64Bit) { assert(DestTy == IceType_i32 || DestTy == IceType_i64); } else { assert(typeWidthInBytes(DestTy) <= 4); } XmmRegister SrcReg = Traits::getEncodedXmm(Src->getRegNum()); GPRRegister DestReg = Traits::getEncodedGPR(Dest->getRegNum()); Asm->movmsk(SrcTy, DestReg, SrcReg); } template
void InstImpl
::InstX86Sqrt::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 1); Type Ty = this->getSrc(0)->getType(); assert(isScalarFloatingType(Ty)); Str << "\t" "sqrt" << Traits::TypeAttributes[Ty].SpSdString << "\t"; this->getSrc(0)->emit(Func); Str << ", "; this->getDest()->emit(Func); } template
void InstImpl
::InstX86Div::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 3); Operand *Src1 = this->getSrc(1); Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t"; Src1->emit(Func); } template
void InstImpl
::InstX86Div::emitIAS(const Cfg *Func) const { assert(this->getSrcSize() == 3); const Operand *Src = this->getSrc(1); Type Ty = Src->getType(); static GPREmitterOneOp Emitter = {&Assembler::div, &Assembler::div}; emitIASOpTyGPR(Func, Ty, Src, Emitter); } template
void InstImpl
::InstX86Idiv::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 3); Operand *Src1 = this->getSrc(1); Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t"; Src1->emit(Func); } template
void InstImpl
::InstX86Idiv::emitIAS(const Cfg *Func) const { assert(this->getSrcSize() == 3); const Operand *Src = this->getSrc(1); Type Ty = Src->getType(); static const GPREmitterOneOp Emitter = {&Assembler::idiv, &Assembler::idiv}; emitIASOpTyGPR(Func, Ty, Src, Emitter); } // pblendvb and blendvps take xmm0 as a final implicit argument. template
void InstImpl
::emitVariableBlendInst(const char *Opcode, const Inst *Instr, const Cfg *Func) { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(Instr->getSrcSize() == 3); assert(llvm::cast
(Instr->getSrc(2))->getRegNum() == RegisterSet::Reg_xmm0); Str << "\t" << Opcode << "\t"; Instr->getSrc(1)->emit(Func); Str << ", "; Instr->getDest()->emit(Func); } template
void InstImpl
::emitIASVariableBlendInst( const Inst *Instr, const Cfg *Func, const XmmEmitterRegOp &Emitter) { assert(Instr->getSrcSize() == 3); assert(llvm::cast
(Instr->getSrc(2))->getRegNum() == RegisterSet::Reg_xmm0); const Variable *Dest = Instr->getDest(); const Operand *Src = Instr->getSrc(1); emitIASRegOpTyXMM(Func, Dest->getType(), Dest, Src, Emitter); } template
void InstImpl
::InstX86Blendvps::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; emitVariableBlendInst(this->Opcode, this, Func); } template
void InstImpl
::InstX86Blendvps::emitIAS(const Cfg *Func) const { static const XmmEmitterRegOp Emitter = {&Assembler::blendvps, &Assembler::blendvps}; emitIASVariableBlendInst(this, Func, Emitter); } template
void InstImpl
::InstX86Pblendvb::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; emitVariableBlendInst(this->Opcode, this, Func); } template
void InstImpl
::InstX86Pblendvb::emitIAS(const Cfg *Func) const { static const XmmEmitterRegOp Emitter = {&Assembler::pblendvb, &Assembler::pblendvb}; emitIASVariableBlendInst(this, Func, Emitter); } template
void InstImpl
::InstX86Imul::emit(const Cfg *Func) const { if (!BuildDefs::dump()) return; Ostream &Str = Func->getContext()->getStrEmit(); assert(this->getSrcSize() == 2); Variable *Dest = this->getDest(); if (isByteSizedArithType(Dest->getType())) { // The 8-bit version of imul only allows the form "imul r/m8". const auto *Src0Var = llvm::dyn_cast