blob: a4830eff673f5b2255e65af9a3d27d89e4eb172f [file] [log] [blame]
//===- subzero/src/IceInstX86Base.h - Generic x86 instructions -*- C++ -*--===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the InstX86Base template class, as well as the generic X86
/// Instruction class hierarchy. Only X86 instructions common across all/most
/// X86 targets should be defined here, with target-specific instructions
/// declared in the target's traits.
///
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEINSTX86BASE_H
#define SUBZERO_SRC_ICEINSTX86BASE_H
#include "IceDefs.h"
#include "IceInst.h"
#include "IceOperand.h"
namespace Ice {
namespace X86Internal {
template <class Machine> struct MachineTraits;
template <class Machine> class InstX86Base : public InstTarget {
InstX86Base<Machine>() = delete;
InstX86Base<Machine>(const InstX86Base &) = delete;
InstX86Base &operator=(const InstX86Base &) = delete;
public:
using Traits = MachineTraits<Machine>;
enum InstKindX86 {
k__Start = Inst::Target,
Adc,
AdcRMW,
Add,
AddRMW,
Addps,
Addss,
Adjuststack,
And,
AndRMW,
Blendvps,
Br,
Bsf,
Bsr,
Bswap,
Call,
Cbwdq,
Cmov,
Cmpps,
Cmpxchg,
Cmpxchg8b,
Cvt,
Div,
Divps,
Divss,
FakeRMW,
Fld,
Fstp,
Icmp,
Idiv,
Imul,
Insertps,
Jmp,
Label,
Lea,
Load,
Mfence,
Mov,
Movd,
Movp,
Movq,
MovssRegs,
Movsx,
Movzx,
Mul,
Mulps,
Mulss,
Neg,
Nop,
Or,
OrRMW,
Padd,
Pand,
Pandn,
Pblendvb,
Pcmpeq,
Pcmpgt,
Pextr,
Pinsr,
Pmull,
Pmuludq,
Pop,
Por,
Pshufd,
Psll,
Psra,
Psrl,
Psub,
Push,
Pxor,
Ret,
Rol,
Sar,
Sbb,
SbbRMW,
Setcc,
Shl,
Shld,
Shr,
Shrd,
Shufps,
Sqrtss,
Store,
StoreP,
StoreQ,
Sub,
SubRMW,
Subps,
Subss,
Test,
Ucomiss,
UD2,
Xadd,
Xchg,
Xor,
XorRMW
};
static const char *getWidthString(Type Ty);
static const char *getFldString(Type Ty);
static typename Traits::Cond::BrCond
getOppositeCondition(typename Traits::Cond::BrCond Cond);
void dump(const Cfg *Func) const override;
// Shared emit routines for common forms of instructions.
// See the definition of emitTwoAddress() for a description of
// ShiftHack.
static void emitTwoAddress(const char *Opcode, const Inst *Inst,
const Cfg *Func, bool ShiftHack = false);
static void
emitIASGPRShift(const Cfg *Func, Type Ty, const Variable *Var,
const Operand *Src,
const typename Traits::Assembler::GPREmitterShiftOp &Emitter);
protected:
InstX86Base<Machine>(Cfg *Func, InstKindX86 Kind, SizeT Maxsrcs,
Variable *Dest)
: InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
static bool isClassof(const Inst *Inst, InstKindX86 MyKind) {
return Inst->getKind() == static_cast<InstKind>(MyKind);
}
// Most instructions that operate on vector arguments require vector
// memory operands to be fully aligned (16-byte alignment for PNaCl
// vector types). The stack frame layout and call ABI ensure proper
// alignment for stack operands, but memory operands (originating
// from load/store bitcode instructions) only have element-size
// alignment guarantees. This function validates that none of the
// operands is a memory operand of vector type, calling
// report_fatal_error() if one is found. This function should be
// called during emission, and maybe also in the ctor (as long as
// that fits the lowering style).
void validateVectorAddrMode() const {
if (this->getDest())
this->validateVectorAddrModeOpnd(this->getDest());
for (SizeT i = 0; i < this->getSrcSize(); ++i) {
this->validateVectorAddrModeOpnd(this->getSrc(i));
}
}
private:
static void validateVectorAddrModeOpnd(const Operand *Opnd) {
if (llvm::isa<typename InstX86Base<Machine>::Traits::X86OperandMem>(Opnd) &&
isVectorType(Opnd->getType())) {
llvm::report_fatal_error("Possible misaligned vector memory operation");
}
}
};
/// InstX86FakeRMW represents a non-atomic read-modify-write operation on a
/// memory location. An InstX86FakeRMW is a "fake" instruction in that it
/// still needs to be lowered to some actual RMW instruction.
///
/// If A is some memory address, D is some data value to apply, and OP is an
/// arithmetic operator, the instruction operates as: (*A) = (*A) OP D
template <class Machine>
class InstX86FakeRMW final : public InstX86Base<Machine> {
InstX86FakeRMW() = delete;
InstX86FakeRMW(const InstX86FakeRMW &) = delete;
InstX86FakeRMW &operator=(const InstX86FakeRMW &) = delete;
public:
static InstX86FakeRMW *create(Cfg *Func, Operand *Data, Operand *Addr,
Variable *Beacon, InstArithmetic::OpKind Op,
uint32_t Align = 1) {
// TODO(stichnot): Stop ignoring alignment specification.
(void)Align;
return new (Func->allocate<InstX86FakeRMW>())
InstX86FakeRMW(Func, Data, Addr, Op, Beacon);
}
Operand *getAddr() const { return this->getSrc(1); }
Operand *getData() const { return this->getSrc(0); }
InstArithmetic::OpKind getOp() const { return Op; }
Variable *getBeacon() const { return llvm::cast<Variable>(this->getSrc(2)); }
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::FakeRMW);
}
private:
InstArithmetic::OpKind Op;
InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
InstArithmetic::OpKind Op, Variable *Beacon);
};
/// InstX86Label represents an intra-block label that is the target
/// of an intra-block branch. The offset between the label and the
/// branch must be fit into one byte (considered "near"). These are
/// used for lowering i1 calculations, Select instructions, and 64-bit
/// compares on a 32-bit architecture, without basic block splitting.
/// Basic block splitting is not so desirable for several reasons, one
/// of which is the impact on decisions based on whether a variable's
/// live range spans multiple basic blocks.
///
/// Intra-block control flow must be used with caution. Consider the
/// sequence for "c = (a >= b ? x : y)".
/// cmp a, b
/// br lt, L1
/// mov c, x
/// jmp L2
/// L1:
/// mov c, y
/// L2:
///
/// Labels L1 and L2 are intra-block labels. Without knowledge of the
/// intra-block control flow, liveness analysis will determine the "mov
/// c, x" instruction to be dead. One way to prevent this is to insert
/// a "FakeUse(c)" instruction anywhere between the two "mov c, ..."
/// instructions, e.g.:
///
/// cmp a, b
/// br lt, L1
/// mov c, x
/// jmp L2
/// FakeUse(c)
/// L1:
/// mov c, y
/// L2:
///
/// The down-side is that "mov c, x" can never be dead-code eliminated
/// even if there are no uses of c. As unlikely as this situation is,
/// it may be prevented by running dead code elimination before
/// lowering.
template <class Machine>
class InstX86Label final : public InstX86Base<Machine> {
InstX86Label() = delete;
InstX86Label(const InstX86Label &) = delete;
InstX86Label &operator=(const InstX86Label &) = delete;
public:
static InstX86Label *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::TargetLowering *Target) {
return new (Func->allocate<InstX86Label>()) InstX86Label(Func, Target);
}
uint32_t getEmitInstCount() const override { return 0; }
IceString getName(const Cfg *Func) const;
SizeT getNumber() const { return Number; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
private:
InstX86Label(Cfg *Func,
typename InstX86Base<Machine>::Traits::TargetLowering *Target);
SizeT Number; // used for unique label generation.
};
/// Conditional and unconditional branch instruction.
template <class Machine> class InstX86Br final : public InstX86Base<Machine> {
InstX86Br() = delete;
InstX86Br(const InstX86Br &) = delete;
InstX86Br &operator=(const InstX86Br &) = delete;
public:
/// Create a conditional branch to a node.
static InstX86Br *
create(Cfg *Func, CfgNode *TargetTrue, CfgNode *TargetFalse,
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) {
assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
const InstX86Label<Machine> *NoLabel = nullptr;
return new (Func->allocate<InstX86Br>())
InstX86Br(Func, TargetTrue, TargetFalse, NoLabel, Condition);
}
/// Create an unconditional branch to a node.
static InstX86Br *create(Cfg *Func, CfgNode *Target) {
const CfgNode *NoCondTarget = nullptr;
const InstX86Label<Machine> *NoLabel = nullptr;
return new (Func->allocate<InstX86Br>())
InstX86Br(Func, NoCondTarget, Target, NoLabel,
InstX86Base<Machine>::Traits::Cond::Br_None);
}
/// Create a non-terminator conditional branch to a node, with a
/// fallthrough to the next instruction in the current node. This is
/// used for switch lowering.
static InstX86Br *
create(Cfg *Func, CfgNode *Target,
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) {
assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
const CfgNode *NoUncondTarget = nullptr;
const InstX86Label<Machine> *NoLabel = nullptr;
return new (Func->allocate<InstX86Br>())
InstX86Br(Func, Target, NoUncondTarget, NoLabel, Condition);
}
/// Create a conditional intra-block branch (or unconditional, if
/// Condition==Br_None) to a label in the current block.
static InstX86Br *
create(Cfg *Func, InstX86Label<Machine> *Label,
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) {
const CfgNode *NoCondTarget = nullptr;
const CfgNode *NoUncondTarget = nullptr;
return new (Func->allocate<InstX86Br>())
InstX86Br(Func, NoCondTarget, NoUncondTarget, Label, Condition);
}
const CfgNode *getTargetTrue() const { return TargetTrue; }
const CfgNode *getTargetFalse() const { return TargetFalse; }
bool optimizeBranch(const CfgNode *NextNode);
uint32_t getEmitInstCount() const override {
uint32_t Sum = 0;
if (Label)
++Sum;
if (getTargetTrue())
++Sum;
if (getTargetFalse())
++Sum;
return Sum;
}
bool isUnconditionalBranch() const override {
return !Label && Condition == InstX86Base<Machine>::Traits::Cond::Br_None;
}
bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override;
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Br);
}
private:
InstX86Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
const InstX86Label<Machine> *Label,
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition);
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition;
const CfgNode *TargetTrue;
const CfgNode *TargetFalse;
const InstX86Label<Machine> *Label; // Intra-block branch target
};
/// Jump to a target outside this function, such as tailcall, nacljump,
/// naclret, unreachable. This is different from a Branch instruction
/// in that there is no intra-function control flow to represent.
template <class Machine> class InstX86Jmp final : public InstX86Base<Machine> {
InstX86Jmp() = delete;
InstX86Jmp(const InstX86Jmp &) = delete;
InstX86Jmp &operator=(const InstX86Jmp &) = delete;
public:
static InstX86Jmp *create(Cfg *Func, Operand *Target) {
return new (Func->allocate<InstX86Jmp>()) InstX86Jmp(Func, Target);
}
Operand *getJmpTarget() const { return this->getSrc(0); }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Jmp);
}
private:
InstX86Jmp(Cfg *Func, Operand *Target);
};
/// AdjustStack instruction - subtracts esp by the given amount and
/// updates the stack offset during code emission.
template <class Machine>
class InstX86AdjustStack final : public InstX86Base<Machine> {
InstX86AdjustStack() = delete;
InstX86AdjustStack(const InstX86AdjustStack &) = delete;
InstX86AdjustStack &operator=(const InstX86AdjustStack &) = delete;
public:
static InstX86AdjustStack *create(Cfg *Func, SizeT Amount, Variable *Esp) {
return new (Func->allocate<InstX86AdjustStack>())
InstX86AdjustStack(Func, Amount, Esp);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst,
InstX86Base<Machine>::Adjuststack);
}
private:
InstX86AdjustStack(Cfg *Func, SizeT Amount, Variable *Esp);
SizeT Amount;
};
/// Call instruction. Arguments should have already been pushed.
template <class Machine> class InstX86Call final : public InstX86Base<Machine> {
InstX86Call() = delete;
InstX86Call(const InstX86Call &) = delete;
InstX86Call &operator=(const InstX86Call &) = delete;
public:
static InstX86Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) {
return new (Func->allocate<InstX86Call>())
InstX86Call(Func, Dest, CallTarget);
}
Operand *getCallTarget() const { return this->getSrc(0); }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Call);
}
private:
InstX86Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
};
/// Emit a one-operand (GPR) instruction.
template <class Machine>
void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Var,
const typename InstX86Base<
Machine>::Traits::Assembler::GPREmitterOneOp &Emitter);
template <class Machine>
void emitIASAsAddrOpTyGPR(
const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
&Emitter);
/// Instructions of the form x := op(x).
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseInplaceopGPR : public InstX86Base<Machine> {
InstX86BaseInplaceopGPR() = delete;
InstX86BaseInplaceopGPR(const InstX86BaseInplaceopGPR &) = delete;
InstX86BaseInplaceopGPR &operator=(const InstX86BaseInplaceopGPR &) = delete;
public:
using Base = InstX86BaseInplaceopGPR<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 1);
Str << "\t" << Opcode << "\t";
this->getSrc(0)->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
assert(this->getSrcSize() == 1);
const Variable *Var = this->getDest();
Type Ty = Var->getType();
emitIASOpTyGPR<Machine>(Func, Ty, Var, Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseInplaceopGPR(Cfg *Func, Operand *SrcDest)
: InstX86Base<Machine>(Func, K, 1, llvm::dyn_cast<Variable>(SrcDest)) {
this->addSource(SrcDest);
}
private:
static const char *Opcode;
static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
Emitter;
};
/// Emit a two-operand (GPR) instruction, where the dest operand is a
/// Variable that's guaranteed to be a register.
template <class Machine, bool VarCanBeByte = true, bool SrcCanBeByte = true>
void emitIASRegOpTyGPR(
const Cfg *Func, Type Ty, const Variable *Dst, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
&Emitter);
/// Instructions of the form x := op(y).
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseUnaryopGPR : public InstX86Base<Machine> {
InstX86BaseUnaryopGPR() = delete;
InstX86BaseUnaryopGPR(const InstX86BaseUnaryopGPR &) = delete;
InstX86BaseUnaryopGPR &operator=(const InstX86BaseUnaryopGPR &) = delete;
public:
using Base = InstX86BaseUnaryopGPR<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 1);
Type SrcTy = this->getSrc(0)->getType();
Type DestTy = this->getDest()->getType();
Str << "\t" << Opcode << this->getWidthString(SrcTy);
// Movsx and movzx need both the source and dest type width letter
// to define the operation. The other unary operations have the
// same source and dest type and as a result need only one letter.
if (SrcTy != DestTy)
Str << this->getWidthString(DestTy);
Str << "\t";
this->getSrc(0)->emit(Func);
Str << ", ";
this->getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
assert(this->getSrcSize() == 1);
const Variable *Var = this->getDest();
Type Ty = Var->getType();
const Operand *Src = this->getSrc(0);
emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getSrc(0)->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseUnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86Base<Machine>(Func, K, 1, Dest) {
this->addSource(Src);
}
static const char *Opcode;
static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
Emitter;
};
template <class Machine>
void emitIASRegOpTyXMM(
const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
&Emitter);
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseUnaryopXmm : public InstX86Base<Machine> {
InstX86BaseUnaryopXmm() = delete;
InstX86BaseUnaryopXmm(const InstX86BaseUnaryopXmm &) = delete;
InstX86BaseUnaryopXmm &operator=(const InstX86BaseUnaryopXmm &) = delete;
public:
using Base = InstX86BaseUnaryopXmm<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 1);
Str << "\t" << Opcode << "\t";
this->getSrc(0)->emit(Func);
Str << ", ";
this->getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = this->getDest()->getType();
assert(this->getSrcSize() == 1);
emitIASRegOpTyXMM<Machine>(Func, Ty, this->getDest(), this->getSrc(0),
Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseUnaryopXmm(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86Base<Machine>(Func, K, 1, Dest) {
this->addSource(Src);
}
static const char *Opcode;
static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
Emitter;
};
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseBinopGPRShift : public InstX86Base<Machine> {
InstX86BaseBinopGPRShift() = delete;
InstX86BaseBinopGPRShift(const InstX86BaseBinopGPRShift &) = delete;
InstX86BaseBinopGPRShift &
operator=(const InstX86BaseBinopGPRShift &) = delete;
public:
using Base = InstX86BaseBinopGPRShift<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = true;
this->emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = this->getDest()->getType();
assert(this->getSrcSize() == 2);
this->emitIASGPRShift(Func, Ty, this->getDest(), this->getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseBinopGPRShift(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86Base<Machine>(Func, K, 2, Dest) {
this->addSource(Dest);
this->addSource(Source);
}
static const char *Opcode;
static const typename InstX86Base<
Machine>::Traits::Assembler::GPREmitterShiftOp Emitter;
};
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseBinopGPR : public InstX86Base<Machine> {
InstX86BaseBinopGPR() = delete;
InstX86BaseBinopGPR(const InstX86BaseBinopGPR &) = delete;
InstX86BaseBinopGPR &operator=(const InstX86BaseBinopGPR &) = delete;
public:
using Base = InstX86BaseBinopGPR<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = false;
this->emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = this->getDest()->getType();
assert(this->getSrcSize() == 2);
emitIASRegOpTyGPR<Machine>(Func, Ty, this->getDest(), this->getSrc(1),
Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseBinopGPR(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86Base<Machine>(Func, K, 2, Dest) {
this->addSource(Dest);
this->addSource(Source);
}
static const char *Opcode;
static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
Emitter;
};
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseBinopRMW : public InstX86Base<Machine> {
InstX86BaseBinopRMW() = delete;
InstX86BaseBinopRMW(const InstX86BaseBinopRMW &) = delete;
InstX86BaseBinopRMW &operator=(const InstX86BaseBinopRMW &) = delete;
public:
using Base = InstX86BaseBinopRMW<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = false;
this->emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = this->getSrc(0)->getType();
assert(this->getSrcSize() == 2);
emitIASAsAddrOpTyGPR<Machine>(Func, Ty, this->getSrc(0), this->getSrc(1),
Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << Opcode << "." << this->getSrc(0)->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseBinopRMW(
Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86Base<Machine>(Func, K, 2, nullptr) {
this->addSource(DestSrc0);
this->addSource(Src1);
}
static const char *Opcode;
static const typename InstX86Base<
Machine>::Traits::Assembler::GPREmitterAddrOp Emitter;
};
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K,
bool NeedsElementType>
class InstX86BaseBinopXmm : public InstX86Base<Machine> {
InstX86BaseBinopXmm() = delete;
InstX86BaseBinopXmm(const InstX86BaseBinopXmm &) = delete;
InstX86BaseBinopXmm &operator=(const InstX86BaseBinopXmm &) = delete;
public:
using Base = InstX86BaseBinopXmm<Machine, K, NeedsElementType>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
this->validateVectorAddrMode();
const bool ShiftHack = false;
this->emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
this->validateVectorAddrMode();
Type Ty = this->getDest()->getType();
if (NeedsElementType)
Ty = typeElementType(Ty);
assert(this->getSrcSize() == 2);
emitIASRegOpTyXMM<Machine>(Func, Ty, this->getDest(), this->getSrc(1),
Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseBinopXmm(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86Base<Machine>(Func, K, 2, Dest) {
this->addSource(Dest);
this->addSource(Source);
}
static const char *Opcode;
static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
Emitter;
};
template <class Machine>
void emitIASXmmShift(
const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp
&Emitter);
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K,
bool AllowAllTypes = false>
class InstX86BaseBinopXmmShift : public InstX86Base<Machine> {
InstX86BaseBinopXmmShift() = delete;
InstX86BaseBinopXmmShift(const InstX86BaseBinopXmmShift &) = delete;
InstX86BaseBinopXmmShift &
operator=(const InstX86BaseBinopXmmShift &) = delete;
public:
using Base = InstX86BaseBinopXmmShift<Machine, K, AllowAllTypes>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
this->validateVectorAddrMode();
const bool ShiftHack = false;
this->emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
this->validateVectorAddrMode();
Type Ty = this->getDest()->getType();
assert(AllowAllTypes || isVectorType(Ty));
Type ElementTy = typeElementType(Ty);
assert(this->getSrcSize() == 2);
emitIASXmmShift<Machine>(Func, ElementTy, this->getDest(), this->getSrc(1),
Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseBinopXmmShift(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86Base<Machine>(Func, K, 2, Dest) {
this->addSource(Dest);
this->addSource(Source);
}
static const char *Opcode;
static const typename InstX86Base<
Machine>::Traits::Assembler::XmmEmitterShiftOp Emitter;
};
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseTernop : public InstX86Base<Machine> {
InstX86BaseTernop() = delete;
InstX86BaseTernop(const InstX86BaseTernop &) = delete;
InstX86BaseTernop &operator=(const InstX86BaseTernop &) = delete;
public:
using Base = InstX86BaseTernop<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 3);
Str << "\t" << Opcode << "\t";
this->getSrc(2)->emit(Func);
Str << ", ";
this->getSrc(1)->emit(Func);
Str << ", ";
this->getDest()->emit(Func);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseTernop(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2)
: InstX86Base<Machine>(Func, K, 3, Dest) {
this->addSource(Dest);
this->addSource(Source1);
this->addSource(Source2);
}
static const char *Opcode;
};
// Instructions of the form x := y op z
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseThreeAddressop : public InstX86Base<Machine> {
InstX86BaseThreeAddressop() = delete;
InstX86BaseThreeAddressop(const InstX86BaseThreeAddressop &) = delete;
InstX86BaseThreeAddressop &
operator=(const InstX86BaseThreeAddressop &) = delete;
public:
using Base = InstX86BaseThreeAddressop<Machine, K>;
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getSrcSize() == 2);
Str << "\t" << Opcode << "\t";
this->getSrc(1)->emit(Func);
Str << ", ";
this->getSrc(0)->emit(Func);
Str << ", ";
this->getDest()->emit(Func);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
this->dumpDest(Func);
Str << " = " << Opcode << "." << this->getDest()->getType() << " ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseThreeAddressop(Cfg *Func, Variable *Dest, Operand *Source0,
Operand *Source1)
: InstX86Base<Machine>(Func, K, 2, Dest) {
this->addSource(Source0);
this->addSource(Source1);
}
static const char *Opcode;
};
/// Base class for assignment instructions
template <class Machine, typename InstX86Base<Machine>::InstKindX86 K>
class InstX86BaseMovlike : public InstX86Base<Machine> {
InstX86BaseMovlike() = delete;
InstX86BaseMovlike(const InstX86BaseMovlike &) = delete;
InstX86BaseMovlike &operator=(const InstX86BaseMovlike &) = delete;
public:
using Base = InstX86BaseMovlike<Machine, K>;
bool isRedundantAssign() const override {
return checkForRedundantAssign(this->getDest(), this->getSrc(0));
}
bool isSimpleAssign() const override { return true; }
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << Opcode << "." << this->getDest()->getType() << " ";
this->dumpDest(Func);
Str << ", ";
this->dumpSources(Func);
}
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::K);
}
protected:
InstX86BaseMovlike(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86Base<Machine>(Func, K, 1, Dest) {
this->addSource(Source);
}
static const char *Opcode;
};
template <class Machine>
class InstX86Bswap
: public InstX86BaseInplaceopGPR<Machine, InstX86Base<Machine>::Bswap> {
public:
static InstX86Bswap *create(Cfg *Func, Operand *SrcDest) {
return new (Func->allocate<InstX86Bswap>()) InstX86Bswap(Func, SrcDest);
}
private:
InstX86Bswap(Cfg *Func, Operand *SrcDest)
: InstX86BaseInplaceopGPR<Machine, InstX86Base<Machine>::Bswap>(Func,
SrcDest) {
}
};
template <class Machine>
class InstX86Neg
: public InstX86BaseInplaceopGPR<Machine, InstX86Base<Machine>::Neg> {
public:
static InstX86Neg *create(Cfg *Func, Operand *SrcDest) {
return new (Func->allocate<InstX86Neg>()) InstX86Neg(Func, SrcDest);
}
private:
InstX86Neg(Cfg *Func, Operand *SrcDest)
: InstX86BaseInplaceopGPR<Machine, InstX86Base<Machine>::Neg>(Func,
SrcDest) {}
};
template <class Machine>
class InstX86Bsf
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Bsf> {
public:
static InstX86Bsf *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Bsf>()) InstX86Bsf(Func, Dest, Src);
}
private:
InstX86Bsf(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Bsf>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Bsr
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Bsr> {
public:
static InstX86Bsr *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Bsr>()) InstX86Bsr(Func, Dest, Src);
}
private:
InstX86Bsr(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Bsr>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Lea
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Lea> {
public:
static InstX86Lea *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Lea>()) InstX86Lea(Func, Dest, Src);
}
void emit(const Cfg *Func) const override;
private:
InstX86Lea(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Lea>(Func, Dest,
Src) {}
};
// Cbwdq instruction - wrapper for cbw, cwd, and cdq
template <class Machine>
class InstX86Cbwdq
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Cbwdq> {
public:
static InstX86Cbwdq *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Cbwdq>()) InstX86Cbwdq(Func, Dest, Src);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Cbwdq(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Cbwdq>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Movsx
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Movsx> {
public:
static InstX86Movsx *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Movsx>()) InstX86Movsx(Func, Dest, Src);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Movsx(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Movsx>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Movzx
: public InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Movzx> {
public:
static InstX86Movzx *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Movzx>()) InstX86Movzx(Func, Dest, Src);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Movzx(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopGPR<Machine, InstX86Base<Machine>::Movzx>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Movd
: public InstX86BaseUnaryopXmm<Machine, InstX86Base<Machine>::Movd> {
public:
static InstX86Movd *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Movd>()) InstX86Movd(Func, Dest, Src);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Movd(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopXmm<Machine, InstX86Base<Machine>::Movd>(Func, Dest,
Src) {}
};
template <class Machine>
class InstX86Sqrtss
: public InstX86BaseUnaryopXmm<Machine, InstX86Base<Machine>::Sqrtss> {
public:
static InstX86Sqrtss *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX86Sqrtss>()) InstX86Sqrtss(Func, Dest, Src);
}
virtual void emit(const Cfg *Func) const override;
private:
InstX86Sqrtss(Cfg *Func, Variable *Dest, Operand *Src)
: InstX86BaseUnaryopXmm<Machine, InstX86Base<Machine>::Sqrtss>(Func, Dest,
Src) {}
};
/// Move/assignment instruction - wrapper for mov/movss/movsd.
template <class Machine>
class InstX86Mov
: public InstX86BaseMovlike<Machine, InstX86Base<Machine>::Mov> {
public:
static InstX86Mov *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Mov>()) InstX86Mov(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Mov(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseMovlike<Machine, InstX86Base<Machine>::Mov>(Func, Dest,
Source) {}
};
/// Move packed - copy 128 bit values between XMM registers, or mem128
/// and XMM registers.
template <class Machine>
class InstX86Movp
: public InstX86BaseMovlike<Machine, InstX86Base<Machine>::Movp> {
public:
static InstX86Movp *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Movp>()) InstX86Movp(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Movp(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseMovlike<Machine, InstX86Base<Machine>::Movp>(Func, Dest,
Source) {}
};
/// Movq - copy between XMM registers, or mem64 and XMM registers.
template <class Machine>
class InstX86Movq
: public InstX86BaseMovlike<Machine, InstX86Base<Machine>::Movq> {
public:
static InstX86Movq *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Movq>()) InstX86Movq(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Movq(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseMovlike<Machine, InstX86Base<Machine>::Movq>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Add
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Add> {
public:
static InstX86Add *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Add>()) InstX86Add(Func, Dest, Source);
}
private:
InstX86Add(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Add>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86AddRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AddRMW> {
public:
static InstX86AddRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86AddRMW>())
InstX86AddRMW(Func, DestSrc0, Src1);
}
private:
InstX86AddRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AddRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Addps
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Addps, true> {
public:
static InstX86Addps *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Addps>())
InstX86Addps(Func, Dest, Source);
}
private:
InstX86Addps(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Addps, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Adc
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Adc> {
public:
static InstX86Adc *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Adc>()) InstX86Adc(Func, Dest, Source);
}
private:
InstX86Adc(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Adc>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86AdcRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AdcRMW> {
public:
static InstX86AdcRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86AdcRMW>())
InstX86AdcRMW(Func, DestSrc0, Src1);
}
private:
InstX86AdcRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AdcRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Addss
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Addss, false> {
public:
static InstX86Addss *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Addss>())
InstX86Addss(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Addss(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Addss, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Padd
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Padd, true> {
public:
static InstX86Padd *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Padd>()) InstX86Padd(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Padd(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Padd, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Sub
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Sub> {
public:
static InstX86Sub *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Sub>()) InstX86Sub(Func, Dest, Source);
}
private:
InstX86Sub(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Sub>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86SubRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::SubRMW> {
public:
static InstX86SubRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86SubRMW>())
InstX86SubRMW(Func, DestSrc0, Src1);
}
private:
InstX86SubRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::SubRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Subps
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Subps, true> {
public:
static InstX86Subps *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Subps>())
InstX86Subps(Func, Dest, Source);
}
private:
InstX86Subps(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Subps, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Subss
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Subss, false> {
public:
static InstX86Subss *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Subss>())
InstX86Subss(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Subss(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Subss, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Sbb
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Sbb> {
public:
static InstX86Sbb *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Sbb>()) InstX86Sbb(Func, Dest, Source);
}
private:
InstX86Sbb(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Sbb>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86SbbRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::SbbRMW> {
public:
static InstX86SbbRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86SbbRMW>())
InstX86SbbRMW(Func, DestSrc0, Src1);
}
private:
InstX86SbbRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::SbbRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Psub
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Psub, true> {
public:
static InstX86Psub *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Psub>()) InstX86Psub(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Psub(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Psub, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86And
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::And> {
public:
static InstX86And *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86And>()) InstX86And(Func, Dest, Source);
}
private:
InstX86And(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::And>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86AndRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AndRMW> {
public:
static InstX86AndRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86AndRMW>())
InstX86AndRMW(Func, DestSrc0, Src1);
}
private:
InstX86AndRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::AndRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Pand
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pand, false> {
public:
static InstX86Pand *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pand>()) InstX86Pand(Func, Dest, Source);
}
private:
InstX86Pand(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pand, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Pandn
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pandn, false> {
public:
static InstX86Pandn *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pandn>())
InstX86Pandn(Func, Dest, Source);
}
private:
InstX86Pandn(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pandn, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Or
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Or> {
public:
static InstX86Or *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Or>()) InstX86Or(Func, Dest, Source);
}
private:
InstX86Or(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Or>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86OrRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::OrRMW> {
public:
static InstX86OrRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86OrRMW>())
InstX86OrRMW(Func, DestSrc0, Src1);
}
private:
InstX86OrRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::OrRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Por
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Por, false> {
public:
static InstX86Por *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Por>()) InstX86Por(Func, Dest, Source);
}
private:
InstX86Por(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Por, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Xor
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Xor> {
public:
static InstX86Xor *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Xor>()) InstX86Xor(Func, Dest, Source);
}
private:
InstX86Xor(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Xor>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86XorRMW
: public InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::XorRMW> {
public:
static InstX86XorRMW *
create(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX86XorRMW>())
InstX86XorRMW(Func, DestSrc0, Src1);
}
private:
InstX86XorRMW(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *DestSrc0,
Operand *Src1)
: InstX86BaseBinopRMW<Machine, InstX86Base<Machine>::XorRMW>(
Func, DestSrc0, Src1) {}
};
template <class Machine>
class InstX86Pxor
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pxor, false> {
public:
static InstX86Pxor *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pxor>()) InstX86Pxor(Func, Dest, Source);
}
private:
InstX86Pxor(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pxor, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Imul
: public InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Imul> {
public:
static InstX86Imul *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Imul>()) InstX86Imul(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Imul(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPR<Machine, InstX86Base<Machine>::Imul>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Mulps
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Mulps, true> {
public:
static InstX86Mulps *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Mulps>())
InstX86Mulps(Func, Dest, Source);
}
private:
InstX86Mulps(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Mulps, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Mulss
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Mulss, false> {
public:
static InstX86Mulss *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Mulss>())
InstX86Mulss(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Mulss(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Mulss, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Pmull
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pmull, true> {
public:
static InstX86Pmull *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pmull>())
InstX86Pmull(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Pmull(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pmull, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Pmuludq
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pmuludq,
false> {
public:
static InstX86Pmuludq *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pmuludq>())
InstX86Pmuludq(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Pmuludq(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pmuludq, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Divps
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Divps, true> {
public:
static InstX86Divps *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Divps>())
InstX86Divps(Func, Dest, Source);
}
private:
InstX86Divps(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Divps, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Divss
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Divss, false> {
public:
static InstX86Divss *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Divss>())
InstX86Divss(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Divss(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Divss, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Rol
: public InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Rol> {
public:
static InstX86Rol *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Rol>()) InstX86Rol(Func, Dest, Source);
}
private:
InstX86Rol(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Rol>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Shl
: public InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Shl> {
public:
static InstX86Shl *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Shl>()) InstX86Shl(Func, Dest, Source);
}
private:
InstX86Shl(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Shl>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Psll
: public InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psll> {
public:
static InstX86Psll *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Psll>()) InstX86Psll(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Psll(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psll>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Psrl
: public InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psrl,
true> {
public:
static InstX86Psrl *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Psrl>()) InstX86Psrl(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Psrl(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psrl, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Shr
: public InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Shr> {
public:
static InstX86Shr *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Shr>()) InstX86Shr(Func, Dest, Source);
}
private:
InstX86Shr(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Shr>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Sar
: public InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Sar> {
public:
static InstX86Sar *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Sar>()) InstX86Sar(Func, Dest, Source);
}
private:
InstX86Sar(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopGPRShift<Machine, InstX86Base<Machine>::Sar>(Func, Dest,
Source) {}
};
template <class Machine>
class InstX86Psra
: public InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psra> {
public:
static InstX86Psra *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Psra>()) InstX86Psra(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Psra(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmmShift<Machine, InstX86Base<Machine>::Psra>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Pcmpeq
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pcmpeq, true> {
public:
static InstX86Pcmpeq *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pcmpeq>())
InstX86Pcmpeq(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Pcmpeq(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pcmpeq, true>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Pcmpgt
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pcmpgt, true> {
public:
static InstX86Pcmpgt *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86Pcmpgt>())
InstX86Pcmpgt(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
private:
InstX86Pcmpgt(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::Pcmpgt, true>(
Func, Dest, Source) {}
};
/// movss is only a binary operation when the source and dest
/// operands are both registers (the high bits of dest are left untouched).
/// In other cases, it behaves like a copy (mov-like) operation (and the
/// high bits of dest are cleared).
/// InstX86Movss will assert that both its source and dest operands are
/// registers, so the lowering code should use _mov instead of _movss
/// in cases where a copy operation is intended.
template <class Machine>
class InstX86MovssRegs
: public InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::MovssRegs,
false> {
public:
static InstX86MovssRegs *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX86MovssRegs>())
InstX86MovssRegs(Func, Dest, Source);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86MovssRegs(Cfg *Func, Variable *Dest, Operand *Source)
: InstX86BaseBinopXmm<Machine, InstX86Base<Machine>::MovssRegs, false>(
Func, Dest, Source) {}
};
template <class Machine>
class InstX86Idiv
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Idiv> {
public:
static InstX86Idiv *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Idiv>())
InstX86Idiv(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Idiv(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Idiv>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Div
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Div> {
public:
static InstX86Div *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Div>())
InstX86Div(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Div(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Div>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Insertps
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Insertps> {
public:
static InstX86Insertps *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Insertps>())
InstX86Insertps(Func, Dest, Source1, Source2);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Insertps(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Insertps>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Pinsr
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Pinsr> {
public:
static InstX86Pinsr *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Pinsr>())
InstX86Pinsr(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Pinsr(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Pinsr>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Shufps
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Shufps> {
public:
static InstX86Shufps *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Shufps>())
InstX86Shufps(Func, Dest, Source1, Source2);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Shufps(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Shufps>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Blendvps
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Blendvps> {
public:
static InstX86Blendvps *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Blendvps>())
InstX86Blendvps(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Fund) const override;
private:
InstX86Blendvps(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Blendvps>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Pblendvb
: public InstX86BaseTernop<Machine, InstX86Base<Machine>::Pblendvb> {
public:
static InstX86Pblendvb *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Pblendvb>())
InstX86Pblendvb(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Pblendvb(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX86BaseTernop<Machine, InstX86Base<Machine>::Pblendvb>(
Func, Dest, Source1, Source2) {}
};
template <class Machine>
class InstX86Pextr
: public InstX86BaseThreeAddressop<Machine, InstX86Base<Machine>::Pextr> {
public:
static InstX86Pextr *create(Cfg *Func, Variable *Dest, Operand *Source0,
Operand *Source1) {
return new (Func->allocate<InstX86Pextr>())
InstX86Pextr(Func, Dest, Source0, Source1);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
private:
InstX86Pextr(Cfg *Func, Variable *Dest, Operand *Source0, Operand *Source1)
: InstX86BaseThreeAddressop<Machine, InstX86Base<Machine>::Pextr>(
Func, Dest, Source0, Source1) {}
};
template <class Machine>
class InstX86Pshufd
: public InstX86BaseThreeAddressop<Machine, InstX86Base<Machine>::Pshufd> {
public:
static InstX86Pshufd *create(Cfg *Func, Variable *Dest, Operand *Source0,
Operand *Source1) {
return new (Func->allocate<InstX86Pshufd>())
InstX86Pshufd(Func, Dest, Source0, Source1);
}
void emitIAS(const Cfg *Func) const override;
private:
InstX86Pshufd(Cfg *Func, Variable *Dest, Operand *Source0, Operand *Source1)
: InstX86BaseThreeAddressop<Machine, InstX86Base<Machine>::Pshufd>(
Func, Dest, Source0, Source1) {}
};
/// Base class for a lockable x86-32 instruction (emits a locked prefix).
template <class Machine>
class InstX86BaseLockable : public InstX86Base<Machine> {
InstX86BaseLockable() = delete;
InstX86BaseLockable(const InstX86BaseLockable &) = delete;
InstX86BaseLockable &operator=(const InstX86BaseLockable &) = delete;
protected:
bool Locked;
InstX86BaseLockable(Cfg *Func,
typename InstX86Base<Machine>::InstKindX86 Kind,
SizeT Maxsrcs, Variable *Dest, bool Locked)
: InstX86Base<Machine>(Func, Kind, Maxsrcs, Dest), Locked(Locked) {
// Assume that such instructions are used for Atomics and be careful
// with optimizations.
this->HasSideEffects = Locked;
}
};
/// Mul instruction - unsigned multiply.
template <class Machine> class InstX86Mul final : public InstX86Base<Machine> {
InstX86Mul() = delete;
InstX86Mul(const InstX86Mul &) = delete;
InstX86Mul &operator=(const InstX86Mul &) = delete;
public:
static InstX86Mul *create(Cfg *Func, Variable *Dest, Variable *Source1,
Operand *Source2) {
return new (Func->allocate<InstX86Mul>())
InstX86Mul(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Mul);
}
private:
InstX86Mul(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2);
};
/// Shld instruction - shift across a pair of operands.
template <class Machine> class InstX86Shld final : public InstX86Base<Machine> {
InstX86Shld() = delete;
InstX86Shld(const InstX86Shld &) = delete;
InstX86Shld &operator=(const InstX86Shld &) = delete;
public:
static InstX86Shld *create(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2) {
return new (Func->allocate<InstX86Shld>())
InstX86Shld(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Shld);
}
private:
InstX86Shld(Cfg *Func, Variable *Dest, Variable *Source1, Variable *Source2);
};
/// Shrd instruction - shift across a pair of operands.
template <class Machine> class InstX86Shrd final : public InstX86Base<Machine> {
InstX86Shrd() = delete;
InstX86Shrd(const InstX86Shrd &) = delete;
InstX86Shrd &operator=(const InstX86Shrd &) = delete;
public:
static InstX86Shrd *create(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2) {
return new (Func->allocate<InstX86Shrd>())
InstX86Shrd(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Shrd);
}
private:
InstX86Shrd(Cfg *Func, Variable *Dest, Variable *Source1, Variable *Source2);
};
/// Conditional move instruction.
template <class Machine> class InstX86Cmov final : public InstX86Base<Machine> {
InstX86Cmov() = delete;
InstX86Cmov(const InstX86Cmov &) = delete;
InstX86Cmov &operator=(const InstX86Cmov &) = delete;
public:
static InstX86Cmov *
create(Cfg *Func, Variable *Dest, Operand *Source,
typename InstX86Base<Machine>::Traits::Cond::BrCond Cond) {
return new (Func->allocate<InstX86Cmov>())
InstX86Cmov(Func, Dest, Source, Cond);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Cmov);
}
private:
InstX86Cmov(Cfg *Func, Variable *Dest, Operand *Source,
typename InstX86Base<Machine>::Traits::Cond::BrCond Cond);
typename InstX86Base<Machine>::Traits::Cond::BrCond Condition;
};
/// Cmpps instruction - compare packed singled-precision floating point
/// values
template <class Machine>
class InstX86Cmpps final : public InstX86Base<Machine> {
InstX86Cmpps() = delete;
InstX86Cmpps(const InstX86Cmpps &) = delete;
InstX86Cmpps &operator=(const InstX86Cmpps &) = delete;
public:
static InstX86Cmpps *
create(Cfg *Func, Variable *Dest, Operand *Source,
typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition) {
return new (Func->allocate<InstX86Cmpps>())
InstX86Cmpps(Func, Dest, Source, Condition);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Cmpps);
}
private:
InstX86Cmpps(Cfg *Func, Variable *Dest, Operand *Source,
typename InstX86Base<Machine>::Traits::Cond::CmppsCond Cond);
typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition;
};
/// Cmpxchg instruction - cmpxchg <dest>, <desired> will compare if <dest>
/// equals eax. If so, the ZF is set and <desired> is stored in <dest>.
/// If not, ZF is cleared and <dest> is copied to eax (or subregister).
/// <dest> can be a register or memory, while <desired> must be a register.
/// It is the user's responsiblity to mark eax with a FakeDef.
template <class Machine>
class InstX86Cmpxchg final : public InstX86BaseLockable<Machine> {
InstX86Cmpxchg() = delete;
InstX86Cmpxchg(const InstX86Cmpxchg &) = delete;
InstX86Cmpxchg &operator=(const InstX86Cmpxchg &) = delete;
public:
static InstX86Cmpxchg *create(Cfg *Func, Operand *DestOrAddr, Variable *Eax,
Variable *Desired, bool Locked) {
return new (Func->allocate<InstX86Cmpxchg>())
InstX86Cmpxchg(Func, DestOrAddr, Eax, Desired, Locked);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Cmpxchg);
}
private:
InstX86Cmpxchg(Cfg *Func, Operand *DestOrAddr, Variable *Eax,
Variable *Desired, bool Locked);
};
/// Cmpxchg8b instruction - cmpxchg8b <m64> will compare if <m64>
/// equals edx:eax. If so, the ZF is set and ecx:ebx is stored in <m64>.
/// If not, ZF is cleared and <m64> is copied to edx:eax.
/// The caller is responsible for inserting FakeDefs to mark edx
/// and eax as modified.
/// <m64> must be a memory operand.
template <class Machine>
class InstX86Cmpxchg8b final : public InstX86BaseLockable<Machine> {
InstX86Cmpxchg8b() = delete;
InstX86Cmpxchg8b(const InstX86Cmpxchg8b &) = delete;
InstX86Cmpxchg8b &operator=(const InstX86Cmpxchg8b &) = delete;
public:
static InstX86Cmpxchg8b *
create(Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *Dest,
Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx,
bool Locked) {
return new (Func->allocate<InstX86Cmpxchg8b>())
InstX86Cmpxchg8b(Func, Dest, Edx, Eax, Ecx, Ebx, Locked);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst,
InstX86Base<Machine>::Cmpxchg8b);
}
private:
InstX86Cmpxchg8b(Cfg *Func,
typename InstX86Base<Machine>::Traits::X86OperandMem *Dest,
Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx,
bool Locked);
};
/// Cvt instruction - wrapper for cvtsX2sY where X and Y are in {s,d,i}
/// as appropriate. s=float, d=double, i=int. X and Y are determined
/// from dest/src types. Sign and zero extension on the integer
/// operand needs to be done separately.
template <class Machine> class InstX86Cvt final : public InstX86Base<Machine> {
InstX86Cvt() = delete;
InstX86Cvt(const InstX86Cvt &) = delete;
InstX86Cvt &operator=(const InstX86Cvt &) = delete;
public:
enum CvtVariant { Si2ss, Tss2si, Float2float, Dq2ps, Tps2dq };
static InstX86Cvt *create(Cfg *Func, Variable *Dest, Operand *Source,
CvtVariant Variant) {
return new (Func->allocate<InstX86Cvt>())
InstX86Cvt(Func, Dest, Source, Variant);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Cvt);
}
bool isTruncating() const { return Variant == Tss2si || Variant == Tps2dq; }
private:
CvtVariant Variant;
InstX86Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant);
};
/// cmp - Integer compare instruction.
template <class Machine> class InstX86Icmp final : public InstX86Base<Machine> {
InstX86Icmp() = delete;
InstX86Icmp(const InstX86Icmp &) = delete;
InstX86Icmp &operator=(const InstX86Icmp &) = delete;
public:
static InstX86Icmp *create(Cfg *Func, Operand *Src1, Operand *Src2) {
return new (Func->allocate<InstX86Icmp>()) InstX86Icmp(Func, Src1, Src2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Icmp);
}
private:
InstX86Icmp(Cfg *Func, Operand *Src1, Operand *Src2);
};
/// ucomiss/ucomisd - floating-point compare instruction.
template <class Machine>
class InstX86Ucomiss final : public InstX86Base<Machine> {
InstX86Ucomiss() = delete;
InstX86Ucomiss(const InstX86Ucomiss &) = delete;
InstX86Ucomiss &operator=(const InstX86Ucomiss &) = delete;
public:
static InstX86Ucomiss *create(Cfg *Func, Operand *Src1, Operand *Src2) {
return new (Func->allocate<InstX86Ucomiss>())
InstX86Ucomiss(Func, Src1, Src2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Ucomiss);
}
private:
InstX86Ucomiss(Cfg *Func, Operand *Src1, Operand *Src2);
};
/// UD2 instruction.
template <class Machine> class InstX86UD2 final : public InstX86Base<Machine> {
InstX86UD2() = delete;
InstX86UD2(const InstX86UD2 &) = delete;
InstX86UD2 &operator=(const InstX86UD2 &) = delete;
public:
static InstX86UD2 *create(Cfg *Func) {
return new (Func->allocate<InstX86UD2>()) InstX86UD2(Func);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::UD2);
}
private:
explicit InstX86UD2(Cfg *Func);
};
/// Test instruction.
template <class Machine> class InstX86Test final : public InstX86Base<Machine> {
InstX86Test() = delete;
InstX86Test(const InstX86Test &) = delete;
InstX86Test &operator=(const InstX86Test &) = delete;
public:
static InstX86Test *create(Cfg *Func, Operand *Source1, Operand *Source2) {
return new (Func->allocate<InstX86Test>())
InstX86Test(Func, Source1, Source2);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Test);
}
private:
InstX86Test(Cfg *Func, Operand *Source1, Operand *Source2);
};
/// Mfence instruction.
template <class Machine>
class InstX86Mfence final : public InstX86Base<Machine> {
InstX86Mfence() = delete;
InstX86Mfence(const InstX86Mfence &) = delete;
InstX86Mfence &operator=(const InstX86Mfence &) = delete;
public:
static InstX86Mfence *create(Cfg *Func) {
return new (Func->allocate<InstX86Mfence>()) InstX86Mfence(Func);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Mfence);
}
private:
explicit InstX86Mfence(Cfg *Func);
};
/// This is essentially a "mov" instruction with an
/// InstX86Base<Machine>::Traits::X86OperandMem
/// operand instead of Variable as the destination. It's important
/// for liveness that there is no Dest operand.
template <class Machine>
class InstX86Store final : public InstX86Base<Machine> {
InstX86Store() = delete;
InstX86Store(const InstX86Store &) = delete;
InstX86Store &operator=(const InstX86Store &) = delete;
public:
static InstX86Store *
create(Cfg *Func, Operand *Value,
typename InstX86Base<Machine>::Traits::X86Operand *Mem) {
return new (Func->allocate<InstX86Store>()) InstX86Store(Func, Value, Mem);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Store);
}
private:
InstX86Store(Cfg *Func, Operand *Value,
typename InstX86Base<Machine>::Traits::X86Operand *Mem);
};
/// This is essentially a vector "mov" instruction with an typename
/// InstX86Base<Machine>::Traits::X86OperandMem
/// operand instead of Variable as the destination. It's important
/// for liveness that there is no Dest operand. The source must be an
/// Xmm register, since Dest is mem.
template <class Machine>
class InstX86StoreP final : public InstX86Base<Machine> {
InstX86StoreP() = delete;
InstX86StoreP(const InstX86StoreP &) = delete;
InstX86StoreP &operator=(const InstX86StoreP &) = delete;
public:
static InstX86StoreP *
create(Cfg *Func, Variable *Value,
typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) {
return new (Func->allocate<InstX86StoreP>())
InstX86StoreP(Func, Value, Mem);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::StoreP);
}
private:
InstX86StoreP(Cfg *Func, Variable *Value,
typename InstX86Base<Machine>::Traits::X86OperandMem *Mem);
};
template <class Machine>
class InstX86StoreQ final : public InstX86Base<Machine> {
InstX86StoreQ() = delete;
InstX86StoreQ(const InstX86StoreQ &) = delete;
InstX86StoreQ &operator=(const InstX86StoreQ &) = delete;
public:
static InstX86StoreQ *
create(Cfg *Func, Variable *Value,
typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) {
return new (Func->allocate<InstX86StoreQ>())
InstX86StoreQ(Func, Value, Mem);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::StoreQ);
}
private:
InstX86StoreQ(Cfg *Func, Variable *Value,
typename InstX86Base<Machine>::Traits::X86OperandMem *Mem);
};
/// Nop instructions of varying length
template <class Machine> class InstX86Nop final : public InstX86Base<Machine> {
InstX86Nop() = delete;
InstX86Nop(const InstX86Nop &) = delete;
InstX86Nop &operator=(const InstX86Nop &) = delete;
public:
// TODO: Replace with enum.
typedef unsigned NopVariant;
static InstX86Nop *create(Cfg *Func, NopVariant Variant) {
return new (Func->allocate<InstX86Nop>()) InstX86Nop(Func, Variant);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Nop);
}
private:
InstX86Nop(Cfg *Func, SizeT Length);
NopVariant Variant;
};
/// Fld - load a value onto the x87 FP stack.
template <class Machine> class InstX86Fld final : public InstX86Base<Machine> {
InstX86Fld() = delete;
InstX86Fld(const InstX86Fld &) = delete;
InstX86Fld &operator=(const InstX86Fld &) = delete;
public:
static InstX86Fld *create(Cfg *Func, Operand *Src) {
return new (Func->allocate<InstX86Fld>()) InstX86Fld(Func, Src);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Fld);
}
private:
InstX86Fld(Cfg *Func, Operand *Src);
};
/// Fstp - store x87 st(0) into memory and pop st(0).
template <class Machine> class InstX86Fstp final : public InstX86Base<Machine> {
InstX86Fstp() = delete;
InstX86Fstp(const InstX86Fstp &) = delete;
InstX86Fstp &operator=(const InstX86Fstp &) = delete;
public:
static InstX86Fstp *create(Cfg *Func, Variable *Dest) {
return new (Func->allocate<InstX86Fstp>()) InstX86Fstp(Func, Dest);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Fstp);
}
private:
InstX86Fstp(Cfg *Func, Variable *Dest);
};
template <class Machine> class InstX86Pop final : public InstX86Base<Machine> {
InstX86Pop() = delete;
InstX86Pop(const InstX86Pop &) = delete;
InstX86Pop &operator=(const InstX86Pop &) = delete;
public:
static InstX86Pop *create(Cfg *Func, Variable *Dest) {
return new (Func->allocate<InstX86Pop>()) InstX86Pop(Func, Dest);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Pop);
}
private:
InstX86Pop(Cfg *Func, Variable *Dest);
};
template <class Machine> class InstX86Push final : public InstX86Base<Machine> {
InstX86Push() = delete;
InstX86Push(const InstX86Push &) = delete;
InstX86Push &operator=(const InstX86Push &) = delete;
public:
static InstX86Push *create(Cfg *Func, Variable *Source) {
return new (Func->allocate<InstX86Push>()) InstX86Push(Func, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Push);
}
private:
InstX86Push(Cfg *Func, Variable *Source);
};
/// Ret instruction. Currently only supports the "ret" version that
/// does not pop arguments. This instruction takes a Source operand
/// (for non-void returning functions) for liveness analysis, though
/// a FakeUse before the ret would do just as well.
template <class Machine> class InstX86Ret final : public InstX86Base<Machine> {
InstX86Ret() = delete;
InstX86Ret(const InstX86Ret &) = delete;
InstX86Ret &operator=(const InstX86Ret &) = delete;
public:
static InstX86Ret *create(Cfg *Func, Variable *Source = nullptr) {
return new (Func->allocate<InstX86Ret>()) InstX86Ret(Func, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Ret);
}
private:
InstX86Ret(Cfg *Func, Variable *Source);
};
/// Conditional set-byte instruction.
template <class Machine>
class InstX86Setcc final : public InstX86Base<Machine> {
InstX86Setcc() = delete;
InstX86Setcc(const InstX86Cmov<Machine> &) = delete;
InstX86Setcc &operator=(const InstX86Setcc &) = delete;
public:
static InstX86Setcc *
create(Cfg *Func, Variable *Dest,
typename InstX86Base<Machine>::Traits::Cond::BrCond Cond) {
return new (Func->allocate<InstX86Setcc>()) InstX86Setcc(Func, Dest, Cond);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Setcc);
}
private:
InstX86Setcc(Cfg *Func, Variable *Dest,
typename InstX86Base<Machine>::Traits::Cond::BrCond Cond);
const typename InstX86Base<Machine>::Traits::Cond::BrCond Condition;
};
/// Exchanging Add instruction. Exchanges the first operand (destination
/// operand) with the second operand (source operand), then loads the sum
/// of the two values into the destination operand. The destination may be
/// a register or memory, while the source must be a register.
///
/// Both the dest and source are updated. The caller should then insert a
/// FakeDef to reflect the second udpate.
template <class Machine>
class InstX86Xadd final : public InstX86BaseLockable<Machine> {
InstX86Xadd() = delete;
InstX86Xadd(const InstX86Xadd &) = delete;
InstX86Xadd &operator=(const InstX86Xadd &) = delete;
public:
static InstX86Xadd *create(Cfg *Func, Operand *Dest, Variable *Source,
bool Locked) {
return new (Func->allocate<InstX86Xadd>())
InstX86Xadd(Func, Dest, Source, Locked);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Xadd);
}
private:
InstX86Xadd(Cfg *Func, Operand *Dest, Variable *Source, bool Locked);
};
/// Exchange instruction. Exchanges the first operand (destination
/// operand) with the second operand (source operand). At least one of
/// the operands must be a register (and the other can be reg or mem).
/// Both the Dest and Source are updated. If there is a memory operand,
/// then the instruction is automatically "locked" without the need for
/// a lock prefix.
template <class Machine> class InstX86Xchg final : public InstX86Base<Machine> {
InstX86Xchg() = delete;
InstX86Xchg(const InstX86Xchg &) = delete;
InstX86Xchg &operator=(const InstX86Xchg &) = delete;
public:
static InstX86Xchg *create(Cfg *Func, Operand *Dest, Variable *Source) {
return new (Func->allocate<InstX86Xchg>()) InstX86Xchg(Func, Dest, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) {
return InstX86Base<Machine>::isClassof(Inst, InstX86Base<Machine>::Xchg);
}
private:
InstX86Xchg(Cfg *Func, Operand *Dest, Variable *Source);
};
/// struct Insts is a template that can be used to instantiate all the X86
/// instructions for a target with a simple
///
/// using Insts = ::Ice::X86Internal::Insts<TargeT>;
template <class Machine> struct Insts {
using FakeRMW = InstX86FakeRMW<Machine>;
using Label = InstX86Label<Machine>;
using AdjustStack = InstX86AdjustStack<Machine>;
using Call = InstX86Call<Machine>;
using Br = InstX86Br<Machine>;
using Jmp = InstX86Jmp<Machine>;
using Bswap = InstX86Bswap<Machine>;
using Neg = InstX86Neg<Machine>;
using Bsf = InstX86Bsf<Machine>;
using Bsr = InstX86Bsr<Machine>;
using Lea = InstX86Lea<Machine>;
using Cbwdq = InstX86Cbwdq<Machine>;
using Movsx = InstX86Movsx<Machine>;
using Movzx = InstX86Movzx<Machine>;
using Movd = InstX86Movd<Machine>;
using Sqrtss = InstX86Sqrtss<Machine>;
using Mov = InstX86Mov<Machine>;
using Movp = InstX86Movp<Machine>;
using Movq = InstX86Movq<Machine>;
using Add = InstX86Add<Machine>;
using AddRMW = InstX86AddRMW<Machine>;
using Addps = InstX86Addps<Machine>;
using Adc = InstX86Adc<Machine>;
using AdcRMW = InstX86AdcRMW<Machine>;
using Addss = InstX86Addss<Machine>;
using Padd = InstX86Padd<Machine>;
using Sub = InstX86Sub<Machine>;
using SubRMW = InstX86SubRMW<Machine>;
using Subps = InstX86Subps<Machine>;
using Subss = InstX86Subss<Machine>;
using Sbb = InstX86Sbb<Machine>;
using SbbRMW = InstX86SbbRMW<Machine>;
using Psub = InstX86Psub<Machine>;
using And = InstX86And<Machine>;
using AndRMW = InstX86AndRMW<Machine>;
using Pand = InstX86Pand<Machine>;
using Pandn = InstX86Pandn<Machine>;
using Or = InstX86Or<Machine>;
using OrRMW = InstX86OrRMW<Machine>;
using Por = InstX86Por<Machine>;
using Xor = InstX86Xor<Machine>;
using XorRMW = InstX86XorRMW<Machine>;
using Pxor = InstX86Pxor<Machine>;
using Imul = InstX86Imul<Machine>;
using Mulps = InstX86Mulps<Machine>;
using Mulss = InstX86Mulss<Machine>;
using Pmull = InstX86Pmull<Machine>;
using Pmuludq = InstX86Pmuludq<Machine>;
using Divps = InstX86Divps<Machine>;
using Divss = InstX86Divss<Machine>;
using Rol = InstX86Rol<Machine>;
using Shl = InstX86Shl<Machine>;
using Psll = InstX86Psll<Machine>;
using Psrl = InstX86Psrl<Machine>;
using Shr = InstX86Shr<Machine>;
using Sar = InstX86Sar<Machine>;
using Psra = InstX86Psra<Machine>;
using Pcmpeq = InstX86Pcmpeq<Machine>;
using Pcmpgt = InstX86Pcmpgt<Machine>;
using MovssRegs = InstX86MovssRegs<Machine>;
using Idiv = InstX86Idiv<Machine>;
using Div = InstX86Div<Machine>;
using Insertps = InstX86Insertps<Machine>;
using Pinsr = InstX86Pinsr<Machine>;
using Shufps = InstX86Shufps<Machine>;
using Blendvps = InstX86Blendvps<Machine>;
using Pblendvb = InstX86Pblendvb<Machine>;
using Pextr = InstX86Pextr<Machine>;
using Pshufd = InstX86Pshufd<Machine>;
using Lockable = InstX86BaseLockable<Machine>;
using Mul = InstX86Mul<Machine>;
using Shld = InstX86Shld<Machine>;
using Shrd = InstX86Shrd<Machine>;
using Cmov = InstX86Cmov<Machine>;
using Cmpps = InstX86Cmpps<Machine>;
using Cmpxchg = InstX86Cmpxchg<Machine>;
using Cmpxchg8b = InstX86Cmpxchg8b<Machine>;
using Cvt = InstX86Cvt<Machine>;
using Icmp = InstX86Icmp<Machine>;
using Ucomiss = InstX86Ucomiss<Machine>;
using UD2 = InstX86UD2<Machine>;
using Test = InstX86Test<Machine>;
using Mfence = InstX86Mfence<Machine>;
using Store = InstX86Store<Machine>;
using StoreP = InstX86StoreP<Machine>;
using StoreQ = InstX86StoreQ<Machine>;
using Nop = InstX86Nop<Machine>;
using Fld = InstX86Fld<Machine>;
using Fstp = InstX86Fstp<Machine>;
using Pop = InstX86Pop<Machine>;
using Push = InstX86Push<Machine>;
using Ret = InstX86Ret<Machine>;
using Setcc = InstX86Setcc<Machine>;
using Xadd = InstX86Xadd<Machine>;
using Xchg = InstX86Xchg<Machine>;
};
/// X86 Instructions have static data (particularly, opcodes and instruction
/// emitters). Each X86 target needs to define all of these, so this macro is
/// provided so that, if something changes, then all X86 targets will be updated
/// automatically.
#define X86INSTS_DEFINE_STATIC_DATA(Machine) \
namespace Ice { \
namespace X86Internal { \
/* In-place ops */ \
template <> const char *InstX86Bswap<Machine>::Base::Opcode = "bswap"; \
template <> const char *InstX86Neg<Machine>::Base::Opcode = "neg"; \
/* Unary ops */ \
template <> const char *InstX86Bsf<Machine>::Base::Opcode = "bsf"; \
template <> const char *InstX86Bsr<Machine>::Base::Opcode = "bsr"; \
template <> const char *InstX86Lea<Machine>::Base::Opcode = "lea"; \
template <> const char *InstX86Movd<Machine>::Base::Opcode = "movd"; \
template <> const char *InstX86Movsx<Machine>::Base::Opcode = "movs"; \
template <> const char *InstX86Movzx<Machine>::Base::Opcode = "movz"; \
template <> const char *InstX86Sqrtss<Machine>::Base::Opcode = "sqrtss"; \
template <> const char *InstX86Cbwdq<Machine>::Base::Opcode = "cbw/cwd/cdq"; \
/* Mov-like ops */ \
template <> const char *InstX86Mov<Machine>::Base::Opcode = "mov"; \
template <> const char *InstX86Movp<Machine>::Base::Opcode = "movups"; \
template <> const char *InstX86Movq<Machine>::Base::Opcode = "movq"; \
/* Binary ops */ \
template <> const char *InstX86Add<Machine>::Base::Opcode = "add"; \
template <> const char *InstX86AddRMW<Machine>::Base::Opcode = "add"; \
template <> const char *InstX86Addps<Machine>::Base::Opcode = "addps"; \
template <> const char *InstX86Adc<Machine>::Base::Opcode = "adc"; \
template <> const char *InstX86AdcRMW<Machine>::Base::Opcode = "adc"; \
template <> const char *InstX86Addss<Machine>::Base::Opcode = "addss"; \
template <> const char *InstX86Padd<Machine>::Base::Opcode = "padd"; \
template <> const char *InstX86Sub<Machine>::Base::Opcode = "sub"; \
template <> const char *InstX86SubRMW<Machine>::Base::Opcode = "sub"; \
template <> const char *InstX86Subps<Machine>::Base::Opcode = "subps"; \
template <> const char *InstX86Subss<Machine>::Base::Opcode = "subss"; \
template <> const char *InstX86Sbb<Machine>::Base::Opcode = "sbb"; \
template <> const char *InstX86SbbRMW<Machine>::Base::Opcode = "sbb"; \
template <> const char *InstX86Psub<Machine>::Base::Opcode = "psub"; \
template <> const char *InstX86And<Machine>::Base::Opcode = "and"; \
template <> const char *InstX86AndRMW<Machine>::Base::Opcode = "and"; \
template <> const char *InstX86Pand<Machine>::Base::Opcode = "pand"; \
template <> const char *InstX86Pandn<Machine>::Base::Opcode = "pandn"; \
template <> const char *InstX86Or<Machine>::Base::Opcode = "or"; \
template <> const char *InstX86OrRMW<Machine>::Base::Opcode = "or"; \
template <> const char *InstX86Por<Machine>::Base::Opcode = "por"; \
template <> const char *InstX86Xor<Machine>::Base::Opcode = "xor"; \
template <> const char *InstX86XorRMW<Machine>::Base::Opcode = "xor"; \
template <> const char *InstX86Pxor<Machine>::Base::Opcode = "pxor"; \
template <> const char *InstX86Imul<Machine>::Base::Opcode = "imul"; \
template <> const char *InstX86Mulps<Machine>::Base::Opcode = "mulps"; \
template <> const char *InstX86Mulss<Machine>::Base::Opcode = "mulss"; \
template <> const char *InstX86Pmull<Machine>::Base::Opcode = "pmull"; \
template <> const char *InstX86Pmuludq<Machine>::Base::Opcode = "pmuludq"; \
template <> const char *InstX86Div<Machine>::Base::Opcode = "div"; \
template <> const char *InstX86Divps<Machine>::Base::Opcode = "divps"; \
template <> const char *InstX86Idiv<Machine>::Base::Opcode = "idiv"; \
template <> const char *InstX86Divss<Machine>::Base::Opcode = "divss"; \
template <> const char *InstX86Rol<Machine>::Base::Opcode = "rol"; \
template <> const char *InstX86Shl<Machine>::Base::Opcode = "shl"; \
template <> const char *InstX86Psll<Machine>::Base::Opcode = "psll"; \
template <> const char *InstX86Shr<Machine>::Base::Opcode = "shr"; \
template <> const char *InstX86Sar<Machine>::Base::Opcode = "sar"; \
template <> const char *InstX86Psra<Machine>::Base::Opcode = "psra"; \
template <> const char *InstX86Psrl<Machine>::Base::Opcode = "psrl"; \
template <> const char *InstX86Pcmpeq<Machine>::Base::Opcode = "pcmpeq"; \
template <> const char *InstX86Pcmpgt<Machine>::Base::Opcode = "pcmpgt"; \
template <> const char *InstX86MovssRegs<Machine>::Base::Opcode = "movss"; \
/* Ternary ops */ \
template <> const char *InstX86Insertps<Machine>::Base::Opcode = "insertps"; \
template <> const char *InstX86Shufps<Machine>::Base::Opcode = "shufps"; \
template <> const char *InstX86Pinsr<Machine>::Base::Opcode = "pinsr"; \
template <> const char *InstX86Blendvps<Machine>::Base::Opcode = "blendvps"; \
template <> const char *InstX86Pblendvb<Machine>::Base::Opcode = "pblendvb"; \
/* Three address ops */ \
template <> const char *InstX86Pextr<Machine>::Base::Opcode = "pextr"; \
template <> const char *InstX86Pshufd<Machine>::Base::Opcode = "pshufd"; \
/* Inplace GPR ops */ \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp \
InstX86Bswap<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::bswap, \
nullptr /* only a reg form exists */ \
}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp \
InstX86Neg<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::neg, \
&InstX86Base<Machine>::Traits::Assembler::neg}; \
\
/* Unary GPR ops */ \
template <> /* uses specialized emitter. */ \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Cbwdq<Machine>::Base::Emitter = {nullptr, nullptr, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Bsf<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::bsf, \
&InstX86Base<Machine>::Traits::Assembler::bsf, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Bsr<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::bsr, \
&InstX86Base<Machine>::Traits::Assembler::bsr, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Lea<Machine>::Base::Emitter = { \
/* reg/reg and reg/imm are illegal */ nullptr, \
&InstX86Base<Machine>::Traits::Assembler::lea, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Movsx<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::movsx, \
&InstX86Base<Machine>::Traits::Assembler::movsx, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Movzx<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::movzx, \
&InstX86Base<Machine>::Traits::Assembler::movzx, nullptr}; \
\
/* Unary XMM ops */ \
template <> /* uses specialized emitter. */ \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Movd<Machine>::Base::Emitter = {nullptr, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Sqrtss<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sqrtss, \
&InstX86Base<Machine>::Traits::Assembler::sqrtss}; \
\
/* Binary GPR ops */ \
template <> /* uses specialized emitter. */ \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Imul<Machine>::Base::Emitter = {nullptr, nullptr, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Add<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::add, \
&InstX86Base<Machine>::Traits::Assembler::add, \
&InstX86Base<Machine>::Traits::Assembler::add}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86AddRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::add, \
&InstX86Base<Machine>::Traits::Assembler::add}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Adc<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::adc, \
&InstX86Base<Machine>::Traits::Assembler::adc, \
&InstX86Base<Machine>::Traits::Assembler::adc}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86AdcRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::adc, \
&InstX86Base<Machine>::Traits::Assembler::adc}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86And<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::And, \
&InstX86Base<Machine>::Traits::Assembler::And, \
&InstX86Base<Machine>::Traits::Assembler::And}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86AndRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::And, \
&InstX86Base<Machine>::Traits::Assembler::And}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Or<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::Or, \
&InstX86Base<Machine>::Traits::Assembler::Or, \
&InstX86Base<Machine>::Traits::Assembler::Or}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86OrRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::Or, \
&InstX86Base<Machine>::Traits::Assembler::Or}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Sbb<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sbb, \
&InstX86Base<Machine>::Traits::Assembler::sbb, \
&InstX86Base<Machine>::Traits::Assembler::sbb}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86SbbRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sbb, \
&InstX86Base<Machine>::Traits::Assembler::sbb}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Sub<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sub, \
&InstX86Base<Machine>::Traits::Assembler::sub, \
&InstX86Base<Machine>::Traits::Assembler::sub}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86SubRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sub, \
&InstX86Base<Machine>::Traits::Assembler::sub}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp \
InstX86Xor<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::Xor, \
&InstX86Base<Machine>::Traits::Assembler::Xor, \
&InstX86Base<Machine>::Traits::Assembler::Xor}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp \
InstX86XorRMW<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::Xor, \
&InstX86Base<Machine>::Traits::Assembler::Xor}; \
\
/* Binary Shift GPR ops */ \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp \
InstX86Rol<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::rol, \
&InstX86Base<Machine>::Traits::Assembler::rol}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp \
InstX86Sar<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::sar, \
&InstX86Base<Machine>::Traits::Assembler::sar}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp \
InstX86Shl<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::shl, \
&InstX86Base<Machine>::Traits::Assembler::shl}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp \
InstX86Shr<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::shr, \
&InstX86Base<Machine>::Traits::Assembler::shr}; \
\
/* Binary XMM ops */ \
template <> /* uses specialized emitter. */ \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86MovssRegs<Machine>::Base::Emitter = {nullptr, nullptr}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Addss<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::addss, \
&InstX86Base<Machine>::Traits::Assembler::addss}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Addps<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::addps, \
&InstX86Base<Machine>::Traits::Assembler::addps}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Divss<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::divss, \
&InstX86Base<Machine>::Traits::Assembler::divss}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Divps<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::divps, \
&InstX86Base<Machine>::Traits::Assembler::divps}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Mulss<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::mulss, \
&InstX86Base<Machine>::Traits::Assembler::mulss}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Mulps<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::mulps, \
&InstX86Base<Machine>::Traits::Assembler::mulps}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Padd<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::padd, \
&InstX86Base<Machine>::Traits::Assembler::padd}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pand<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pand, \
&InstX86Base<Machine>::Traits::Assembler::pand}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pandn<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pandn, \
&InstX86Base<Machine>::Traits::Assembler::pandn}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pcmpeq<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pcmpeq, \
&InstX86Base<Machine>::Traits::Assembler::pcmpeq}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pcmpgt<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pcmpgt, \
&InstX86Base<Machine>::Traits::Assembler::pcmpgt}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pmull<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pmull, \
&InstX86Base<Machine>::Traits::Assembler::pmull}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pmuludq<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pmuludq, \
&InstX86Base<Machine>::Traits::Assembler::pmuludq}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Por<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::por, \
&InstX86Base<Machine>::Traits::Assembler::por}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Psub<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::psub, \
&InstX86Base<Machine>::Traits::Assembler::psub}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Pxor<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::pxor, \
&InstX86Base<Machine>::Traits::Assembler::pxor}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Subss<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::subss, \
&InstX86Base<Machine>::Traits::Assembler::subss}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp \
InstX86Subps<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::subps, \
&InstX86Base<Machine>::Traits::Assembler::subps}; \
\
/* Binary XMM Shift ops */ \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp \
InstX86Psll<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::psll, \
&InstX86Base<Machine>::Traits::Assembler::psll, \
&InstX86Base<Machine>::Traits::Assembler::psll}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp \
InstX86Psra<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::psra, \
&InstX86Base<Machine>::Traits::Assembler::psra, \
&InstX86Base<Machine>::Traits::Assembler::psra}; \
template <> \
const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp \
InstX86Psrl<Machine>::Base::Emitter = { \
&InstX86Base<Machine>::Traits::Assembler::psrl, \
&InstX86Base<Machine>::Traits::Assembler::psrl, \
&InstX86Base<Machine>::Traits::Assembler::psrl}; \
} \
}
} // end of namespace X86Internal
} // end of namespace Ice
#include "IceInstX86BaseImpl.h"
#endif // SUBZERO_SRC_ICEINSTX86BASE_H