Chromium Code Reviews| Index: src/IceInstX86BaseImpl.h |
| diff --git a/src/IceInstX86BaseImpl.h b/src/IceInstX86BaseImpl.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3baf9c6ed5f6841d9087b1665f44fe87d6ac938a |
| --- /dev/null |
| +++ b/src/IceInstX86BaseImpl.h |
| @@ -0,0 +1,3429 @@ |
| +//===- 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. |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// This file implements the InstX86Base and OperandX86Base template classes that |
| +// are shared accross all x86 targets. |
|
jvoung (off chromium)
2015/07/06 18:58:45
accross -> across
John
2015/07/06 22:30:09
Done.
|
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#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" |
| + |
| +namespace Ice { |
| + |
| +namespace X86Internal { |
| + |
| +template <class Machine> |
| +const char *InstX86Base<Machine>::getWidthString(Type Ty) { |
| + return Traits::TypeAttributes[Ty].WidthString; |
| +} |
| + |
| +template <class Machine> |
| +const char *InstX86Base<Machine>::getFldString(Type Ty) { |
| + return Traits::TypeAttributes[Ty].FldString; |
| +} |
| + |
| +template <class Machine> |
| +typename InstX86Base<Machine>::Traits::Cond::BrCond |
| +InstX86Base<Machine>::getOppositeCondition(typename Traits::Cond::BrCond Cond) { |
| + return Traits::InstBrAttributes[Cond].Opposite; |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseFakeRMW<Machine>::InstX86BaseFakeRMW(Cfg *Func, Operand *Data, |
| + Operand *Addr, |
| + InstArithmetic::OpKind Op, |
| + Variable *Beacon) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::FakeRMW, 3, nullptr), |
| + Op(Op) { |
| + this->addSource(Data); |
| + this->addSource(Addr); |
| + this->addSource(Beacon); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseAdjustStack<Machine>::InstX86BaseAdjustStack(Cfg *Func, SizeT Amount, |
| + Variable *Esp) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Adjuststack, 1, Esp), |
| + Amount(Amount) { |
| + this->addSource(Esp); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseMul<Machine>::InstX86BaseMul(Cfg *Func, Variable *Dest, |
| + Variable *Source1, Operand *Source2) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mul, 2, Dest) { |
| + this->addSource(Source1); |
| + this->addSource(Source2); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseShld<Machine>::InstX86BaseShld(Cfg *Func, Variable *Dest, |
| + Variable *Source1, Variable *Source2) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shld, 3, Dest) { |
| + this->addSource(Dest); |
| + this->addSource(Source1); |
| + this->addSource(Source2); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseShrd<Machine>::InstX86BaseShrd(Cfg *Func, Variable *Dest, |
| + Variable *Source1, Variable *Source2) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shrd, 3, Dest) { |
| + this->addSource(Dest); |
| + this->addSource(Source1); |
| + this->addSource(Source2); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseLabel<Machine>::InstX86BaseLabel( |
| + Cfg *Func, typename InstX86Base<Machine>::Traits::TargetLowering *Target) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Label, 0, nullptr), |
| + Number(Target->makeNextLabelNumber()) {} |
| + |
| +template <class Machine> |
| +IceString InstX86BaseLabel<Machine>::getName(const Cfg *Func) const { |
| + return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseBr<Machine>::InstX86BaseBr( |
| + Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
| + const InstX86BaseLabel<Machine> *Label, |
| + typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr), |
| + Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse), |
| + Label(Label) {} |
| + |
| +template <class Machine> |
| +bool InstX86BaseBr<Machine>::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 == InstX86Base<Machine>::Traits::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 != InstX86Base<Machine>::Traits::Cond::Br_None); |
| + Condition = this->getOppositeCondition(Condition); |
| + TargetTrue = getTargetFalse(); |
| + TargetFalse = nullptr; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +template <class Machine> |
| +bool InstX86BaseBr<Machine>::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { |
| + if (TargetFalse == OldNode) { |
| + TargetFalse = NewNode; |
| + return true; |
| + } else if (TargetTrue == OldNode) { |
| + TargetTrue = NewNode; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseJmp<Machine>::InstX86BaseJmp(Cfg *Func, Operand *Target) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Jmp, 1, nullptr) { |
| + this->addSource(Target); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseCall<Machine>::InstX86BaseCall(Cfg *Func, Variable *Dest, |
| + Operand *CallTarget) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Call, 1, Dest) { |
| + this->HasSideEffects = true; |
| + this->addSource(CallTarget); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseCmov<Machine>::InstX86BaseCmov( |
| + Cfg *Func, Variable *Dest, Operand *Source, |
| + typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::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 <class Machine> |
| +InstX86BaseCmpps<Machine>::InstX86BaseCmpps( |
| + Cfg *Func, Variable *Dest, Operand *Source, |
| + typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest), |
| + Condition(Condition) { |
| + this->addSource(Dest); |
| + this->addSource(Source); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseCmpxchg<Machine>::InstX86BaseCmpxchg(Cfg *Func, Operand *DestOrAddr, |
| + Variable *Eax, |
| + Variable *Desired, bool Locked) |
| + : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 3, |
| + llvm::dyn_cast<Variable>(DestOrAddr), |
| + Locked) { |
| + assert(Eax->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + this->addSource(DestOrAddr); |
| + this->addSource(Eax); |
| + this->addSource(Desired); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseCmpxchg8b<Machine>::InstX86BaseCmpxchg8b( |
| + Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *Addr, |
| + Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked) |
| + : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 5, |
| + nullptr, Locked) { |
| + assert(Edx->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| + assert(Eax->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + assert(Ecx->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); |
| + assert(Ebx->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ebx); |
| + this->addSource(Addr); |
| + this->addSource(Edx); |
| + this->addSource(Eax); |
| + this->addSource(Ecx); |
| + this->addSource(Ebx); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseCvt<Machine>::InstX86BaseCvt(Cfg *Func, Variable *Dest, |
| + Operand *Source, CvtVariant Variant) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cvt, 1, Dest), |
| + Variant(Variant) { |
| + this->addSource(Source); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseIcmp<Machine>::InstX86BaseIcmp(Cfg *Func, Operand *Src0, |
| + Operand *Src1) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Icmp, 2, nullptr) { |
| + this->addSource(Src0); |
| + this->addSource(Src1); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseUcomiss<Machine>::InstX86BaseUcomiss(Cfg *Func, Operand *Src0, |
| + Operand *Src1) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ucomiss, 2, nullptr) { |
| + this->addSource(Src0); |
| + this->addSource(Src1); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseUD2<Machine>::InstX86BaseUD2(Cfg *Func) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::UD2, 0, nullptr) {} |
| + |
| +template <class Machine> |
| +InstX86BaseTest<Machine>::InstX86BaseTest(Cfg *Func, Operand *Src1, |
| + Operand *Src2) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Test, 2, nullptr) { |
| + this->addSource(Src1); |
| + this->addSource(Src2); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseMfence<Machine>::InstX86BaseMfence(Cfg *Func) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mfence, 0, nullptr) { |
| + this->HasSideEffects = true; |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseStore<Machine>::InstX86BaseStore( |
| + Cfg *Func, Operand *Value, |
| + typename InstX86Base<Machine>::Traits::X86Operand *Mem) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Store, 2, nullptr) { |
| + this->addSource(Value); |
| + this->addSource(Mem); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseStoreP<Machine>::InstX86BaseStoreP( |
| + Cfg *Func, Variable *Value, |
| + typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreP, 2, nullptr) { |
| + this->addSource(Value); |
| + this->addSource(Mem); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseStoreQ<Machine>::InstX86BaseStoreQ( |
| + Cfg *Func, Variable *Value, |
| + typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreQ, 2, nullptr) { |
| + this->addSource(Value); |
| + this->addSource(Mem); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseNop<Machine>::InstX86BaseNop(Cfg *Func, |
| + InstX86BaseNop::NopVariant Variant) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Nop, 0, nullptr), |
| + Variant(Variant) {} |
| + |
| +template <class Machine> |
| +InstX86BaseFld<Machine>::InstX86BaseFld(Cfg *Func, Operand *Src) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fld, 1, nullptr) { |
| + this->addSource(Src); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseFstp<Machine>::InstX86BaseFstp(Cfg *Func, Variable *Dest) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {} |
| + |
| +template <class Machine> |
| +InstX86BasePop<Machine>::InstX86BasePop(Cfg *Func, Variable *Dest) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::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 <class Machine> |
| +InstX86BasePush<Machine>::InstX86BasePush(Cfg *Func, Variable *Source) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) { |
| + this->addSource(Source); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseRet<Machine>::InstX86BaseRet(Cfg *Func, Variable *Source) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ret, Source ? 1 : 0, |
| + nullptr) { |
| + if (Source) |
| + this->addSource(Source); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseSetcc<Machine>::InstX86BaseSetcc( |
| + Cfg *Func, Variable *Dest, |
| + typename InstX86Base<Machine>::Traits::Cond::BrCond Cond) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Setcc, 0, Dest), |
| + Condition(Cond) {} |
| + |
| +template <class Machine> |
| +InstX86BaseXadd<Machine>::InstX86BaseXadd(Cfg *Func, Operand *Dest, |
| + Variable *Source, bool Locked) |
| + : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Xadd, 2, |
| + llvm::dyn_cast<Variable>(Dest), Locked) { |
| + this->addSource(Dest); |
| + this->addSource(Source); |
| +} |
| + |
| +template <class Machine> |
| +InstX86BaseXchg<Machine>::InstX86BaseXchg(Cfg *Func, Operand *Dest, |
| + Variable *Source) |
| + : InstX86Base<Machine>(Func, InstX86Base<Machine>::Xchg, 2, |
| + llvm::dyn_cast<Variable>(Dest)) { |
| + this->addSource(Dest); |
| + this->addSource(Source); |
| +} |
| + |
| +// ======================== Dump routines ======================== // |
| + |
| +template <class Machine> |
| +void InstX86Base<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "[" << Traits::TargetName << "] "; |
| + Inst::dump(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFakeRMW<Machine>::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 <class Machine> |
| +void InstX86BaseLabel<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << getName(Func) << ":"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseLabel<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->BindLocalLabel(Number); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseLabel<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << getName(Func) << ":"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseBr<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << "\t"; |
| + |
| + if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { |
| + Str << "jmp"; |
| + } else { |
| + Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].EmitString; |
| + } |
| + |
| + if (Label) { |
| + Str << "\t" << Label->getName(Func); |
| + } else { |
| + if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { |
| + Str << "\t" << getTargetFalse()->getAsmName(); |
| + } else { |
| + Str << "\t" << getTargetTrue()->getAsmName(); |
| + if (getTargetFalse()) { |
| + Str << "\n\tjmp\t" << getTargetFalse()->getAsmName(); |
| + } |
| + } |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseBr<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (Label) { |
| + class Label *L = Asm->GetOrCreateLocalLabel(Label->getNumber()); |
| + // In all these cases, local Labels should only be used for Near. |
| + const bool Near = true; |
| + if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { |
| + Asm->jmp(L, Near); |
| + } else { |
| + Asm->j(Condition, L, Near); |
| + } |
| + } else { |
| + // Pessimistically assume it's far. This only affects Labels that |
| + // are not Bound. |
| + const bool Near = false; |
| + if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { |
| + class Label *L = |
| + Asm->GetOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); |
| + assert(!getTargetTrue()); |
| + Asm->jmp(L, Near); |
| + } else { |
| + class Label *L = |
| + Asm->GetOrCreateCfgNodeLabel(getTargetTrue()->getIndex()); |
| + Asm->j(Condition, L, Near); |
| + if (getTargetFalse()) { |
| + class Label *L2 = |
| + Asm->GetOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); |
| + Asm->jmp(L2, Near); |
| + } |
| + } |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseBr<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "br "; |
| + |
| + if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { |
| + Str << "label %" |
| + << (Label ? Label->getName(Func) : getTargetFalse()->getName()); |
| + return; |
| + } |
| + |
| + Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition] |
| + .DisplayString; |
| + if (Label) { |
| + Str << ", label %" << Label->getName(Func); |
| + } else { |
| + Str << ", label %" << getTargetTrue()->getName(); |
| + if (getTargetFalse()) { |
| + Str << ", label %" << getTargetFalse()->getName(); |
| + } |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseJmp<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Str << "\tjmp\t*"; |
| + getJmpTarget()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseJmp<Machine>::emitIAS(const Cfg *Func) const { |
| + // Note: Adapted (mostly copied) from InstX86BaseCall<Machine>::emitIAS(). |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Operand *Target = getJmpTarget(); |
| + if (const auto Var = llvm::dyn_cast<Variable>(Target)) { |
| + if (Var->hasReg()) { |
| + Asm->jmp(InstX86Base<Machine>::Traits::RegisterSet::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< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + Target)) { |
| + (void)Mem; |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + llvm::report_fatal_error("Assembler can't jmp to memory operand"); |
| + } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { |
| + assert(CR->getOffset() == 0 && "We only support jumping to a function"); |
| + Asm->jmp(CR); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(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. |
| + // TODO(jvoung): Support this when there is a lowering that |
| + // actually triggers this case. |
| + (void)Imm; |
| + llvm::report_fatal_error("Unexpected jmp to absolute address"); |
| + } else { |
| + llvm::report_fatal_error("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseJmp<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "jmp "; |
| + getJmpTarget()->dump(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCall<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Str << "\tcall\t"; |
| + if (const auto CI = llvm::dyn_cast<ConstantInteger32>(getCallTarget())) { |
| + // Emit without a leading '$'. |
| + Str << CI->getValue(); |
| + } else if (const auto CallTarget = |
| + llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { |
| + CallTarget->emitWithoutPrefix(Func->getTarget()); |
| + } else { |
| + Str << "*"; |
| + getCallTarget()->emit(Func); |
| + } |
| + Func->getTarget()->resetStackAdjustment(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCall<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Operand *Target = getCallTarget(); |
| + if (const auto Var = llvm::dyn_cast<Variable>(Target)) { |
| + if (Var->hasReg()) { |
| + Asm->call(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + Var->getRegNum())); |
| + } else { |
| + Asm->call( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Var)); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + Target)) { |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + Asm->call(Mem->toAsmAddress(Asm)); |
| + } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { |
| + assert(CR->getOffset() == 0 && "We only support calling a function"); |
| + Asm->call(CR); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { |
| + Asm->call(Immediate(Imm->getValue())); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| + Func->getTarget()->resetStackAdjustment(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCall<Machine>::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 ShiftHack parameter is used to emit "cl" instead of "ecx" for |
| +// shift instructions, in order to be syntactically valid. The |
| +// this->Opcode parameter needs to be char* and not IceString because of |
| +// template issues. |
| +template <class Machine> |
| +void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst, |
| + const Cfg *Func, bool ShiftHack) { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(Inst->getSrcSize() == 2); |
| + Operand *Dest = Inst->getDest(); |
| + if (Dest == nullptr) |
| + Dest = Inst->getSrc(0); |
| + assert(Dest == Inst->getSrc(0)); |
| + Operand *Src1 = Inst->getSrc(1); |
| + Str << "\t" << Opcode << InstX86Base<Machine>::getWidthString(Dest->getType()) |
| + << "\t"; |
| + const auto ShiftReg = llvm::dyn_cast<Variable>(Src1); |
| + if (ShiftHack && ShiftReg && |
| + ShiftReg->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx) |
| + Str << "%cl"; |
| + else |
| + Src1->emit(Func); |
| + Str << ", "; |
| + Dest->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op, |
| + const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (const auto Var = llvm::dyn_cast<Variable>(Op)) { |
| + if (Var->hasReg()) { |
| + // We cheat a little and use GPRRegister even for byte operations. |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
| + Ty, Var->getRegNum()); |
| + (Asm->*(Emitter.Reg))(Ty, VarReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Var)); |
| + (Asm->*(Emitter.Addr))(Ty, StackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) { |
| + Mem->emitSegmentOverride(Asm); |
| + (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine, bool VarCanBeByte, bool SrcCanBeByte> |
| +void emitIASRegOpTyGPR( |
| + const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(Var->hasReg()); |
| + // We cheat a little and use GPRRegister even for byte operations. |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = |
| + VarCanBeByte |
| + ? InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
| + Ty, Var->getRegNum()) |
| + : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + Var->getRegNum()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = |
| + SrcCanBeByte |
| + ? InstX86Base<Machine>::Traits::RegisterSet:: |
| + getEncodedByteRegOrGPR(Ty, SrcVar->getRegNum()) |
| + : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + SrcVar->getRegNum()); |
| + (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + Mem->emitSegmentOverride(Asm); |
| + (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
| + (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); |
| + } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { |
| + AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc); |
| + (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Reloc->getOffset(), Fixup)); |
| + } else if (const auto Split = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::VariableSplit>(Src)) { |
| + (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASAddrOpTyGPR( |
| + const Cfg *Func, Type Ty, |
| + const typename InstX86Base<Machine>::Traits::Address &Addr, |
| + const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + // Src can only be Reg or Immediate. |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + assert(SrcVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
| + Ty, SrcVar->getRegNum()); |
| + (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
| + (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Imm->getValue())); |
| + } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { |
| + AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc); |
| + (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Reloc->getOffset(), Fixup)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASAsAddrOpTyGPR( |
| + const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1, |
| + const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp |
| + &Emitter) { |
| + if (const auto Op0Var = llvm::dyn_cast<Variable>(Op0)) { |
| + assert(!Op0Var->hasReg()); |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Op0Var)); |
| + emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter); |
| + } else if (const auto Op0Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Op0)) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Op0Mem->emitSegmentOverride(Asm); |
| + emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm), Op1, |
| + Emitter); |
| + } else if (const auto Split = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) { |
| + emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1, |
| + Emitter); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86Base<Machine>::emitIASGPRShift( |
| + const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + // 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. |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
| + Ty, Var->getRegNum()); |
| + // Src must be reg == ECX or an Imm8. |
| + // This is asserted by the assembler. |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + assert(SrcVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
| + Ty, SrcVar->getRegNum()); |
| + (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
| + (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASGPRShiftDouble( |
| + const Cfg *Func, const Variable *Dest, const Operand *Src1Op, |
| + const Operand *Src2Op, |
| + const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftD |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + // Dest can be reg or mem, but we only use the reg variant. |
| + assert(Dest->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister DestReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + Dest->getRegNum()); |
| + // SrcVar1 must be reg. |
| + const auto SrcVar1 = llvm::cast<Variable>(Src1Op); |
| + assert(SrcVar1->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + SrcVar1->getRegNum()); |
| + Type Ty = SrcVar1->getType(); |
| + // Src2 can be the implicit CL register or an immediate. |
| + if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src2Op)) { |
| + (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg, |
| + Immediate(Imm->getValue())); |
| + } else { |
| + assert(llvm::cast<Variable>(Src2Op)->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); |
| + (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASXmmShift( |
| + const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(Var->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Var->getRegNum()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum()); |
| + (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); |
| + } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
| + (Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue())); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASRegOpTyXMM( |
| + const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(Var->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Var->getRegNum()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum()); |
| + (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); |
| + } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) { |
| + (Asm->*(Emitter.XmmAddr))( |
| + Ty, VarReg, |
| + InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine, typename DReg_t, typename SReg_t, |
| + DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)> |
| +void emitIASCastRegOp(const Cfg *Func, Type DispatchTy, const Variable *Dest, |
| + const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(Dest->hasReg()); |
| + DReg_t DestReg = destEnc(Dest->getRegNum()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); |
| + (Asm->*(Emitter.RegReg))(DispatchTy, DestReg, SrcReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, SrcStackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + Mem->emitSegmentOverride(Asm); |
| + (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, Mem->toAsmAddress(Asm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine, typename DReg_t, typename SReg_t, |
| + DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)> |
| +void emitIASThreeOpImmOps( |
| + const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0, |
| + const Operand *Src1, |
| + const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + // This only handles Dest being a register, and Src1 being an immediate. |
| + assert(Dest->hasReg()); |
| + DReg_t DestReg = destEnc(Dest->getRegNum()); |
| + Immediate Imm(llvm::cast<ConstantInteger32>(Src1)->getValue()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src0)) { |
| + if (SrcVar->hasReg()) { |
| + SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); |
| + (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) { |
| + Mem->emitSegmentOverride(Asm); |
| + (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, Mem->toAsmAddress(Asm), |
| + Imm); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void emitIASMovlikeXMM( |
| + const Cfg *Func, const Variable *Dest, const Operand *Src, |
| + const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps |
| + Emitter) { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (Dest->hasReg()) { |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Dest->getRegNum()); |
| + if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + (Asm->*(Emitter.XmmXmm))( |
| + DestReg, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering |
| + *>(Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar)); |
| + (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr); |
| + } |
| + } else if (const auto SrcMem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + assert(SrcMem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Dest)); |
| + // Src must be a register in this case. |
| + const auto SrcVar = llvm::cast<Variable>(Src); |
| + assert(SrcVar->hasReg()); |
| + (Asm->*(Emitter.AddrXmm))( |
| + StackAddr, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| + } |
| +} |
| + |
| +#if 0 |
| +TODO(jpp) |
|
jvoung (off chromium)
2015/07/06 18:58:45
Can this TODO be addressed as part of this CL (see
John
2015/07/06 22:30:09
It had been handled, I just forgot to remove it.
|
| +// In-place ops |
| +template <> const char *InstX86BaseBswap::Opcode = "bswap"; |
| +template <> const char *InstX86BaseNeg::Opcode = "neg"; |
| +// Unary ops |
| +template <> const char *InstX86BaseBsf::Opcode = "bsf"; |
| +template <> const char *InstX86BaseBsr::Opcode = "bsr"; |
| +template <> const char *InstX86BaseLea::Opcode = "lea"; |
| +template <> const char *InstX86BaseMovd::Opcode = "movd"; |
| +template <> const char *InstX86BaseMovsx::Opcode = "movs"; |
| +template <> const char *InstX86BaseMovzx::Opcode = "movz"; |
| +template <> const char *InstX86BaseSqrtss::Opcode = "sqrtss"; |
| +template <> const char *InstX86BaseCbwdq::Opcode = "cbw/cwd/cdq"; |
| +// Mov-like ops |
| +template <> const char *InstX86BaseMov::Opcode = "mov"; |
| +template <> const char *InstX86BaseMovp::Opcode = "movups"; |
| +template <> const char *InstX86BaseMovq::Opcode = "movq"; |
| +// Binary ops |
| +template <> const char *InstX86BaseAdd::Opcode = "add"; |
| +template <> const char *InstX86BaseAddRMW::Opcode = "add"; |
| +template <> const char *InstX86BaseAddps::Opcode = "addps"; |
| +template <> const char *InstX86BaseAdc::Opcode = "adc"; |
| +template <> const char *InstX86BaseAdcRMW::Opcode = "adc"; |
| +template <> const char *InstX86BaseAddss::Opcode = "addss"; |
| +template <> const char *InstX86BasePadd::Opcode = "padd"; |
| +template <> const char *InstX86BaseSub::Opcode = "sub"; |
| +template <> const char *InstX86BaseSubRMW::Opcode = "sub"; |
| +template <> const char *InstX86BaseSubps::Opcode = "subps"; |
| +template <> const char *InstX86BaseSubss::Opcode = "subss"; |
| +template <> const char *InstX86BaseSbb::Opcode = "sbb"; |
| +template <> const char *InstX86BaseSbbRMW::Opcode = "sbb"; |
| +template <> const char *InstX86BasePsub::Opcode = "psub"; |
| +template <> const char *InstX86BaseAnd::Opcode = "and"; |
| +template <> const char *InstX86BaseAndRMW::Opcode = "and"; |
| +template <> const char *InstX86BasePand::Opcode = "pand"; |
| +template <> const char *InstX86BasePandn::Opcode = "pandn"; |
| +template <> const char *InstX86BaseOr::Opcode = "or"; |
| +template <> const char *InstX86BaseOrRMW::Opcode = "or"; |
| +template <> const char *InstX86BasePor::Opcode = "por"; |
| +template <> const char *InstX86BaseXor::Opcode = "xor"; |
| +template <> const char *InstX86BaseXorRMW::Opcode = "xor"; |
| +template <> const char *InstX86BasePxor::Opcode = "pxor"; |
| +template <> const char *InstX86BaseImul::Opcode = "imul"; |
| +template <> const char *InstX86BaseMulps::Opcode = "mulps"; |
| +template <> const char *InstX86BaseMulss::Opcode = "mulss"; |
| +template <> const char *InstX86BasePmull::Opcode = "pmull"; |
| +template <> const char *InstX86BasePmuludq::Opcode = "pmuludq"; |
| +template <> const char *InstX86BaseDiv::Opcode = "div"; |
| +template <> const char *InstX86BaseDivps::Opcode = "divps"; |
| +template <> const char *InstX86BaseIdiv::Opcode = "idiv"; |
| +template <> const char *InstX86BaseDivss::Opcode = "divss"; |
| +template <> const char *InstX86BaseRol::Opcode = "rol"; |
| +template <> const char *InstX86BaseShl::Opcode = "shl"; |
| +template <> const char *InstX86BasePsll::Opcode = "psll"; |
| +template <> const char *InstX86BaseShr::Opcode = "shr"; |
| +template <> const char *InstX86BaseSar::Opcode = "sar"; |
| +template <> const char *InstX86BasePsra::Opcode = "psra"; |
| +template <> const char *InstX86BasePsrl::Opcode = "psrl"; |
| +template <> const char *InstX86BasePcmpeq::Opcode = "pcmpeq"; |
| +template <> const char *InstX86BasePcmpgt::Opcode = "pcmpgt"; |
| +template <> const char *InstX86BaseMovssRegs::Opcode = "movss"; |
| +// Ternary ops |
| +template <> const char *InstX86BaseInsertps::Opcode = "insertps"; |
| +template <> const char *InstX86BaseShufps::Opcode = "shufps"; |
| +template <> const char *InstX86BasePinsr::Opcode = "pinsr"; |
| +template <> const char *InstX86BaseBlendvps::Opcode = "blendvps"; |
| +template <> const char *InstX86BasePblendvb::Opcode = "pblendvb"; |
| +// Three address ops |
| +template <> const char *InstX86BasePextr::Opcode = "pextr"; |
| +template <> const char *InstX86BasePshufd::Opcode = "pshufd"; |
| + |
| +// Inplace GPR ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp InstX86BaseBswap::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::bswap, nullptr /* only a reg form exists */ |
| +}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp InstX86BaseNeg::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::neg, &InstX86Base<Machine>::Traits::Assembler::neg}; |
|
jvoung (off chromium)
2015/07/06 18:58:45
wonder why clang-format doesn't move stuff to the
John
2015/07/06 22:30:09
Maybe?... :)
|
| + |
| +// Unary GPR ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseBsf::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::bsf, &InstX86Base<Machine>::Traits::Assembler::bsf, nullptr}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseBsr::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::bsr, &InstX86Base<Machine>::Traits::Assembler::bsr, nullptr}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseLea::Emitter = { |
| + /* reg/reg and reg/imm are illegal */ nullptr, &InstX86Base<Machine>::Traits::Assembler::lea, |
| + nullptr}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseMovsx::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::movsx, &InstX86Base<Machine>::Traits::Assembler::movsx, nullptr}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseMovzx::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::movzx, &InstX86Base<Machine>::Traits::Assembler::movzx, nullptr}; |
| + |
| +// Unary XMM ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSqrtss::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sqrtss, &InstX86Base<Machine>::Traits::Assembler::sqrtss}; |
| + |
| +// Binary GPR ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAdd::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::add, &InstX86Base<Machine>::Traits::Assembler::add, |
| + &InstX86Base<Machine>::Traits::Assembler::add}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAddRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::add, &InstX86Base<Machine>::Traits::Assembler::add}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAdc::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::adc, &InstX86Base<Machine>::Traits::Assembler::adc, |
| + &InstX86Base<Machine>::Traits::Assembler::adc}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAdcRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::adc, &InstX86Base<Machine>::Traits::Assembler::adc}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAnd::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::And, &InstX86Base<Machine>::Traits::Assembler::And, |
| + &InstX86Base<Machine>::Traits::Assembler::And}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAndRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::And, &InstX86Base<Machine>::Traits::Assembler::And}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseOr::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::Or, &InstX86Base<Machine>::Traits::Assembler::Or, |
| + &InstX86Base<Machine>::Traits::Assembler::Or}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseOrRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::Or, &InstX86Base<Machine>::Traits::Assembler::Or}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseSbb::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sbb, &InstX86Base<Machine>::Traits::Assembler::sbb, |
| + &InstX86Base<Machine>::Traits::Assembler::sbb}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseSbbRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sbb, &InstX86Base<Machine>::Traits::Assembler::sbb}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseSub::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sub, &InstX86Base<Machine>::Traits::Assembler::sub, |
| + &InstX86Base<Machine>::Traits::Assembler::sub}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseSubRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sub, &InstX86Base<Machine>::Traits::Assembler::sub}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseXor::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::Xor, &InstX86Base<Machine>::Traits::Assembler::Xor, |
| + &InstX86Base<Machine>::Traits::Assembler::Xor}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseXorRMW::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::Xor, &InstX86Base<Machine>::Traits::Assembler::Xor}; |
| + |
| +// Binary Shift GPR ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseRol::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::rol, &InstX86Base<Machine>::Traits::Assembler::rol}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseSar::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::sar, &InstX86Base<Machine>::Traits::Assembler::sar}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseShl::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::shl, &InstX86Base<Machine>::Traits::Assembler::shl}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseShr::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::shr, &InstX86Base<Machine>::Traits::Assembler::shr}; |
| + |
| +// Binary XMM ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseAddss::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::addss, &InstX86Base<Machine>::Traits::Assembler::addss}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseAddps::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::addps, &InstX86Base<Machine>::Traits::Assembler::addps}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseDivss::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::divss, &InstX86Base<Machine>::Traits::Assembler::divss}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseDivps::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::divps, &InstX86Base<Machine>::Traits::Assembler::divps}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseMulss::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::mulss, &InstX86Base<Machine>::Traits::Assembler::mulss}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseMulps::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::mulps, &InstX86Base<Machine>::Traits::Assembler::mulps}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePadd::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::padd, &InstX86Base<Machine>::Traits::Assembler::padd}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePand::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pand, &InstX86Base<Machine>::Traits::Assembler::pand}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePandn::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pandn, &InstX86Base<Machine>::Traits::Assembler::pandn}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePcmpeq::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pcmpeq, &InstX86Base<Machine>::Traits::Assembler::pcmpeq}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePcmpgt::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pcmpgt, &InstX86Base<Machine>::Traits::Assembler::pcmpgt}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePmull::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pmull, &InstX86Base<Machine>::Traits::Assembler::pmull}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePmuludq::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pmuludq, &InstX86Base<Machine>::Traits::Assembler::pmuludq}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePor::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::por, &InstX86Base<Machine>::Traits::Assembler::por}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePsub::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::psub, &InstX86Base<Machine>::Traits::Assembler::psub}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePxor::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::pxor, &InstX86Base<Machine>::Traits::Assembler::pxor}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSubss::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::subss, &InstX86Base<Machine>::Traits::Assembler::subss}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSubps::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::subps, &InstX86Base<Machine>::Traits::Assembler::subps}; |
| + |
| +// Binary XMM Shift ops |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsll::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::psll, &InstX86Base<Machine>::Traits::Assembler::psll, |
| + &InstX86Base<Machine>::Traits::Assembler::psll}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsra::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::psra, &InstX86Base<Machine>::Traits::Assembler::psra, |
| + &InstX86Base<Machine>::Traits::Assembler::psra}; |
| +template <> |
| +const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsrl::Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::psrl, &InstX86Base<Machine>::Traits::Assembler::psrl, |
| + &InstX86Base<Machine>::Traits::Assembler::psrl}; |
| +#endif // 0 |
| + |
| +template <class Machine> |
| +void InstX86BaseSqrtss<Machine>::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 << "\tsqrt" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString |
| + << "\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseAddss<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "add%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .SdSsString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePadd<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "padd%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePmull<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 || |
| + this->getDest()->getType() == IceType_v8i16; |
| + bool InstructionSetIsValid = |
| + this->getDest()->getType() == IceType_v8i16 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; |
| + (void)TypesAreValid; |
| + (void)InstructionSetIsValid; |
| + assert(TypesAreValid); |
| + assert(InstructionSetIsValid); |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "pmull%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePmull<Machine>::emitIAS(const Cfg *Func) const { |
| + Type Ty = this->getDest()->getType(); |
| + bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16; |
| + bool InstructionSetIsValid = |
| + Ty == IceType_v8i16 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; |
| + (void)TypesAreValid; |
| + (void)InstructionSetIsValid; |
| + assert(TypesAreValid); |
| + assert(InstructionSetIsValid); |
| + assert(this->getSrcSize() == 2); |
| + Type ElementTy = typeElementType(Ty); |
| + emitIASRegOpTyXMM<Machine>(Func, ElementTy, this->getDest(), this->getSrc(1), |
| + this->Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseSubss<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "sub%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .SdSsString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePsub<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "psub%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMulss<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "mul%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .SdSsString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePmuludq<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + assert(this->getSrc(0)->getType() == IceType_v4i32 && |
| + this->getSrc(1)->getType() == IceType_v4i32); |
| + this->emitTwoAddress(this->Opcode, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseDivss<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "div%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .SdSsString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseDiv<Machine>::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 <class Machine> |
| +void InstX86BaseDiv<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + const Operand *Src = this->getSrc(1); |
| + Type Ty = Src->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::div, |
| + &InstX86Base<Machine>::Traits::Assembler::div}; |
| + emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseIdiv<Machine>::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 <class Machine> |
| +void InstX86BaseIdiv<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + const Operand *Src = this->getSrc(1); |
| + Type Ty = Src->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::idiv, |
| + &InstX86Base<Machine>::Traits::Assembler::idiv}; |
| + emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); |
| +} |
| + |
| +// pblendvb and blendvps take xmm0 as a final implicit argument. |
| +template <class Machine> |
| +void emitVariableBlendInst(const char *Opcode, const Inst *Inst, |
| + const Cfg *Func) { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(Inst->getSrcSize() == 3); |
| + assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0); |
| + Str << "\t" << Opcode << "\t"; |
| + Inst->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + Inst->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void emitIASVariableBlendInst( |
| + const Inst *Inst, const Cfg *Func, |
| + const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + &Emitter) { |
| + assert(Inst->getSrcSize() == 3); |
| + assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0); |
| + const Variable *Dest = Inst->getDest(); |
| + const Operand *Src = Inst->getSrc(1); |
| + emitIASRegOpTyXMM<Machine>(Func, Dest->getType(), Dest, Src, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseBlendvps<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + emitVariableBlendInst<Machine>(this->Opcode, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseBlendvps<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps, |
| + &InstX86Base<Machine>::Traits::Assembler::blendvps}; |
| + emitIASVariableBlendInst<Machine>(this, Func, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePblendvb<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + emitVariableBlendInst<Machine>(this->Opcode, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePblendvb<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb, |
| + &InstX86Base<Machine>::Traits::Assembler::pblendvb}; |
| + emitIASVariableBlendInst<Machine>(this, Func, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseImul<Machine>::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<Variable>(this->getSrc(0)); |
| + (void)Src0Var; |
| + assert(Src0Var && |
| + Src0Var->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + Str << "\timulb\t"; |
| + this->getSrc(1)->emit(Func); |
| + } else if (llvm::isa<Constant>(this->getSrc(1))) { |
| + Str << "\timul" << this->getWidthString(Dest->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + Dest->emit(Func); |
| + } else { |
| + this->emitTwoAddress("imul", this, Func); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseImul<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + const Variable *Var = this->getDest(); |
| + Type Ty = Var->getType(); |
| + const Operand *Src = this->getSrc(1); |
| + if (isByteSizedArithType(Ty)) { |
| + // The 8-bit version of imul only allows the form "imul r/m8". |
| + const auto Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0)); |
| + (void)Src0Var; |
| + assert(Src0Var && |
| + Src0Var->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterOneOp Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::imul, |
| + &InstX86Base<Machine>::Traits::Assembler::imul}; |
| + emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter); |
| + } else { |
| + // We only use imul as a two-address instruction even though |
| + // there is a 3 operand version when one of the operands is a constant. |
| + assert(Var == this->getSrc(0)); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterRegOp Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::imul, |
| + &InstX86Base<Machine>::Traits::Assembler::imul, |
| + &InstX86Base<Machine>::Traits::Assembler::imul}; |
| + emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseInsertps<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + const Variable *Dest = this->getDest(); |
| + assert(Dest == this->getSrc(0)); |
| + Type Ty = Dest->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::insertps, |
| + &InstX86Base<Machine>::Traits::Assembler::insertps}; |
| + emitIASThreeOpImmOps< |
| + Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( |
| + Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCbwdq<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Operand *Src0 = this->getSrc(0); |
| + assert(llvm::isa<Variable>(Src0)); |
| + assert(llvm::cast<Variable>(Src0)->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + switch (Src0->getType()) { |
| + default: |
| + llvm_unreachable("unexpected source type!"); |
| + break; |
| + case IceType_i8: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + Str << "\tcbtw"; |
| + break; |
| + case IceType_i16: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| + Str << "\tcwtd"; |
| + break; |
| + case IceType_i32: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| + Str << "\tcltd"; |
| + break; |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCbwdq<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 1); |
| + Operand *Src0 = this->getSrc(0); |
| + assert(llvm::isa<Variable>(Src0)); |
| + assert(llvm::cast<Variable>(Src0)->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + switch (Src0->getType()) { |
| + default: |
| + llvm_unreachable("unexpected source type!"); |
| + break; |
| + case IceType_i8: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + Asm->cbw(); |
| + break; |
| + case IceType_i16: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| + Asm->cwd(); |
| + break; |
| + case IceType_i32: |
| + assert(this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| + Asm->cdq(); |
| + break; |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMul<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + assert(llvm::isa<Variable>(this->getSrc(0))); |
| + assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + assert( |
| + this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx? |
| + Str << "\tmul" << this->getWidthString(this->getDest()->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMul<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + assert(llvm::isa<Variable>(this->getSrc(0))); |
| + assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| + assert( |
| + this->getDest()->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx? |
| + const Operand *Src = this->getSrc(1); |
| + Type Ty = Src->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::mul, |
| + &InstX86Base<Machine>::Traits::Assembler::mul}; |
| + emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMul<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = mul." << this->getDest()->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShld<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Variable *Dest = this->getDest(); |
| + assert(this->getSrcSize() == 3); |
| + assert(Dest == this->getSrc(0)); |
| + Str << "\tshld" << this->getWidthString(Dest->getType()) << "\t"; |
| + if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) { |
| + (void)ShiftReg; |
| + assert(ShiftReg->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); |
| + Str << "%cl"; |
| + } else { |
| + this->getSrc(2)->emit(Func); |
| + } |
| + Str << ", "; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + Dest->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShld<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + assert(this->getDest() == this->getSrc(0)); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src1 = this->getSrc(1); |
| + const Operand *Src2 = this->getSrc(2); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterShiftD Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::shld, |
| + &InstX86Base<Machine>::Traits::Assembler::shld}; |
| + emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShld<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = shld." << this->getDest()->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShrd<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Variable *Dest = this->getDest(); |
| + assert(this->getSrcSize() == 3); |
| + assert(Dest == this->getSrc(0)); |
| + Str << "\tshrd" << this->getWidthString(Dest->getType()) << "\t"; |
| + if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) { |
| + (void)ShiftReg; |
| + assert(ShiftReg->getRegNum() == |
| + InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); |
| + Str << "%cl"; |
| + } else { |
| + this->getSrc(2)->emit(Func); |
| + } |
| + Str << ", "; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + Dest->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShrd<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + assert(this->getDest() == this->getSrc(0)); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src1 = this->getSrc(1); |
| + const Operand *Src2 = this->getSrc(2); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterShiftD Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::shrd, |
| + &InstX86Base<Machine>::Traits::Assembler::shrd}; |
| + emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShrd<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = shrd." << this->getDest()->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmov<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Variable *Dest = this->getDest(); |
| + Str << "\t"; |
| + assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); |
| + assert(this->getDest()->hasReg()); |
| + Str << "cmov" |
| + << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString |
| + << this->getWidthString(Dest->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + Dest->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmov<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); |
| + assert(this->getDest()->hasReg()); |
| + assert(this->getSrcSize() == 2); |
| + Operand *Src = this->getSrc(1); |
| + Type SrcTy = Src->getType(); |
| + assert(SrcTy == IceType_i16 || SrcTy == IceType_i32); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| + if (SrcVar->hasReg()) { |
| + Asm->cmov(SrcTy, Condition, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + this->getDest()->getRegNum()), |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + SrcVar->getRegNum())); |
| + } else { |
| + Asm->cmov( |
| + SrcTy, Condition, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + this->getDest()->getRegNum()), |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar)); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + Asm->cmov(SrcTy, Condition, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + this->getDest()->getRegNum()), |
| + Mem->toAsmAddress(Asm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmov<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "cmov" |
| + << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString |
| + << "."; |
| + Str << this->getDest()->getType() << " "; |
| + this->dumpDest(Func); |
| + Str << ", "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpps<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); |
| + Str << "\t"; |
| + Str << "cmp" |
| + << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString |
| + << "ps" |
| + << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpps<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 2); |
| + assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); |
| + // Assuming there isn't any load folding for cmpps, and vector constants |
| + // are not allowed in PNaCl. |
| + assert(llvm::isa<Variable>(this->getSrc(1))); |
| + const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); |
| + if (SrcVar->hasReg()) { |
| + Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + this->getDest()->getRegNum()), |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum()), |
| + Condition); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar); |
| + Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + this->getDest()->getRegNum()), |
| + SrcStackAddr, Condition); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpps<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); |
| + this->dumpDest(Func); |
| + Str << " = cmp" |
| + << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString |
| + << "ps" |
| + << "\t"; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 3); |
| + if (this->Locked) { |
| + Str << "\tlock"; |
| + } |
| + Str << "\tcmpxchg" << this->getWidthString(this->getSrc(0)->getType()) |
| + << "\t"; |
| + this->getSrc(2)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Type Ty = this->getSrc(0)->getType(); |
| + const auto Mem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(0)); |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + const typename InstX86Base<Machine>::Traits::Address Addr = |
| + Mem->toAsmAddress(Asm); |
| + const auto VarReg = llvm::cast<Variable>(this->getSrc(2)); |
| + assert(VarReg->hasReg()); |
| + const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + VarReg->getRegNum()); |
| + Asm->cmpxchg(Ty, Addr, Reg, this->Locked); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + if (this->Locked) { |
| + Str << "lock "; |
| + } |
| + Str << "cmpxchg." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg8b<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 5); |
| + if (this->Locked) { |
| + Str << "\tlock"; |
| + } |
| + Str << "\tcmpxchg8b\t"; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg8b<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 5); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + const auto Mem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(0)); |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + const typename InstX86Base<Machine>::Traits::Address Addr = |
| + Mem->toAsmAddress(Asm); |
| + Asm->cmpxchg8b(Addr, this->Locked); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCmpxchg8b<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + if (this->Locked) { |
| + Str << "lock "; |
| + } |
| + Str << "cmpxchg8b "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCvt<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Str << "\tcvt"; |
| + if (isTruncating()) |
| + Str << "t"; |
| + Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) |
| + ->getType()] |
| + .CvtString << "2" |
| + << InstX86Base< |
| + Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .CvtString << "\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCvt<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + Type DestTy = Dest->getType(); |
| + Type SrcTy = Src->getType(); |
| + switch (Variant) { |
| + case Si2ss: { |
| + assert(isScalarIntegerType(SrcTy)); |
| + assert(typeWidthInBytes(SrcTy) <= 4); |
| + assert(isScalarFloatingType(DestTy)); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template CastEmitterRegOp< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvtsi2ss, |
| + &InstX86Base<Machine>::Traits::Assembler::cvtsi2ss}; |
| + emitIASCastRegOp< |
| + Machine, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>( |
| + Func, DestTy, Dest, Src, Emitter); |
| + return; |
| + } |
| + case Tss2si: { |
| + assert(isScalarFloatingType(SrcTy)); |
| + assert(isScalarIntegerType(DestTy)); |
| + assert(typeWidthInBytes(DestTy) <= 4); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template CastEmitterRegOp< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvttss2si, |
| + &InstX86Base<Machine>::Traits::Assembler::cvttss2si}; |
| + emitIASCastRegOp< |
| + Machine, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( |
| + Func, SrcTy, Dest, Src, Emitter); |
| + return; |
| + } |
| + case Float2float: { |
| + assert(isScalarFloatingType(SrcTy)); |
| + assert(isScalarFloatingType(DestTy)); |
| + assert(DestTy != SrcTy); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float, |
| + &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float}; |
| + emitIASRegOpTyXMM<Machine>(Func, SrcTy, Dest, Src, Emitter); |
| + return; |
| + } |
| + case Dq2ps: { |
| + assert(isVectorIntegerType(SrcTy)); |
| + assert(isVectorFloatingType(DestTy)); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps, |
| + &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps}; |
| + emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter); |
| + return; |
| + } |
| + case Tps2dq: { |
| + assert(isVectorFloatingType(SrcTy)); |
| + assert(isVectorIntegerType(DestTy)); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::cvttps2dq, |
| + &InstX86Base<Machine>::Traits::Assembler::cvttps2dq}; |
| + emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter); |
| + return; |
| + } |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseCvt<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = cvt"; |
| + if (isTruncating()) |
| + Str << "t"; |
| + Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) |
| + ->getType()] |
| + .CvtString << "2" |
| + << InstX86Base< |
| + Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .CvtString << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseIcmp<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + Str << "\tcmp" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseIcmp<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + const Operand *Src0 = this->getSrc(0); |
| + const Operand *Src1 = this->getSrc(1); |
| + Type Ty = Src0->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
| + RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::cmp, |
| + &InstX86Base<Machine>::Traits::Assembler::cmp, |
| + &InstX86Base<Machine>::Traits::Assembler::cmp}; |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::cmp, |
| + &InstX86Base<Machine>::Traits::Assembler::cmp}; |
| + if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { |
| + if (SrcVar0->hasReg()) { |
| + emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter); |
| + return; |
| + } |
| + } |
| + emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseIcmp<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "cmp." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUcomiss<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + Str << "\tucomi" |
| + << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) |
| + ->getType()] |
| + .SdSsString << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUcomiss<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + // Currently src0 is always a variable by convention, to avoid having |
| + // two memory operands. |
| + assert(llvm::isa<Variable>(this->getSrc(0))); |
| + const auto Src0Var = llvm::cast<Variable>(this->getSrc(0)); |
| + Type Ty = Src0Var->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss, |
| + &InstX86Base<Machine>::Traits::Assembler::ucomiss}; |
| + emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUcomiss<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "ucomiss." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUD2<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 0); |
| + Str << "\tud2"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUD2<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->ud2(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseUD2<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "ud2"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseTest<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + Str << "\ttest" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseTest<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + const Operand *Src0 = this->getSrc(0); |
| + const Operand *Src1 = this->getSrc(1); |
| + Type Ty = Src0->getType(); |
| + // The Reg/Addr form of test is not encodeable. |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
| + RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::test, nullptr, |
| + &InstX86Base<Machine>::Traits::Assembler::test}; |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::test, |
| + &InstX86Base<Machine>::Traits::Assembler::test}; |
| + if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { |
| + if (SrcVar0->hasReg()) { |
| + emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter); |
| + return; |
| + } |
| + } |
| + llvm_unreachable("Nothing actually generates this so it's untested"); |
| + emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseTest<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "test." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMfence<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 0); |
| + Str << "\tmfence"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMfence<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->mfence(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMfence<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "mfence"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStore<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + Type Ty = this->getSrc(0)->getType(); |
| + Str << "\tmov" << this->getWidthString(Ty) |
| + << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(1)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStore<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + const Operand *Dest = this->getSrc(1); |
| + const Operand *Src = this->getSrc(0); |
| + Type DestTy = Dest->getType(); |
| + if (isScalarFloatingType(DestTy)) { |
| + // Src must be a register, since Dest is a Mem operand of some kind. |
| + const auto SrcVar = llvm::cast<Variable>(Src); |
| + assert(SrcVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum()); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (const auto DestVar = llvm::dyn_cast<Variable>(Dest)) { |
| + assert(!DestVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(DestVar)); |
| + Asm->movss(DestTy, StackAddr, SrcReg); |
| + } else { |
| + const auto DestMem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + Dest); |
| + assert(DestMem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + Asm->movss(DestTy, DestMem->toAsmAddress(Asm), SrcReg); |
| + } |
| + return; |
| + } else { |
| + assert(isScalarIntegerType(DestTy)); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::mov, |
| + &InstX86Base<Machine>::Traits::Assembler::mov}; |
| + emitIASAsAddrOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRAddrEmitter); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStore<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "mov." << this->getSrc(0)->getType() << " "; |
| + this->getSrc(1)->dump(Func); |
| + Str << ", "; |
| + this->getSrc(0)->dump(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreP<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + Str << "\tmovups\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(1)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreP<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 2); |
| + const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); |
| + const auto DestMem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(1)); |
| + assert(DestMem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + assert(SrcVar->hasReg()); |
| + Asm->movups(DestMem->toAsmAddress(Asm), |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreP<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "storep." << this->getSrc(0)->getType() << " "; |
| + this->getSrc(1)->dump(Func); |
| + Str << ", "; |
| + this->getSrc(0)->dump(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreQ<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + assert(this->getSrc(1)->getType() == IceType_i64 || |
| + this->getSrc(1)->getType() == IceType_f64); |
| + Str << "\tmovq\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(1)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreQ<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 2); |
| + const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); |
| + const auto DestMem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(1)); |
| + assert(DestMem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + assert(SrcVar->hasReg()); |
| + Asm->movq(DestMem->toAsmAddress(Asm), |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseStoreQ<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "storeq." << this->getSrc(0)->getType() << " "; |
| + this->getSrc(1)->dump(Func); |
| + Str << ", "; |
| + this->getSrc(0)->dump(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseLea<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + assert(this->getDest()->hasReg()); |
| + Str << "\tleal\t"; |
| + Operand *Src0 = this->getSrc(0); |
| + if (const auto Src0Var = llvm::dyn_cast<Variable>(Src0)) { |
| + Type Ty = Src0Var->getType(); |
| + // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an |
| + // acceptable type. |
| + Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty)->emit(Func); |
| + } else { |
| + Src0->emit(Func); |
| + } |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMov<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Operand *Src = this->getSrc(0); |
| + Type SrcTy = Src->getType(); |
| + Type DestTy = this->getDest()->getType(); |
| + Str << "\tmov" |
| + << (!isScalarFloatingType(DestTy) |
| + ? this->getWidthString(SrcTy) |
| + : InstX86Base<Machine>::Traits::TypeAttributes[DestTy].SdSsString) |
| + << "\t"; |
| + // For an integer truncation operation, src is wider than dest. |
| + // Ideally, we use a mov instruction whose data width matches the |
| + // narrower dest. This is a problem if e.g. src is a register like |
| + // esi or si where there is no 8-bit version of the register. To be |
| + // safe, we instead widen the dest to match src. This works even |
| + // for stack-allocated dest variables because typeWidthOnStack() |
| + // pads to a 4-byte boundary even if only a lower portion is used. |
| + // TODO: This assert disallows usages such as copying a floating point |
| + // value between a vector and a scalar (which movss is used for). |
| + // Clean this up. |
| + assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == |
| + Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); |
| + Src->emit(Func); |
| + Str << ", "; |
| + this->getDest()->asType(SrcTy)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMov<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + Type DestTy = Dest->getType(); |
| + Type SrcTy = Src->getType(); |
| + // Mov can be used for GPRs or XMM registers. Also, the type does not |
| + // necessarily match (Mov can be used for bitcasts). However, when |
| + // the type does not match, one of the operands must be a register. |
| + // Thus, the strategy is to find out if Src or Dest are a register, |
| + // then use that register's type to decide on which emitter set to use. |
| + // The emitter set will include reg-reg movs, but that case should |
| + // be unused when the types don't match. |
| + static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| + XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, |
| + &InstX86Base<Machine>::Traits::Assembler::movss}; |
| + static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
| + GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, |
| + &InstX86Base<Machine>::Traits::Assembler::mov, |
| + &InstX86Base<Machine>::Traits::Assembler::mov}; |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::mov, |
| + &InstX86Base<Machine>::Traits::Assembler::mov}; |
| + // For an integer truncation operation, src is wider than dest. |
| + // Ideally, we use a mov instruction whose data width matches the |
| + // narrower dest. This is a problem if e.g. src is a register like |
| + // esi or si where there is no 8-bit version of the register. To be |
| + // safe, we instead widen the dest to match src. This works even |
| + // for stack-allocated dest variables because typeWidthOnStack() |
| + // pads to a 4-byte boundary even if only a lower portion is used. |
| + // TODO: This assert disallows usages such as copying a floating point |
| + // value between a vector and a scalar (which movss is used for). |
| + // Clean this up. |
| + assert( |
| + Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == |
| + Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); |
| + if (Dest->hasReg()) { |
| + if (isScalarFloatingType(DestTy)) { |
| + emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); |
| + return; |
| + } else { |
| + assert(isScalarIntegerType(DestTy)); |
| + // Widen DestTy for truncation (see above note). We should only do this |
| + // when both Src and Dest are integer types. |
| + if (isScalarIntegerType(SrcTy)) { |
| + DestTy = SrcTy; |
| + } |
| + emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); |
| + return; |
| + } |
| + } else { |
| + // Dest must be Stack and Src *could* be a register. Use Src's type |
| + // to decide on the emitters. |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Dest)); |
| + if (isScalarFloatingType(SrcTy)) { |
| + // Src must be a register. |
| + const auto SrcVar = llvm::cast<Variable>(Src); |
| + assert(SrcVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler< |
| + typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->movss(SrcTy, StackAddr, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| + return; |
| + } else { |
| + // Src can be a register or immediate. |
| + assert(isScalarIntegerType(SrcTy)); |
| + emitIASAddrOpTyGPR<Machine>(Func, SrcTy, StackAddr, Src, GPRAddrEmitter); |
| + return; |
| + } |
| + return; |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovd<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 1); |
| + const Variable *Dest = this->getDest(); |
| + const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); |
| + // For insert/extract element (one of Src/Dest is an Xmm vector and |
| + // the other is an int type). |
| + if (SrcVar->getType() == IceType_i32) { |
| + assert(isVectorType(Dest->getType())); |
| + assert(Dest->hasReg()); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Dest->getRegNum()); |
| + if (SrcVar->hasReg()) { |
| + Asm->movd(DestReg, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + SrcVar->getRegNum())); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(SrcVar)); |
| + Asm->movd(DestReg, StackAddr); |
| + } |
| + } else { |
| + assert(isVectorType(SrcVar->getType())); |
| + assert(SrcVar->hasReg()); |
| + assert(Dest->getType() == IceType_i32); |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum()); |
| + if (Dest->hasReg()) { |
| + Asm->movd(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + Dest->getRegNum()), |
| + SrcReg); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Dest)); |
| + Asm->movd(StackAddr, SrcReg); |
| + } |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovp<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + // TODO(wala,stichnot): movups works with all vector operands, but |
| + // there exist other instructions (movaps, movdqa, movdqu) that may |
| + // perform better, depending on the data type and alignment of the |
| + // operands. |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Str << "\tmovups\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovp<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + assert(isVectorType(this->getDest()->getType())); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::movups, |
| + &InstX86Base<Machine>::Traits::Assembler::movups, |
| + &InstX86Base<Machine>::Traits::Assembler::movups}; |
| + emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovq<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + assert(this->getDest()->getType() == IceType_i64 || |
| + this->getDest()->getType() == IceType_f64); |
| + Str << "\tmovq\t"; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovq<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + assert(this->getDest()->getType() == IceType_i64 || |
| + this->getDest()->getType() == IceType_f64); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + static const typename InstX86Base< |
| + Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { |
| + &InstX86Base<Machine>::Traits::Assembler::movq, |
| + &InstX86Base<Machine>::Traits::Assembler::movq, |
| + &InstX86Base<Machine>::Traits::Assembler::movq}; |
| + emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovssRegs<Machine>::emitIAS(const Cfg *Func) const { |
| + // This is Binop variant is only intended to be used for reg-reg moves |
| + // where part of the Dest register is untouched. |
| + assert(this->getSrcSize() == 2); |
| + const Variable *Dest = this->getDest(); |
| + assert(Dest == this->getSrc(0)); |
| + const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); |
| + assert(Dest->hasReg() && SrcVar->hasReg()); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->movss(IceType_f32, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Dest->getRegNum()), |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + SrcVar->getRegNum())); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovsx<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + // Dest must be a > 8-bit register, but Src can be 8-bit. In practice |
| + // we just use the full register for Dest to avoid having an |
| + // OperandSizeOverride prefix. It also allows us to only dispatch on SrcTy. |
| + Type SrcTy = Src->getType(); |
| + assert(typeWidthInBytes(Dest->getType()) > 1); |
| + assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); |
| + emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, |
| + this->Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseMovzx<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + const Variable *Dest = this->getDest(); |
| + const Operand *Src = this->getSrc(0); |
| + Type SrcTy = Src->getType(); |
| + assert(typeWidthInBytes(Dest->getType()) > 1); |
| + assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); |
| + emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, |
| + this->Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseNop<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + // TODO: Emit the right code for each variant. |
| + Str << "\tnop\t# variant = " << Variant; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseNop<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + // TODO: Emit the right code for the variant. |
| + Asm->nop(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseNop<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "nop (variant = " << Variant << ")"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFld<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + Type Ty = this->getSrc(0)->getType(); |
| + SizeT Width = typeWidthInBytes(Ty); |
| + const auto Var = llvm::dyn_cast<Variable>(this->getSrc(0)); |
| + if (Var && Var->hasReg()) { |
| + // This is a physical xmm register, so we need to spill it to a |
| + // temporary stack slot. |
| + Str << "\tsubl\t$" << Width << ", %esp" |
| + << "\n"; |
| + Str << "\tmov" |
| + << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; |
| + Var->emit(Func); |
| + Str << ", (%esp)\n"; |
| + Str << "\tfld" << this->getFldString(Ty) << "\t" |
| + << "(%esp)\n"; |
| + Str << "\taddl\t$" << Width << ", %esp"; |
| + return; |
| + } |
| + Str << "\tfld" << this->getFldString(Ty) << "\t"; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFld<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 1); |
| + const Operand *Src = this->getSrc(0); |
| + Type Ty = Src->getType(); |
| + if (const auto Var = llvm::dyn_cast<Variable>(Src)) { |
| + if (Var->hasReg()) { |
| + // This is a physical xmm register, so we need to spill it to a |
| + // temporary stack slot. |
| + Immediate Width(typeWidthInBytes(Ty)); |
| + Asm->sub(IceType_i32, |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, |
| + Width); |
| + typename InstX86Base<Machine>::Traits::Address StackSlot = |
| + typename InstX86Base<Machine>::Traits::Address( |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); |
| + Asm->movss(Ty, StackSlot, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Var->getRegNum())); |
| + Asm->fld(Ty, StackSlot); |
| + Asm->add(IceType_i32, |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, |
| + Width); |
| + } else { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Var)); |
| + Asm->fld(Ty, StackAddr); |
| + } |
| + } else if (const auto Mem = llvm::dyn_cast< |
| + typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + Asm->fld(Ty, Mem->toAsmAddress(Asm)); |
| + } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) { |
| + Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm)); |
| + } else { |
| + llvm_unreachable("Unexpected operand type"); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFld<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "fld." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFstp<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 0); |
| + // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to |
| + // "partially" delete the fstp if the Dest is unused. |
| + // Even if Dest is unused, the fstp should be kept for the SideEffects |
| + // of popping the stack. |
| + if (!this->getDest()) { |
| + Str << "\tfstp\tst(0)"; |
| + return; |
| + } |
| + Type Ty = this->getDest()->getType(); |
| + size_t Width = typeWidthInBytes(Ty); |
| + if (!this->getDest()->hasReg()) { |
| + Str << "\tfstp" << this->getFldString(Ty) << "\t"; |
| + this->getDest()->emit(Func); |
| + return; |
| + } |
| + // Dest is a physical (xmm) register, so st(0) needs to go through |
| + // memory. Hack this by creating a temporary stack slot, spilling |
| + // st(0) there, loading it into the xmm register, and deallocating |
| + // the stack slot. |
| + Str << "\tsubl\t$" << Width << ", %esp\n"; |
| + Str << "\tfstp" << this->getFldString(Ty) << "\t" |
| + << "(%esp)\n"; |
| + Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString |
| + << "\t" |
| + << "(%esp), "; |
| + this->getDest()->emit(Func); |
| + Str << "\n"; |
| + Str << "\taddl\t$" << Width << ", %esp"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFstp<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + assert(this->getSrcSize() == 0); |
| + const Variable *Dest = this->getDest(); |
| + // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to |
| + // "partially" delete the fstp if the Dest is unused. |
| + // Even if Dest is unused, the fstp should be kept for the SideEffects |
| + // of popping the stack. |
| + if (!Dest) { |
| + Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0)); |
| + return; |
| + } |
| + Type Ty = Dest->getType(); |
| + if (!Dest->hasReg()) { |
| + typename InstX86Base<Machine>::Traits::Address StackAddr( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(Dest)); |
| + Asm->fstp(Ty, StackAddr); |
| + } else { |
| + // Dest is a physical (xmm) register, so st(0) needs to go through |
| + // memory. Hack this by creating a temporary stack slot, spilling |
| + // st(0) there, loading it into the xmm register, and deallocating |
| + // the stack slot. |
| + Immediate Width(typeWidthInBytes(Ty)); |
| + Asm->sub(IceType_i32, |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); |
| + typename InstX86Base<Machine>::Traits::Address StackSlot = |
| + typename InstX86Base<Machine>::Traits::Address( |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); |
| + Asm->fstp(Ty, StackSlot); |
| + Asm->movss(Ty, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
| + Dest->getRegNum()), |
| + StackSlot); |
| + Asm->add(IceType_i32, |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseFstp<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = fstp." << this->getDest()->getType() << ", st(0)"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePcmpeq<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "pcmpeq%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePcmpgt<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "pcmpgt%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePextr<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 2); |
| + // pextrb and pextrd are SSE4.1 instructions. |
| + assert(this->getSrc(0)->getType() == IceType_v8i16 || |
| + this->getSrc(0)->getType() == IceType_v8i1 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + Str << "\t" << this->Opcode |
| + << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) |
| + ->getType()] |
| + .PackString << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| + Str << ", "; |
| + Variable *Dest = this->getDest(); |
| + // pextrw must take a register dest. There is an SSE4.1 version that takes |
| + // a memory dest, but we aren't using it. For uniformity, just restrict |
| + // them all to have a register dest for now. |
| + assert(Dest->hasReg()); |
| + Dest->asType(IceType_i32)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePextr<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + // pextrb and pextrd are SSE4.1 instructions. |
| + const Variable *Dest = this->getDest(); |
| + Type DispatchTy = Dest->getType(); |
| + assert(DispatchTy == IceType_i16 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + // pextrw must take a register dest. There is an SSE4.1 version that takes |
| + // a memory dest, but we aren't using it. For uniformity, just restrict |
| + // them all to have a register dest for now. |
| + assert(Dest->hasReg()); |
| + // pextrw's Src(0) must be a register (both SSE4.1 and SSE2). |
| + assert(llvm::cast<Variable>(this->getSrc(0))->hasReg()); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr}; |
| + emitIASThreeOpImmOps< |
| + Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( |
| + Func, DispatchTy, Dest, this->getSrc(0), this->getSrc(1), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePinsr<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 3); |
| + // pinsrb and pinsrd are SSE4.1 instructions. |
| + assert(this->getDest()->getType() == IceType_v8i16 || |
| + this->getDest()->getType() == IceType_v8i1 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + Str << "\t" << this->Opcode |
| + << InstX86Base< |
| + Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString << "\t"; |
| + this->getSrc(2)->emit(Func); |
| + Str << ", "; |
| + Operand *Src1 = this->getSrc(1); |
| + if (const auto Src1Var = llvm::dyn_cast<Variable>(Src1)) { |
| + // If src1 is a register, it should always be r32. |
| + if (Src1Var->hasReg()) { |
| + Src1Var->asType(IceType_i32)->emit(Func); |
| + } else { |
| + Src1Var->emit(Func); |
| + } |
| + } else { |
| + Src1->emit(Func); |
| + } |
| + Str << ", "; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePinsr<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + assert(this->getDest() == this->getSrc(0)); |
| + // pinsrb and pinsrd are SSE4.1 instructions. |
| + const Operand *Src0 = this->getSrc(1); |
| + Type DispatchTy = Src0->getType(); |
| + assert(DispatchTy == IceType_i16 || |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
| + // If src1 is a register, it should always be r32 (this should fall out |
| + // from the encodings for ByteRegs overlapping the encodings for r32), |
| + // but we have to trust the regalloc to not choose "ah", where it |
| + // doesn't overlap. |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr, |
| + &InstX86Base<Machine>::Traits::Assembler::pinsr}; |
| + emitIASThreeOpImmOps< |
| + Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>( |
| + Func, DispatchTy, this->getDest(), Src0, this->getSrc(2), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePshufd<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + const Variable *Dest = this->getDest(); |
| + Type Ty = Dest->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::pshufd, |
| + &InstX86Base<Machine>::Traits::Assembler::pshufd}; |
| + emitIASThreeOpImmOps< |
| + Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( |
| + Func, Ty, Dest, this->getSrc(0), this->getSrc(1), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseShufps<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 3); |
| + const Variable *Dest = this->getDest(); |
| + assert(Dest == this->getSrc(0)); |
| + Type Ty = Dest->getType(); |
| + static const typename InstX86Base<Machine>::Traits::Assembler:: |
| + template ThreeOpImmEmitter< |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
| + Emitter = {&InstX86Base<Machine>::Traits::Assembler::shufps, |
| + &InstX86Base<Machine>::Traits::Assembler::shufps}; |
| + emitIASThreeOpImmOps< |
| + Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( |
| + Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePop<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 0); |
| + Str << "\tpop\t"; |
| + this->getDest()->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePop<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 0); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (this->getDest()->hasReg()) { |
| + Asm->popl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + this->getDest()->getRegNum())); |
| + } else { |
| + Asm->popl( |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(this->getDest())); |
| + } |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePop<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + this->dumpDest(Func); |
| + Str << " = pop." << this->getDest()->getType() << " "; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseAdjustStack<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << "\tsubl\t$" << Amount << ", %esp"; |
| + Func->getTarget()->updateStackAdjustment(Amount); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseAdjustStack<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->sub(IceType_i32, |
| + InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, |
| + Immediate(Amount)); |
| + Func->getTarget()->updateStackAdjustment(Amount); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseAdjustStack<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "esp = sub.i32 esp, " << Amount; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePush<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + assert(this->getSrcSize() == 1); |
| + // Push is currently only used for saving GPRs. |
| + const auto Var = llvm::cast<Variable>(this->getSrc(0)); |
| + assert(Var->hasReg()); |
| + Str << "\tpush\t"; |
| + Var->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePush<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 1); |
| + // Push is currently only used for saving GPRs. |
| + const auto Var = llvm::cast<Variable>(this->getSrc(0)); |
| + assert(Var->hasReg()); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->pushl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + Var->getRegNum())); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePush<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "push." << this->getSrc(0)->getType() << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePsll<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + assert(this->getDest()->getType() == IceType_v8i16 || |
| + this->getDest()->getType() == IceType_v8i1 || |
| + this->getDest()->getType() == IceType_v4i32 || |
| + this->getDest()->getType() == IceType_v4i1); |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "psll%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePsra<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + assert(this->getDest()->getType() == IceType_v8i16 || |
| + this->getDest()->getType() == IceType_v8i1 || |
| + this->getDest()->getType() == IceType_v4i32 || |
| + this->getDest()->getType() == IceType_v4i1); |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "psra%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BasePsrl<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + char buf[30]; |
| + snprintf( |
| + buf, llvm::array_lengthof(buf), "psrl%s", |
| + InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] |
| + .PackString); |
| + this->emitTwoAddress(buf, this, Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseRet<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << "\tret"; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseRet<Machine>::emitIAS(const Cfg *Func) const { |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Asm->ret(); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseRet<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Type Ty = |
| + (this->getSrcSize() == 0 ? IceType_void : this->getSrc(0)->getType()); |
| + Str << "ret." << Ty << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseSetcc<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << "\tset" |
| + << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString |
| + << "\t"; |
| + this->Dest->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseSetcc<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); |
| + assert(this->getDest()->getType() == IceType_i1); |
| + assert(this->getSrcSize() == 0); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + if (this->getDest()->hasReg()) |
| + Asm->setcc(Condition, |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteReg( |
| + this->getDest()->getRegNum())); |
| + else |
| + Asm->setcc( |
| + Condition, |
| + static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| + Func->getTarget()) |
| + ->stackVarToAsmOperand(this->getDest())); |
| + return; |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseSetcc<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Str << "setcc." |
| + << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString |
| + << " "; |
| + this->dumpDest(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXadd<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + if (this->Locked) { |
| + Str << "\tlock"; |
| + } |
| + Str << "\txadd" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXadd<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Type Ty = this->getSrc(0)->getType(); |
| + const auto Mem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(0)); |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + const typename InstX86Base<Machine>::Traits::Address Addr = |
| + Mem->toAsmAddress(Asm); |
| + const auto VarReg = llvm::cast<Variable>(this->getSrc(1)); |
| + assert(VarReg->hasReg()); |
| + const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + VarReg->getRegNum()); |
| + Asm->xadd(Ty, Addr, Reg, this->Locked); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXadd<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + if (this->Locked) { |
| + Str << "lock "; |
| + } |
| + Type Ty = this->getSrc(0)->getType(); |
| + Str << "xadd." << Ty << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXchg<Machine>::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + Str << "\txchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; |
| + this->getSrc(1)->emit(Func); |
| + Str << ", "; |
| + this->getSrc(0)->emit(Func); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXchg<Machine>::emitIAS(const Cfg *Func) const { |
| + assert(this->getSrcSize() == 2); |
| + typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| + Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| + Type Ty = this->getSrc(0)->getType(); |
| + const auto Mem = |
| + llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( |
| + this->getSrc(0)); |
| + assert(Mem->getSegmentRegister() == |
| + InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
| + const typename InstX86Base<Machine>::Traits::Address Addr = |
| + Mem->toAsmAddress(Asm); |
| + const auto VarReg = llvm::cast<Variable>(this->getSrc(1)); |
| + assert(VarReg->hasReg()); |
| + const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = |
| + InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
| + VarReg->getRegNum()); |
| + Asm->xchg(Ty, Addr, Reg); |
| +} |
| + |
| +template <class Machine> |
| +void InstX86BaseXchg<Machine>::dump(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Type Ty = this->getSrc(0)->getType(); |
| + Str << "xchg." << Ty << " "; |
| + this->dumpSources(Func); |
| +} |
| + |
| +} // end of namespace X86Internal |
| + |
| +} // end of namespace Ice |
| + |
| +#endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H |