Commit 921856d4 by John Porto

X8632 Templatization completed.

This CL introduces the X86Inst templates. The previous implementation relied on template specialization which did not played nice with the new design. This required a lot of other boilerplate code (i.e., tons of new named constructors, one for each X86Inst.) This CL also moves X8632 code out of the X86Base{Impl}?.h files so that they are **almost** target agnostic. As we move to adding other X86 targets more methods will be moved to the target-specific trait class (e.g., call/ret/argument lowering.) BUG= https://code.google.com/p/nativeclient/issues/detail?id=4077 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/1216933015.
parent a83e9c14
...@@ -37,6 +37,9 @@ class TargetX8632; ...@@ -37,6 +37,9 @@ class TargetX8632;
namespace X8632 { namespace X8632 {
using Immediate = ::Ice::X86Internal::Immediate;
using Label = ::Ice::X86Internal::Label;
class AssemblerX8632 : public X86Internal::AssemblerX86Base<TargetX8632> { class AssemblerX8632 : public X86Internal::AssemblerX86Base<TargetX8632> {
AssemblerX8632(const AssemblerX8632 &) = delete; AssemblerX8632(const AssemblerX8632 &) = delete;
AssemblerX8632 &operator=(const AssemblerX8632 &) = delete; AssemblerX8632 &operator=(const AssemblerX8632 &) = delete;
......
...@@ -948,10 +948,6 @@ inline void AssemblerX86Base<Machine>::emitOperandSizeOverride() { ...@@ -948,10 +948,6 @@ inline void AssemblerX86Base<Machine>::emitOperandSizeOverride() {
} // end of namespace X86Internal } // end of namespace X86Internal
namespace X8632 {
using Immediate = ::Ice::X86Internal::Immediate;
using Label = ::Ice::X86Internal::Label;
} // end of namespace X8632
} // end of namespace Ice } // end of namespace Ice
#include "IceAssemblerX86BaseImpl.h" #include "IceAssemblerX86BaseImpl.h"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,1784 +8,30 @@ ...@@ -8,1784 +8,30 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ///
/// \file /// \file
/// This file declares the InstX8632 and OperandX8632 classes and /// This file used to house all the X8632 instructions. Subzero has been
/// their subclasses. This represents the machine instructions and /// modified to use templates for X86 instructions, so all those definitions are
/// operands used for x86-32 code selection. /// are in IceInstX86Base.h
///
/// When interacting with the X8632 target (which should only happen in the
/// X8632 TargetLowering) clients have should use the Ice::X8632::Traits::Insts
/// traits, which hides all the template verboseness behind a type alias.
///
/// For example, to create an X8632 MOV Instruction, clients should do
///
/// ::Ice::X8632::Traits::Insts::Mov::create
///
/// In the future, this file might be used to declare X8632 specific
/// instructions (e.g., FLD, and FSTP.)
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEINSTX8632_H #ifndef SUBZERO_SRC_ICEINSTX8632_H
#define SUBZERO_SRC_ICEINSTX8632_H #define SUBZERO_SRC_ICEINSTX8632_H
#include "IceAssemblerX8632.h"
#include "IceConditionCodesX8632.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceInstX8632.def" #include "IceInstX86Base.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTargetLoweringX8632Traits.h" #include "IceTargetLoweringX8632Traits.h"
namespace Ice {
class TargetX8632;
/// OperandX8632 extends the Operand hierarchy. Its subclasses are
/// OperandX8632Mem and VariableSplit.
class OperandX8632 : public Operand {
OperandX8632() = delete;
OperandX8632(const OperandX8632 &) = delete;
OperandX8632 &operator=(const OperandX8632 &) = delete;
public:
enum OperandKindX8632 { k__Start = Operand::kTarget, kMem, kSplit };
using Operand::dump;
void dump(const Cfg *, Ostream &Str) const override {
if (BuildDefs::dump())
Str << "<OperandX8632>";
}
protected:
OperandX8632(OperandKindX8632 Kind, Type Ty)
: Operand(static_cast<OperandKind>(Kind), Ty) {}
};
/// OperandX8632Mem represents the m32 addressing mode, with optional
/// base and index registers, a constant offset, and a fixed shift
/// value for the index register.
class OperandX8632Mem : public OperandX8632 {
OperandX8632Mem() = delete;
OperandX8632Mem(const OperandX8632Mem &) = delete;
OperandX8632Mem &operator=(const OperandX8632Mem &) = delete;
public:
enum SegmentRegisters {
DefaultSegment = -1,
#define X(val, name, prefix) val,
SEG_REGX8632_TABLE
#undef X
SegReg_NUM
};
static OperandX8632Mem *create(Cfg *Func, Type Ty, Variable *Base,
Constant *Offset, Variable *Index = nullptr,
uint16_t Shift = 0,
SegmentRegisters SegmentReg = DefaultSegment) {
return new (Func->allocate<OperandX8632Mem>())
OperandX8632Mem(Func, Ty, Base, Offset, Index, Shift, SegmentReg);
}
Variable *getBase() const { return Base; }
Constant *getOffset() const { return Offset; }
Variable *getIndex() const { return Index; }
uint16_t getShift() const { return Shift; }
SegmentRegisters getSegmentRegister() const { return SegmentReg; }
void emitSegmentOverride(X8632::AssemblerX8632 *Asm) const;
X8632::Traits::Address toAsmAddress(Assembler *Asm) const;
void emit(const Cfg *Func) const override;
using OperandX8632::dump;
void dump(const Cfg *Func, Ostream &Str) const override;
static bool classof(const Operand *Operand) {
return Operand->getKind() == static_cast<OperandKind>(kMem);
}
void setRandomized(bool R) { Randomized = R; }
bool getRandomized() const { return Randomized; }
private:
OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg);
Variable *Base;
Constant *Offset;
Variable *Index;
uint16_t Shift;
SegmentRegisters SegmentReg : 16;
/// A flag to show if this memory operand is a randomized one.
/// Randomized memory operands are generated in
/// TargetX8632::randomizeOrPoolImmediate()
bool Randomized;
};
/// VariableSplit is a way to treat an f64 memory location as a pair
/// of i32 locations (Low and High). This is needed for some cases
/// of the Bitcast instruction. Since it's not possible for integer
/// registers to access the XMM registers and vice versa, the
/// lowering forces the f64 to be spilled to the stack and then
/// accesses through the VariableSplit.
class VariableSplit : public OperandX8632 {
VariableSplit() = delete;
VariableSplit(const VariableSplit &) = delete;
VariableSplit &operator=(const VariableSplit &) = delete;
public:
enum Portion { Low, High };
static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) {
return new (Func->allocate<VariableSplit>()) VariableSplit(Func, Var, Part);
}
int32_t getOffset() const { return Part == High ? 4 : 0; }
X8632::Traits::Address toAsmAddress(const Cfg *Func) const;
void emit(const Cfg *Func) const override;
using OperandX8632::dump;
void dump(const Cfg *Func, Ostream &Str) const override;
static bool classof(const Operand *Operand) {
return Operand->getKind() == static_cast<OperandKind>(kSplit);
}
private:
VariableSplit(Cfg *Func, Variable *Var, Portion Part)
: OperandX8632(kSplit, IceType_i32), Var(Var), Part(Part) {
assert(Var->getType() == IceType_f64);
Vars = Func->allocateArrayOf<Variable *>(1);
Vars[0] = Var;
NumVars = 1;
}
Variable *Var;
Portion Part;
};
/// SpillVariable decorates a Variable by linking it to another
/// Variable. When stack frame offsets are computed, the SpillVariable
/// is given a distinct stack slot only if its linked Variable has a
/// register. If the linked Variable has a stack slot, then the
/// Variable and SpillVariable share that slot.
class SpillVariable : public Variable {
SpillVariable() = delete;
SpillVariable(const SpillVariable &) = delete;
SpillVariable &operator=(const SpillVariable &) = delete;
public:
static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<SpillVariable>()) SpillVariable(Ty, Index);
}
const static OperandKind SpillVariableKind =
static_cast<OperandKind>(kVariable_Target);
static bool classof(const Operand *Operand) {
return Operand->getKind() == SpillVariableKind;
}
void setLinkedTo(Variable *Var) { LinkedTo = Var; }
Variable *getLinkedTo() const { return LinkedTo; }
// Inherit dump() and emit() from Variable.
private:
SpillVariable(Type Ty, SizeT Index)
: Variable(SpillVariableKind, Ty, Index), LinkedTo(nullptr) {}
Variable *LinkedTo;
};
class InstX8632 : public InstTarget {
InstX8632() = delete;
InstX8632(const InstX8632 &) = delete;
InstX8632 &operator=(const InstX8632 &) = delete;
public:
enum InstKindX8632 {
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 X8632::Traits::Cond::BrCond
getOppositeCondition(X8632::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 X8632::AssemblerX8632::GPREmitterShiftOp &Emitter);
protected:
InstX8632(Cfg *Func, InstKindX8632 Kind, SizeT Maxsrcs, Variable *Dest)
: InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
static bool isClassof(const Inst *Inst, InstKindX8632 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 (getDest())
validateVectorAddrModeOpnd(getDest());
for (SizeT i = 0; i < getSrcSize(); ++i) {
validateVectorAddrModeOpnd(getSrc(i));
}
}
private:
static void validateVectorAddrModeOpnd(const Operand *Opnd) {
if (llvm::isa<OperandX8632Mem>(Opnd) && isVectorType(Opnd->getType())) {
llvm::report_fatal_error("Possible misaligned vector memory operation");
}
}
};
/// InstX8632FakeRMW represents a non-atomic read-modify-write operation on a
/// memory location. An InstX8632FakeRMW 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
class InstX8632FakeRMW : public InstX8632 {
InstX8632FakeRMW() = delete;
InstX8632FakeRMW(const InstX8632FakeRMW &) = delete;
InstX8632FakeRMW &operator=(const InstX8632FakeRMW &) = delete;
public:
static InstX8632FakeRMW *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<InstX8632FakeRMW>())
InstX8632FakeRMW(Func, Data, Addr, Op, Beacon);
}
Operand *getAddr() const { return getSrc(1); }
Operand *getData() const { return getSrc(0); }
InstArithmetic::OpKind getOp() const { return Op; }
Variable *getBeacon() const { return llvm::cast<Variable>(getSrc(2)); }
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, FakeRMW); }
private:
InstArithmetic::OpKind Op;
InstX8632FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
InstArithmetic::OpKind Op, Variable *Beacon);
};
/// InstX8632Label 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.
class InstX8632Label : public InstX8632 {
InstX8632Label() = delete;
InstX8632Label(const InstX8632Label &) = delete;
InstX8632Label &operator=(const InstX8632Label &) = delete;
public:
static InstX8632Label *create(Cfg *Func, TargetX8632 *Target) {
return new (Func->allocate<InstX8632Label>()) InstX8632Label(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:
InstX8632Label(Cfg *Func, TargetX8632 *Target);
SizeT Number; /// used for unique label generation.
};
/// Conditional and unconditional branch instruction.
class InstX8632Br : public InstX8632 {
InstX8632Br() = delete;
InstX8632Br(const InstX8632Br &) = delete;
InstX8632Br &operator=(const InstX8632Br &) = delete;
public:
/// Create a conditional branch to a node.
static InstX8632Br *create(Cfg *Func, CfgNode *TargetTrue,
CfgNode *TargetFalse,
X8632::Traits::Cond::BrCond Condition) {
assert(Condition != X8632::Traits::Cond::Br_None);
const InstX8632Label *NoLabel = nullptr;
return new (Func->allocate<InstX8632Br>())
InstX8632Br(Func, TargetTrue, TargetFalse, NoLabel, Condition);
}
/// Create an unconditional branch to a node.
static InstX8632Br *create(Cfg *Func, CfgNode *Target) {
const CfgNode *NoCondTarget = nullptr;
const InstX8632Label *NoLabel = nullptr;
return new (Func->allocate<InstX8632Br>()) InstX8632Br(
Func, NoCondTarget, Target, NoLabel, X8632::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 InstX8632Br *create(Cfg *Func, CfgNode *Target,
X8632::Traits::Cond::BrCond Condition) {
assert(Condition != X8632::Traits::Cond::Br_None);
const CfgNode *NoUncondTarget = nullptr;
const InstX8632Label *NoLabel = nullptr;
return new (Func->allocate<InstX8632Br>())
InstX8632Br(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 InstX8632Br *create(Cfg *Func, InstX8632Label *Label,
X8632::Traits::Cond::BrCond Condition) {
const CfgNode *NoCondTarget = nullptr;
const CfgNode *NoUncondTarget = nullptr;
return new (Func->allocate<InstX8632Br>())
InstX8632Br(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 == X8632::Traits::Cond::Br_None;
}
bool repointEdge(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 isClassof(Inst, Br); }
private:
InstX8632Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
const InstX8632Label *Label,
X8632::Traits::Cond::BrCond Condition);
X8632::Traits::Cond::BrCond Condition;
const CfgNode *TargetTrue;
const CfgNode *TargetFalse;
const InstX8632Label *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.
class InstX8632Jmp : public InstX8632 {
InstX8632Jmp() = delete;
InstX8632Jmp(const InstX8632Jmp &) = delete;
InstX8632Jmp &operator=(const InstX8632Jmp &) = delete;
public:
static InstX8632Jmp *create(Cfg *Func, Operand *Target) {
return new (Func->allocate<InstX8632Jmp>()) InstX8632Jmp(Func, Target);
}
Operand *getJmpTarget() const { return 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 isClassof(Inst, Jmp); }
private:
InstX8632Jmp(Cfg *Func, Operand *Target);
};
/// AdjustStack instruction - subtracts esp by the given amount and
/// updates the stack offset during code emission.
class InstX8632AdjustStack : public InstX8632 {
InstX8632AdjustStack() = delete;
InstX8632AdjustStack(const InstX8632AdjustStack &) = delete;
InstX8632AdjustStack &operator=(const InstX8632AdjustStack &) = delete;
public:
static InstX8632AdjustStack *create(Cfg *Func, SizeT Amount, Variable *Esp) {
return new (Func->allocate<InstX8632AdjustStack>())
InstX8632AdjustStack(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 isClassof(Inst, Adjuststack); }
private:
InstX8632AdjustStack(Cfg *Func, SizeT Amount, Variable *Esp);
SizeT Amount;
};
/// Call instruction. Arguments should have already been pushed.
class InstX8632Call : public InstX8632 {
InstX8632Call() = delete;
InstX8632Call(const InstX8632Call &) = delete;
InstX8632Call &operator=(const InstX8632Call &) = delete;
public:
static InstX8632Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) {
return new (Func->allocate<InstX8632Call>())
InstX8632Call(Func, Dest, CallTarget);
}
Operand *getCallTarget() const { return 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 isClassof(Inst, Call); }
private:
InstX8632Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
};
/// Emit a one-operand (GPR) instruction.
void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Var,
const X8632::AssemblerX8632::GPREmitterOneOp &Emitter);
void emitIASAsAddrOpTyGPR(
const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
const X8632::AssemblerX8632::GPREmitterAddrOp &Emitter);
/// Instructions of the form x := op(x).
template <InstX8632::InstKindX8632 K>
class InstX8632InplaceopGPR : public InstX8632 {
InstX8632InplaceopGPR() = delete;
InstX8632InplaceopGPR(const InstX8632InplaceopGPR &) = delete;
InstX8632InplaceopGPR &operator=(const InstX8632InplaceopGPR &) = delete;
public:
static InstX8632InplaceopGPR *create(Cfg *Func, Operand *SrcDest) {
return new (Func->allocate<InstX8632InplaceopGPR>())
InstX8632InplaceopGPR(Func, SrcDest);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
assert(getSrcSize() == 1);
const Variable *Var = getDest();
Type Ty = Var->getType();
emitIASOpTyGPR(Func, Ty, Var, Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632InplaceopGPR(Cfg *Func, Operand *SrcDest)
: InstX8632(Func, K, 1, llvm::dyn_cast<Variable>(SrcDest)) {
addSource(SrcDest);
}
static const char *Opcode;
static const X8632::AssemblerX8632::GPREmitterOneOp Emitter;
};
/// Emit a two-operand (GPR) instruction, where the dest operand is a
/// Variable that's guaranteed to be a register.
template <bool VarCanBeByte = true, bool SrcCanBeByte = true>
void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Dst,
const Operand *Src,
const X8632::AssemblerX8632::GPREmitterRegOp &Emitter);
/// Instructions of the form x := op(y).
template <InstX8632::InstKindX8632 K>
class InstX8632UnaryopGPR : public InstX8632 {
InstX8632UnaryopGPR() = delete;
InstX8632UnaryopGPR(const InstX8632UnaryopGPR &) = delete;
InstX8632UnaryopGPR &operator=(const InstX8632UnaryopGPR &) = delete;
public:
static InstX8632UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX8632UnaryopGPR>())
InstX8632UnaryopGPR(Func, Dest, Src);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
Type SrcTy = getSrc(0)->getType();
Type DestTy = getDest()->getType();
Str << "\t" << Opcode << 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 << getWidthString(DestTy);
Str << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
assert(getSrcSize() == 1);
const Variable *Var = getDest();
Type Ty = Var->getType();
const Operand *Src = getSrc(0);
emitIASRegOpTyGPR(Func, Ty, Var, Src, Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getSrc(0)->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src)
: InstX8632(Func, K, 1, Dest) {
addSource(Src);
}
static const char *Opcode;
static const X8632::AssemblerX8632::GPREmitterRegOp Emitter;
};
void emitIASRegOpTyXMM(const Cfg *Func, Type Ty, const Variable *Var,
const Operand *Src,
const X8632::AssemblerX8632::XmmEmitterRegOp &Emitter);
template <InstX8632::InstKindX8632 K>
class InstX8632UnaryopXmm : public InstX8632 {
InstX8632UnaryopXmm() = delete;
InstX8632UnaryopXmm(const InstX8632UnaryopXmm &) = delete;
InstX8632UnaryopXmm &operator=(const InstX8632UnaryopXmm &) = delete;
public:
static InstX8632UnaryopXmm *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstX8632UnaryopXmm>())
InstX8632UnaryopXmm(Func, Dest, Src);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = getDest()->getType();
assert(getSrcSize() == 1);
emitIASRegOpTyXMM(Func, Ty, getDest(), getSrc(0), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632UnaryopXmm(Cfg *Func, Variable *Dest, Operand *Src)
: InstX8632(Func, K, 1, Dest) {
addSource(Src);
}
static const char *Opcode;
static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter;
};
template <InstX8632::InstKindX8632 K>
class InstX8632BinopGPRShift : public InstX8632 {
InstX8632BinopGPRShift() = delete;
InstX8632BinopGPRShift(const InstX8632BinopGPRShift &) = delete;
InstX8632BinopGPRShift &operator=(const InstX8632BinopGPRShift &) = delete;
public:
/// Create a binary-op GPR shift instruction.
static InstX8632BinopGPRShift *create(Cfg *Func, Variable *Dest,
Operand *Source) {
return new (Func->allocate<InstX8632BinopGPRShift>())
InstX8632BinopGPRShift(Func, Dest, Source);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = true;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = getDest()->getType();
assert(getSrcSize() == 2);
emitIASGPRShift(Func, Ty, getDest(), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopGPRShift(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 2, Dest) {
addSource(Dest);
addSource(Source);
}
static const char *Opcode;
static const X8632::AssemblerX8632::GPREmitterShiftOp Emitter;
};
template <InstX8632::InstKindX8632 K>
class InstX8632BinopGPR : public InstX8632 {
InstX8632BinopGPR() = delete;
InstX8632BinopGPR(const InstX8632BinopGPR &) = delete;
InstX8632BinopGPR &operator=(const InstX8632BinopGPR &) = delete;
public:
/// Create an ordinary binary-op instruction like add or sub.
static InstX8632BinopGPR *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX8632BinopGPR>())
InstX8632BinopGPR(Func, Dest, Source);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = false;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = getDest()->getType();
assert(getSrcSize() == 2);
emitIASRegOpTyGPR(Func, Ty, getDest(), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopGPR(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 2, Dest) {
addSource(Dest);
addSource(Source);
}
static const char *Opcode;
static const X8632::AssemblerX8632::GPREmitterRegOp Emitter;
};
template <InstX8632::InstKindX8632 K>
class InstX8632BinopRMW : public InstX8632 {
InstX8632BinopRMW() = delete;
InstX8632BinopRMW(const InstX8632BinopRMW &) = delete;
InstX8632BinopRMW &operator=(const InstX8632BinopRMW &) = delete;
public:
/// Create an ordinary binary-op instruction like add or sub.
static InstX8632BinopRMW *create(Cfg *Func, OperandX8632Mem *DestSrc0,
Operand *Src1) {
return new (Func->allocate<InstX8632BinopRMW>())
InstX8632BinopRMW(Func, DestSrc0, Src1);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
const bool ShiftHack = false;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = getSrc(0)->getType();
assert(getSrcSize() == 2);
emitIASAsAddrOpTyGPR(Func, Ty, getSrc(0), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << Opcode << "." << getSrc(0)->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopRMW(Cfg *Func, OperandX8632Mem *DestSrc0, Operand *Src1)
: InstX8632(Func, K, 2, nullptr) {
addSource(DestSrc0);
addSource(Src1);
}
static const char *Opcode;
static const X8632::AssemblerX8632::GPREmitterAddrOp Emitter;
};
template <InstX8632::InstKindX8632 K, bool NeedsElementType>
class InstX8632BinopXmm : public InstX8632 {
InstX8632BinopXmm() = delete;
InstX8632BinopXmm(const InstX8632BinopXmm &) = delete;
InstX8632BinopXmm &operator=(const InstX8632BinopXmm &) = delete;
public:
/// Create an XMM binary-op instruction like addss or addps.
static InstX8632BinopXmm *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX8632BinopXmm>())
InstX8632BinopXmm(Func, Dest, Source);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
validateVectorAddrMode();
const bool ShiftHack = false;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
validateVectorAddrMode();
Type Ty = getDest()->getType();
if (NeedsElementType)
Ty = typeElementType(Ty);
assert(getSrcSize() == 2);
emitIASRegOpTyXMM(Func, Ty, getDest(), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopXmm(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 2, Dest) {
addSource(Dest);
addSource(Source);
}
static const char *Opcode;
static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter;
};
void emitIASXmmShift(const Cfg *Func, Type Ty, const Variable *Var,
const Operand *Src,
const X8632::AssemblerX8632::XmmEmitterShiftOp &Emitter);
template <InstX8632::InstKindX8632 K, bool AllowAllTypes = false>
class InstX8632BinopXmmShift : public InstX8632 {
InstX8632BinopXmmShift() = delete;
InstX8632BinopXmmShift(const InstX8632BinopXmmShift &) = delete;
InstX8632BinopXmmShift &operator=(const InstX8632BinopXmmShift &) = delete;
public:
/// Create an XMM binary-op shift operation.
static InstX8632BinopXmmShift *create(Cfg *Func, Variable *Dest,
Operand *Source) {
return new (Func->allocate<InstX8632BinopXmmShift>())
InstX8632BinopXmmShift(Func, Dest, Source);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
validateVectorAddrMode();
const bool ShiftHack = false;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
validateVectorAddrMode();
Type Ty = getDest()->getType();
assert(AllowAllTypes || isVectorType(Ty));
Type ElementTy = typeElementType(Ty);
assert(getSrcSize() == 2);
emitIASXmmShift(Func, ElementTy, getDest(), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopXmmShift(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 2, Dest) {
addSource(Dest);
addSource(Source);
}
static const char *Opcode;
static const X8632::AssemblerX8632::XmmEmitterShiftOp Emitter;
};
template <InstX8632::InstKindX8632 K> class InstX8632Ternop : public InstX8632 {
InstX8632Ternop() = delete;
InstX8632Ternop(const InstX8632Ternop &) = delete;
InstX8632Ternop &operator=(const InstX8632Ternop &) = delete;
public:
/// Create a ternary-op instruction like div or idiv.
static InstX8632Ternop *create(Cfg *Func, Variable *Dest, Operand *Source1,
Operand *Source2) {
return new (Func->allocate<InstX8632Ternop>())
InstX8632Ternop(Func, Dest, Source1, Source2);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 3);
Str << "\t" << Opcode << "\t";
getSrc(2)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", ";
getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632Ternop(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2)
: InstX8632(Func, K, 3, Dest) {
addSource(Dest);
addSource(Source1);
addSource(Source2);
}
static const char *Opcode;
};
/// Instructions of the form x := y op z
template <InstX8632::InstKindX8632 K>
class InstX8632ThreeAddressop : public InstX8632 {
InstX8632ThreeAddressop() = delete;
InstX8632ThreeAddressop(const InstX8632ThreeAddressop &) = delete;
InstX8632ThreeAddressop &operator=(const InstX8632ThreeAddressop &) = delete;
public:
static InstX8632ThreeAddressop *create(Cfg *Func, Variable *Dest,
Operand *Source0, Operand *Source1) {
return new (Func->allocate<InstX8632ThreeAddressop>())
InstX8632ThreeAddressop(Func, Dest, Source0, Source1);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 2);
Str << "\t" << Opcode << "\t";
getSrc(1)->emit(Func);
Str << ", ";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
}
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632ThreeAddressop(Cfg *Func, Variable *Dest, Operand *Source0,
Operand *Source1)
: InstX8632(Func, K, 2, Dest) {
addSource(Source0);
addSource(Source1);
}
static const char *Opcode;
};
/// Base class for assignment instructions
template <InstX8632::InstKindX8632 K>
class InstX8632Movlike : public InstX8632 {
InstX8632Movlike() = delete;
InstX8632Movlike(const InstX8632Movlike &) = delete;
InstX8632Movlike &operator=(const InstX8632Movlike &) = delete;
public:
static InstX8632Movlike *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX8632Movlike>())
InstX8632Movlike(Func, Dest, Source);
}
bool isRedundantAssign() const override {
return checkForRedundantAssign(getDest(), getSrc(0));
}
bool isSimpleAssign() const override { return true; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << Opcode << "." << getDest()->getType() << " ";
dumpDest(Func);
Str << ", ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632Movlike(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 1, Dest) {
addSource(Source);
}
static const char *Opcode;
};
typedef InstX8632InplaceopGPR<InstX8632::Bswap> InstX8632Bswap;
typedef InstX8632InplaceopGPR<InstX8632::Neg> InstX8632Neg;
typedef InstX8632UnaryopGPR<InstX8632::Bsf> InstX8632Bsf;
typedef InstX8632UnaryopGPR<InstX8632::Bsr> InstX8632Bsr;
typedef InstX8632UnaryopGPR<InstX8632::Lea> InstX8632Lea;
/// Cbwdq instruction - wrapper for cbw, cwd, and cdq
typedef InstX8632UnaryopGPR<InstX8632::Cbwdq> InstX8632Cbwdq;
typedef InstX8632UnaryopGPR<InstX8632::Movsx> InstX8632Movsx;
typedef InstX8632UnaryopGPR<InstX8632::Movzx> InstX8632Movzx;
typedef InstX8632UnaryopXmm<InstX8632::Movd> InstX8632Movd;
typedef InstX8632UnaryopXmm<InstX8632::Sqrtss> InstX8632Sqrtss;
/// Move/assignment instruction - wrapper for mov/movss/movsd.
typedef InstX8632Movlike<InstX8632::Mov> InstX8632Mov;
/// Move packed - copy 128 bit values between XMM registers, or mem128
/// and XMM registers.
typedef InstX8632Movlike<InstX8632::Movp> InstX8632Movp;
/// Movq - copy between XMM registers, or mem64 and XMM registers.
typedef InstX8632Movlike<InstX8632::Movq> InstX8632Movq;
typedef InstX8632BinopGPR<InstX8632::Add> InstX8632Add;
typedef InstX8632BinopRMW<InstX8632::AddRMW> InstX8632AddRMW;
typedef InstX8632BinopXmm<InstX8632::Addps, true> InstX8632Addps;
typedef InstX8632BinopGPR<InstX8632::Adc> InstX8632Adc;
typedef InstX8632BinopRMW<InstX8632::AdcRMW> InstX8632AdcRMW;
typedef InstX8632BinopXmm<InstX8632::Addss, false> InstX8632Addss;
typedef InstX8632BinopXmm<InstX8632::Padd, true> InstX8632Padd;
typedef InstX8632BinopGPR<InstX8632::Sub> InstX8632Sub;
typedef InstX8632BinopRMW<InstX8632::SubRMW> InstX8632SubRMW;
typedef InstX8632BinopXmm<InstX8632::Subps, true> InstX8632Subps;
typedef InstX8632BinopXmm<InstX8632::Subss, false> InstX8632Subss;
typedef InstX8632BinopGPR<InstX8632::Sbb> InstX8632Sbb;
typedef InstX8632BinopRMW<InstX8632::SbbRMW> InstX8632SbbRMW;
typedef InstX8632BinopXmm<InstX8632::Psub, true> InstX8632Psub;
typedef InstX8632BinopGPR<InstX8632::And> InstX8632And;
typedef InstX8632BinopRMW<InstX8632::AndRMW> InstX8632AndRMW;
typedef InstX8632BinopXmm<InstX8632::Pand, false> InstX8632Pand;
typedef InstX8632BinopXmm<InstX8632::Pandn, false> InstX8632Pandn;
typedef InstX8632BinopGPR<InstX8632::Or> InstX8632Or;
typedef InstX8632BinopRMW<InstX8632::OrRMW> InstX8632OrRMW;
typedef InstX8632BinopXmm<InstX8632::Por, false> InstX8632Por;
typedef InstX8632BinopGPR<InstX8632::Xor> InstX8632Xor;
typedef InstX8632BinopRMW<InstX8632::XorRMW> InstX8632XorRMW;
typedef InstX8632BinopXmm<InstX8632::Pxor, false> InstX8632Pxor;
typedef InstX8632BinopGPR<InstX8632::Imul> InstX8632Imul;
typedef InstX8632BinopXmm<InstX8632::Mulps, true> InstX8632Mulps;
typedef InstX8632BinopXmm<InstX8632::Mulss, false> InstX8632Mulss;
typedef InstX8632BinopXmm<InstX8632::Pmull, true> InstX8632Pmull;
typedef InstX8632BinopXmm<InstX8632::Pmuludq, false> InstX8632Pmuludq;
typedef InstX8632BinopXmm<InstX8632::Divps, true> InstX8632Divps;
typedef InstX8632BinopXmm<InstX8632::Divss, false> InstX8632Divss;
typedef InstX8632BinopGPRShift<InstX8632::Rol> InstX8632Rol;
typedef InstX8632BinopGPRShift<InstX8632::Shl> InstX8632Shl;
typedef InstX8632BinopXmmShift<InstX8632::Psll> InstX8632Psll;
typedef InstX8632BinopXmmShift<InstX8632::Psrl, true> InstX8632Psrl;
typedef InstX8632BinopGPRShift<InstX8632::Shr> InstX8632Shr;
typedef InstX8632BinopGPRShift<InstX8632::Sar> InstX8632Sar;
typedef InstX8632BinopXmmShift<InstX8632::Psra> InstX8632Psra;
typedef InstX8632BinopXmm<InstX8632::Pcmpeq, true> InstX8632Pcmpeq;
typedef InstX8632BinopXmm<InstX8632::Pcmpgt, true> InstX8632Pcmpgt;
/// 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).
/// InstX8632Movss 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.
typedef InstX8632BinopXmm<InstX8632::MovssRegs, false> InstX8632MovssRegs;
typedef InstX8632Ternop<InstX8632::Idiv> InstX8632Idiv;
typedef InstX8632Ternop<InstX8632::Div> InstX8632Div;
typedef InstX8632Ternop<InstX8632::Insertps> InstX8632Insertps;
typedef InstX8632Ternop<InstX8632::Pinsr> InstX8632Pinsr;
typedef InstX8632Ternop<InstX8632::Shufps> InstX8632Shufps;
typedef InstX8632Ternop<InstX8632::Blendvps> InstX8632Blendvps;
typedef InstX8632Ternop<InstX8632::Pblendvb> InstX8632Pblendvb;
typedef InstX8632ThreeAddressop<InstX8632::Pextr> InstX8632Pextr;
typedef InstX8632ThreeAddressop<InstX8632::Pshufd> InstX8632Pshufd;
/// Base class for a lockable x86-32 instruction (emits a locked prefix).
class InstX8632Lockable : public InstX8632 {
InstX8632Lockable() = delete;
InstX8632Lockable(const InstX8632Lockable &) = delete;
InstX8632Lockable &operator=(const InstX8632Lockable &) = delete;
protected:
bool Locked;
InstX8632Lockable(Cfg *Func, InstKindX8632 Kind, SizeT Maxsrcs,
Variable *Dest, bool Locked)
: InstX8632(Func, Kind, Maxsrcs, Dest), Locked(Locked) {
// Assume that such instructions are used for Atomics and be careful
// with optimizations.
HasSideEffects = Locked;
}
};
/// Mul instruction - unsigned multiply.
class InstX8632Mul : public InstX8632 {
InstX8632Mul() = delete;
InstX8632Mul(const InstX8632Mul &) = delete;
InstX8632Mul &operator=(const InstX8632Mul &) = delete;
public:
static InstX8632Mul *create(Cfg *Func, Variable *Dest, Variable *Source1,
Operand *Source2) {
return new (Func->allocate<InstX8632Mul>())
InstX8632Mul(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 isClassof(Inst, Mul); }
private:
InstX8632Mul(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2);
};
/// Shld instruction - shift across a pair of operands.
class InstX8632Shld : public InstX8632 {
InstX8632Shld() = delete;
InstX8632Shld(const InstX8632Shld &) = delete;
InstX8632Shld &operator=(const InstX8632Shld &) = delete;
public:
static InstX8632Shld *create(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2) {
return new (Func->allocate<InstX8632Shld>())
InstX8632Shld(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 isClassof(Inst, Shld); }
private:
InstX8632Shld(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2);
};
/// Shrd instruction - shift across a pair of operands.
class InstX8632Shrd : public InstX8632 {
InstX8632Shrd() = delete;
InstX8632Shrd(const InstX8632Shrd &) = delete;
InstX8632Shrd &operator=(const InstX8632Shrd &) = delete;
public:
static InstX8632Shrd *create(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2) {
return new (Func->allocate<InstX8632Shrd>())
InstX8632Shrd(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 isClassof(Inst, Shrd); }
private:
InstX8632Shrd(Cfg *Func, Variable *Dest, Variable *Source1,
Variable *Source2);
};
/// Conditional move instruction.
class InstX8632Cmov : public InstX8632 {
InstX8632Cmov() = delete;
InstX8632Cmov(const InstX8632Cmov &) = delete;
InstX8632Cmov &operator=(const InstX8632Cmov &) = delete;
public:
static InstX8632Cmov *create(Cfg *Func, Variable *Dest, Operand *Source,
X8632::Traits::Cond::BrCond Cond) {
return new (Func->allocate<InstX8632Cmov>())
InstX8632Cmov(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 isClassof(Inst, Cmov); }
private:
InstX8632Cmov(Cfg *Func, Variable *Dest, Operand *Source,
X8632::Traits::Cond::BrCond Cond);
X8632::Traits::Cond::BrCond Condition;
};
/// Cmpps instruction - compare packed singled-precision floating point
/// values
class InstX8632Cmpps : public InstX8632 {
InstX8632Cmpps() = delete;
InstX8632Cmpps(const InstX8632Cmpps &) = delete;
InstX8632Cmpps &operator=(const InstX8632Cmpps &) = delete;
public:
static InstX8632Cmpps *create(Cfg *Func, Variable *Dest, Operand *Source,
X8632::Traits::Cond::CmppsCond Condition) {
return new (Func->allocate<InstX8632Cmpps>())
InstX8632Cmpps(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 isClassof(Inst, Cmpps); }
private:
InstX8632Cmpps(Cfg *Func, Variable *Dest, Operand *Source,
X8632::Traits::Cond::CmppsCond Cond);
X8632::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.
class InstX8632Cmpxchg : public InstX8632Lockable {
InstX8632Cmpxchg() = delete;
InstX8632Cmpxchg(const InstX8632Cmpxchg &) = delete;
InstX8632Cmpxchg &operator=(const InstX8632Cmpxchg &) = delete;
public:
static InstX8632Cmpxchg *create(Cfg *Func, Operand *DestOrAddr, Variable *Eax,
Variable *Desired, bool Locked) {
return new (Func->allocate<InstX8632Cmpxchg>())
InstX8632Cmpxchg(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 isClassof(Inst, Cmpxchg); }
private:
InstX8632Cmpxchg(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.
class InstX8632Cmpxchg8b : public InstX8632Lockable {
InstX8632Cmpxchg8b() = delete;
InstX8632Cmpxchg8b(const InstX8632Cmpxchg8b &) = delete;
InstX8632Cmpxchg8b &operator=(const InstX8632Cmpxchg8b &) = delete;
public:
static InstX8632Cmpxchg8b *create(Cfg *Func, OperandX8632Mem *Dest,
Variable *Edx, Variable *Eax, Variable *Ecx,
Variable *Ebx, bool Locked) {
return new (Func->allocate<InstX8632Cmpxchg8b>())
InstX8632Cmpxchg8b(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 isClassof(Inst, Cmpxchg8b); }
private:
InstX8632Cmpxchg8b(Cfg *Func, OperandX8632Mem *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.
class InstX8632Cvt : public InstX8632 {
InstX8632Cvt() = delete;
InstX8632Cvt(const InstX8632Cvt &) = delete;
InstX8632Cvt &operator=(const InstX8632Cvt &) = delete;
public:
enum CvtVariant { Si2ss, Tss2si, Float2float, Dq2ps, Tps2dq };
static InstX8632Cvt *create(Cfg *Func, Variable *Dest, Operand *Source,
CvtVariant Variant) {
return new (Func->allocate<InstX8632Cvt>())
InstX8632Cvt(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 isClassof(Inst, Cvt); }
bool isTruncating() const { return Variant == Tss2si || Variant == Tps2dq; }
private:
CvtVariant Variant;
InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant);
};
/// cmp - Integer compare instruction.
class InstX8632Icmp : public InstX8632 {
InstX8632Icmp() = delete;
InstX8632Icmp(const InstX8632Icmp &) = delete;
InstX8632Icmp &operator=(const InstX8632Icmp &) = delete;
public:
static InstX8632Icmp *create(Cfg *Func, Operand *Src1, Operand *Src2) {
return new (Func->allocate<InstX8632Icmp>())
InstX8632Icmp(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 isClassof(Inst, Icmp); }
private:
InstX8632Icmp(Cfg *Func, Operand *Src1, Operand *Src2);
};
/// ucomiss/ucomisd - floating-point compare instruction.
class InstX8632Ucomiss : public InstX8632 {
InstX8632Ucomiss() = delete;
InstX8632Ucomiss(const InstX8632Ucomiss &) = delete;
InstX8632Ucomiss &operator=(const InstX8632Ucomiss &) = delete;
public:
static InstX8632Ucomiss *create(Cfg *Func, Operand *Src1, Operand *Src2) {
return new (Func->allocate<InstX8632Ucomiss>())
InstX8632Ucomiss(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 isClassof(Inst, Ucomiss); }
private:
InstX8632Ucomiss(Cfg *Func, Operand *Src1, Operand *Src2);
};
/// UD2 instruction.
class InstX8632UD2 : public InstX8632 {
InstX8632UD2() = delete;
InstX8632UD2(const InstX8632UD2 &) = delete;
InstX8632UD2 &operator=(const InstX8632UD2 &) = delete;
public:
static InstX8632UD2 *create(Cfg *Func) {
return new (Func->allocate<InstX8632UD2>()) InstX8632UD2(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 isClassof(Inst, UD2); }
private:
explicit InstX8632UD2(Cfg *Func);
};
/// Test instruction.
class InstX8632Test : public InstX8632 {
InstX8632Test() = delete;
InstX8632Test(const InstX8632Test &) = delete;
InstX8632Test &operator=(const InstX8632Test &) = delete;
public:
static InstX8632Test *create(Cfg *Func, Operand *Source1, Operand *Source2) {
return new (Func->allocate<InstX8632Test>())
InstX8632Test(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 isClassof(Inst, Test); }
private:
InstX8632Test(Cfg *Func, Operand *Source1, Operand *Source2);
};
/// Mfence instruction.
class InstX8632Mfence : public InstX8632 {
InstX8632Mfence() = delete;
InstX8632Mfence(const InstX8632Mfence &) = delete;
InstX8632Mfence &operator=(const InstX8632Mfence &) = delete;
public:
static InstX8632Mfence *create(Cfg *Func) {
return new (Func->allocate<InstX8632Mfence>()) InstX8632Mfence(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 isClassof(Inst, Mfence); }
private:
explicit InstX8632Mfence(Cfg *Func);
};
/// This is essentially a "mov" instruction with an OperandX8632Mem
/// operand instead of Variable as the destination. It's important
/// for liveness that there is no Dest operand.
class InstX8632Store : public InstX8632 {
InstX8632Store() = delete;
InstX8632Store(const InstX8632Store &) = delete;
InstX8632Store &operator=(const InstX8632Store &) = delete;
public:
static InstX8632Store *create(Cfg *Func, Operand *Value, OperandX8632 *Mem) {
return new (Func->allocate<InstX8632Store>())
InstX8632Store(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 isClassof(Inst, Store); }
private:
InstX8632Store(Cfg *Func, Operand *Value, OperandX8632 *Mem);
};
/// This is essentially a vector "mov" instruction with an OperandX8632Mem
/// 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.
class InstX8632StoreP : public InstX8632 {
InstX8632StoreP() = delete;
InstX8632StoreP(const InstX8632StoreP &) = delete;
InstX8632StoreP &operator=(const InstX8632StoreP &) = delete;
public:
static InstX8632StoreP *create(Cfg *Func, Variable *Value,
OperandX8632Mem *Mem) {
return new (Func->allocate<InstX8632StoreP>())
InstX8632StoreP(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 isClassof(Inst, StoreP); }
private:
InstX8632StoreP(Cfg *Func, Variable *Value, OperandX8632Mem *Mem);
};
class InstX8632StoreQ : public InstX8632 {
InstX8632StoreQ() = delete;
InstX8632StoreQ(const InstX8632StoreQ &) = delete;
InstX8632StoreQ &operator=(const InstX8632StoreQ &) = delete;
public:
static InstX8632StoreQ *create(Cfg *Func, Variable *Value,
OperandX8632Mem *Mem) {
return new (Func->allocate<InstX8632StoreQ>())
InstX8632StoreQ(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 isClassof(Inst, StoreQ); }
private:
InstX8632StoreQ(Cfg *Func, Variable *Value, OperandX8632Mem *Mem);
};
/// Nop instructions of varying length
class InstX8632Nop : public InstX8632 {
InstX8632Nop() = delete;
InstX8632Nop(const InstX8632Nop &) = delete;
InstX8632Nop &operator=(const InstX8632Nop &) = delete;
public:
// TODO: Replace with enum.
typedef unsigned NopVariant;
static InstX8632Nop *create(Cfg *Func, NopVariant Variant) {
return new (Func->allocate<InstX8632Nop>()) InstX8632Nop(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 isClassof(Inst, Nop); }
private:
InstX8632Nop(Cfg *Func, SizeT Length);
NopVariant Variant;
};
/// Fld - load a value onto the x87 FP stack.
class InstX8632Fld : public InstX8632 {
InstX8632Fld() = delete;
InstX8632Fld(const InstX8632Fld &) = delete;
InstX8632Fld &operator=(const InstX8632Fld &) = delete;
public:
static InstX8632Fld *create(Cfg *Func, Operand *Src) {
return new (Func->allocate<InstX8632Fld>()) InstX8632Fld(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 isClassof(Inst, Fld); }
private:
InstX8632Fld(Cfg *Func, Operand *Src);
};
/// Fstp - store x87 st(0) into memory and pop st(0).
class InstX8632Fstp : public InstX8632 {
InstX8632Fstp() = delete;
InstX8632Fstp(const InstX8632Fstp &) = delete;
InstX8632Fstp &operator=(const InstX8632Fstp &) = delete;
public:
static InstX8632Fstp *create(Cfg *Func, Variable *Dest) {
return new (Func->allocate<InstX8632Fstp>()) InstX8632Fstp(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 isClassof(Inst, Fstp); }
private:
InstX8632Fstp(Cfg *Func, Variable *Dest);
};
class InstX8632Pop : public InstX8632 {
InstX8632Pop() = delete;
InstX8632Pop(const InstX8632Pop &) = delete;
InstX8632Pop &operator=(const InstX8632Pop &) = delete;
public:
static InstX8632Pop *create(Cfg *Func, Variable *Dest) {
return new (Func->allocate<InstX8632Pop>()) InstX8632Pop(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 isClassof(Inst, Pop); }
private:
InstX8632Pop(Cfg *Func, Variable *Dest);
};
class InstX8632Push : public InstX8632 {
InstX8632Push() = delete;
InstX8632Push(const InstX8632Push &) = delete;
InstX8632Push &operator=(const InstX8632Push &) = delete;
public:
static InstX8632Push *create(Cfg *Func, Variable *Source) {
return new (Func->allocate<InstX8632Push>()) InstX8632Push(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 isClassof(Inst, Push); }
private:
InstX8632Push(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.
class InstX8632Ret : public InstX8632 {
InstX8632Ret() = delete;
InstX8632Ret(const InstX8632Ret &) = delete;
InstX8632Ret &operator=(const InstX8632Ret &) = delete;
public:
static InstX8632Ret *create(Cfg *Func, Variable *Source = nullptr) {
return new (Func->allocate<InstX8632Ret>()) InstX8632Ret(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 isClassof(Inst, Ret); }
private:
InstX8632Ret(Cfg *Func, Variable *Source);
};
/// Conditional set-byte instruction.
class InstX8632Setcc : public InstX8632 {
InstX8632Setcc() = delete;
InstX8632Setcc(const InstX8632Cmov &) = delete;
InstX8632Setcc &operator=(const InstX8632Setcc &) = delete;
public:
static InstX8632Setcc *create(Cfg *Func, Variable *Dest,
X8632::Traits::Cond::BrCond Cond) {
return new (Func->allocate<InstX8632Setcc>())
InstX8632Setcc(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 isClassof(Inst, Setcc); }
private:
InstX8632Setcc(Cfg *Func, Variable *Dest, X8632::Traits::Cond::BrCond Cond);
const X8632::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.
class InstX8632Xadd : public InstX8632Lockable {
InstX8632Xadd() = delete;
InstX8632Xadd(const InstX8632Xadd &) = delete;
InstX8632Xadd &operator=(const InstX8632Xadd &) = delete;
public:
static InstX8632Xadd *create(Cfg *Func, Operand *Dest, Variable *Source,
bool Locked) {
return new (Func->allocate<InstX8632Xadd>())
InstX8632Xadd(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 isClassof(Inst, Xadd); }
private:
InstX8632Xadd(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.
class InstX8632Xchg : public InstX8632 {
InstX8632Xchg() = delete;
InstX8632Xchg(const InstX8632Xchg &) = delete;
InstX8632Xchg &operator=(const InstX8632Xchg &) = delete;
public:
static InstX8632Xchg *create(Cfg *Func, Operand *Dest, Variable *Source) {
return new (Func->allocate<InstX8632Xchg>())
InstX8632Xchg(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 isClassof(Inst, Xchg); }
private:
InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source);
};
/// Declare partial template specializations of emit() methods that
/// already have default implementations. Without this, there is the
/// possibility of ODR violations and link errors.
template <> void InstX8632Addss::emit(const Cfg *Func) const;
template <> void InstX8632Blendvps::emit(const Cfg *Func) const;
template <> void InstX8632Cbwdq::emit(const Cfg *Func) const;
template <> void InstX8632Div::emit(const Cfg *Func) const;
template <> void InstX8632Divss::emit(const Cfg *Func) const;
template <> void InstX8632Idiv::emit(const Cfg *Func) const;
template <> void InstX8632Imul::emit(const Cfg *Func) const;
template <> void InstX8632Lea::emit(const Cfg *Func) const;
template <> void InstX8632Mulss::emit(const Cfg *Func) const;
template <> void InstX8632Padd::emit(const Cfg *Func) const;
template <> void InstX8632Pblendvb::emit(const Cfg *Func) const;
template <> void InstX8632Pcmpeq::emit(const Cfg *Func) const;
template <> void InstX8632Pcmpgt::emit(const Cfg *Func) const;
template <> void InstX8632Pextr::emit(const Cfg *Func) const;
template <> void InstX8632Pinsr::emit(const Cfg *Func) const;
template <> void InstX8632Pmull::emit(const Cfg *Func) const;
template <> void InstX8632Pmuludq::emit(const Cfg *Func) const;
template <> void InstX8632Psll::emit(const Cfg *Func) const;
template <> void InstX8632Psra::emit(const Cfg *Func) const;
template <> void InstX8632Psrl::emit(const Cfg *Func) const;
template <> void InstX8632Psub::emit(const Cfg *Func) const;
template <> void InstX8632Sqrtss::emit(const Cfg *Func) const;
template <> void InstX8632Subss::emit(const Cfg *Func) const;
template <> void InstX8632Blendvps::emitIAS(const Cfg *Func) const;
template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const;
template <> void InstX8632Div::emitIAS(const Cfg *Func) const;
template <> void InstX8632Idiv::emitIAS(const Cfg *Func) const;
template <> void InstX8632Imul::emitIAS(const Cfg *Func) const;
template <> void InstX8632Insertps::emitIAS(const Cfg *Func) const;
template <> void InstX8632Movd::emitIAS(const Cfg *Func) const;
template <> void InstX8632MovssRegs::emitIAS(const Cfg *Func) const;
template <> void InstX8632Pblendvb::emitIAS(const Cfg *Func) const;
template <> void InstX8632Pextr::emitIAS(const Cfg *Func) const;
template <> void InstX8632Pinsr::emitIAS(const Cfg *Func) const;
template <> void InstX8632Movsx::emitIAS(const Cfg *Func) const;
template <> void InstX8632Movzx::emitIAS(const Cfg *Func) const;
template <> void InstX8632Pmull::emitIAS(const Cfg *Func) const;
template <> void InstX8632Pshufd::emitIAS(const Cfg *Func) const;
template <> void InstX8632Shufps::emitIAS(const Cfg *Func) const;
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEINSTX8632_H #endif // SUBZERO_SRC_ICEINSTX8632_H
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -77,6 +77,7 @@ const size_t MachineTraits<TargetX8632>::TableTypeX8632AttributesSize = ...@@ -77,6 +77,7 @@ const size_t MachineTraits<TargetX8632>::TableTypeX8632AttributesSize =
llvm::array_lengthof(TableTypeX8632Attributes); llvm::array_lengthof(TableTypeX8632Attributes);
const uint32_t MachineTraits<TargetX8632>::X86_STACK_ALIGNMENT_BYTES = 16; const uint32_t MachineTraits<TargetX8632>::X86_STACK_ALIGNMENT_BYTES = 16;
const char *MachineTraits<TargetX8632>::TargetName = "X8632";
} // end of namespace X86Internal } // end of namespace X86Internal
......
...@@ -6,9 +6,10 @@ ...@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details. // License. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ///
// This file defines the X8632 Target Lowering Traits. /// \file
// /// This file declares the X8632 Target Lowering Traits.
///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H #ifndef SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H
...@@ -19,15 +20,22 @@ ...@@ -19,15 +20,22 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceInstX8632.def" #include "IceInstX8632.def"
#include "IceOperand.h"
#include "IceRegistersX8632.h" #include "IceRegistersX8632.h"
#include "IceTargetLoweringX8632.def" #include "IceTargetLoweringX8632.def"
#include "IceTargetLowering.h"
namespace Ice { namespace Ice {
class TargetX8632; class TargetX8632;
namespace X8632 {
class AssemblerX8632;
} // end of namespace X8632
namespace X86Internal { namespace X86Internal {
template <class Machine> struct Insts;
template <class Machine> struct MachineTraits; template <class Machine> struct MachineTraits;
template <> struct MachineTraits<TargetX8632> { template <> struct MachineTraits<TargetX8632> {
...@@ -56,7 +64,7 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -56,7 +64,7 @@ template <> struct MachineTraits<TargetX8632> {
class Operand { class Operand {
public: public:
Operand(const Operand &other) Operand(const Operand &other)
: length_(other.length_), fixup_(other.fixup_) { : fixup_(other.fixup_), length_(other.length_) {
memmove(&encoding_[0], &other.encoding_[0], other.length_); memmove(&encoding_[0], &other.encoding_[0], other.length_);
} }
...@@ -98,7 +106,7 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -98,7 +106,7 @@ template <> struct MachineTraits<TargetX8632> {
AssemblerFixup *fixup() const { return fixup_; } AssemblerFixup *fixup() const { return fixup_; }
protected: protected:
Operand() : length_(0), fixup_(nullptr) {} // Needed by subclass Address. Operand() : fixup_(nullptr), length_(0) {} // Needed by subclass Address.
void SetModRM(int mod, GPRRegister rm) { void SetModRM(int mod, GPRRegister rm) {
assert((mod & ~3) == 0); assert((mod & ~3) == 0);
...@@ -128,20 +136,20 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -128,20 +136,20 @@ template <> struct MachineTraits<TargetX8632> {
void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; } void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; }
private: private:
uint8_t length_;
uint8_t encoding_[6];
AssemblerFixup *fixup_; AssemblerFixup *fixup_;
uint8_t encoding_[6];
uint8_t length_;
explicit Operand(GPRRegister reg) : fixup_(nullptr) { SetModRM(3, reg); } explicit Operand(GPRRegister reg) : fixup_(nullptr) { SetModRM(3, reg); }
// Get the operand encoding byte at the given index. /// Get the operand encoding byte at the given index.
uint8_t encoding_at(intptr_t index) const { uint8_t encoding_at(intptr_t index) const {
assert(index >= 0 && index < length_); assert(index >= 0 && index < length_);
return encoding_[index]; return encoding_[index];
} }
// Returns whether or not this operand is really the given register in /// Returns whether or not this operand is really the given register in
// disguise. Used from the assembler to generate better encodings. /// disguise. Used from the assembler to generate better encodings.
bool IsRegister(GPRRegister reg) const { bool IsRegister(GPRRegister reg) const {
return ((encoding_[0] & 0xF8) == return ((encoding_[0] & 0xF8) ==
0xC0) // Addressing mode is register only. 0xC0) // Addressing mode is register only.
...@@ -205,8 +213,8 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -205,8 +213,8 @@ template <> struct MachineTraits<TargetX8632> {
} }
} }
// AbsoluteTag is a special tag used by clients to create an absolute /// AbsoluteTag is a special tag used by clients to create an absolute
// Address. /// Address.
enum AbsoluteTag { ABSOLUTE }; enum AbsoluteTag { ABSOLUTE };
Address(AbsoluteTag, const uintptr_t Addr) { Address(AbsoluteTag, const uintptr_t Addr) {
...@@ -255,27 +263,182 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -255,27 +263,182 @@ template <> struct MachineTraits<TargetX8632> {
End End
}; };
// The maximum number of arguments to pass in XMM registers static const char *TargetName;
static IceString getRegName(SizeT RegNum, Type Ty) {
assert(RegNum < RegisterSet::Reg_NUM);
static const char *RegNames8[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name8,
REGX8632_TABLE
#undef X
};
static const char *RegNames16[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name16,
REGX8632_TABLE
#undef X
};
static const char *RegNames[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name,
REGX8632_TABLE
#undef X
};
switch (Ty) {
case IceType_i1:
case IceType_i8:
return RegNames8[RegNum];
case IceType_i16:
return RegNames16[RegNum];
default:
return RegNames[RegNum];
}
}
static void initRegisterSet(llvm::SmallBitVector *IntegerRegisters,
llvm::SmallBitVector *IntegerRegistersI8,
llvm::SmallBitVector *FloatRegisters,
llvm::SmallBitVector *VectorRegisters,
llvm::SmallBitVector *ScratchRegs) {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
(*IntegerRegisters)[RegisterSet::val] = isInt; \
(*IntegerRegistersI8)[RegisterSet::val] = isI8; \
(*FloatRegisters)[RegisterSet::val] = isFP; \
(*VectorRegisters)[RegisterSet::val] = isFP; \
(*ScratchRegs)[RegisterSet::val] = scratch;
REGX8632_TABLE;
#undef X
}
static llvm::SmallBitVector
getRegisterSet(TargetLowering::RegSetMask Include,
TargetLowering::RegSetMask Exclude) {
llvm::SmallBitVector Registers(RegisterSet::Reg_NUM);
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
if (scratch && (Include & ::Ice::TargetLowering::RegSet_CallerSave)) \
Registers[RegisterSet::val] = true; \
if (preserved && (Include & ::Ice::TargetLowering::RegSet_CalleeSave)) \
Registers[RegisterSet::val] = true; \
if (stackptr && (Include & ::Ice::TargetLowering::RegSet_StackPointer)) \
Registers[RegisterSet::val] = true; \
if (frameptr && (Include & ::Ice::TargetLowering::RegSet_FramePointer)) \
Registers[RegisterSet::val] = true; \
if (scratch && (Exclude & ::Ice::TargetLowering::RegSet_CallerSave)) \
Registers[RegisterSet::val] = false; \
if (preserved && (Exclude & ::Ice::TargetLowering::RegSet_CalleeSave)) \
Registers[RegisterSet::val] = false; \
if (stackptr && (Exclude & ::Ice::TargetLowering::RegSet_StackPointer)) \
Registers[RegisterSet::val] = false; \
if (frameptr && (Exclude & ::Ice::TargetLowering::RegSet_FramePointer)) \
Registers[RegisterSet::val] = false;
REGX8632_TABLE
#undef X
return Registers;
}
static void
makeRandomRegisterPermutation(GlobalContext *Ctx, Cfg *Func,
llvm::SmallVectorImpl<int32_t> &Permutation,
const llvm::SmallBitVector &ExcludeRegisters) {
// TODO(stichnot): Declaring Permutation this way loses type/size
// information. Fix this in conjunction with the caller-side TODO.
assert(Permutation.size() >= RegisterSet::Reg_NUM);
// Expected upper bound on the number of registers in a single equivalence
// class. For x86-32, this would comprise the 8 XMM registers. This is for
// performance, not correctness.
static const unsigned MaxEquivalenceClassSize = 8;
typedef llvm::SmallVector<int32_t, MaxEquivalenceClassSize> RegisterList;
typedef std::map<uint32_t, RegisterList> EquivalenceClassMap;
EquivalenceClassMap EquivalenceClasses;
SizeT NumShuffled = 0, NumPreserved = 0;
// Build up the equivalence classes of registers by looking at the register
// properties as well as whether the registers should be explicitly excluded
// from shuffling.
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
if (ExcludeRegisters[RegisterSet::val]) { \
/* val stays the same in the resulting permutation. */ \
Permutation[RegisterSet::val] = RegisterSet::val; \
++NumPreserved; \
} else { \
const uint32_t Index = (scratch << 0) | (preserved << 1) | (isI8 << 2) | \
(isInt << 3) | (isFP << 4); \
/* val is assigned to an equivalence class based on its properties. */ \
EquivalenceClasses[Index].push_back(RegisterSet::val); \
}
REGX8632_TABLE
#undef X
RandomNumberGeneratorWrapper RNG(Ctx->getRNG());
// Shuffle the resulting equivalence classes.
for (auto I : EquivalenceClasses) {
const RegisterList &List = I.second;
RegisterList Shuffled(List);
RandomShuffle(Shuffled.begin(), Shuffled.end(), RNG);
for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) {
Permutation[List[SI]] = Shuffled[SI];
++NumShuffled;
}
}
assert(NumShuffled + NumPreserved == RegisterSet::Reg_NUM);
if (Func->isVerbose(IceV_Random)) {
OstreamLocker L(Func->getContext());
Ostream &Str = Func->getContext()->getStrDump();
Str << "Register equivalence classes:\n";
for (auto I : EquivalenceClasses) {
Str << "{";
const RegisterList &List = I.second;
bool First = true;
for (int32_t Register : List) {
if (!First)
Str << " ";
First = false;
Str << getRegName(Register, IceType_i32);
}
Str << "}\n";
}
}
}
/// The maximum number of arguments to pass in XMM registers
static const uint32_t X86_MAX_XMM_ARGS = 4; static const uint32_t X86_MAX_XMM_ARGS = 4;
// The number of bits in a byte /// The number of bits in a byte
static const uint32_t X86_CHAR_BIT = 8; static const uint32_t X86_CHAR_BIT = 8;
// Stack alignment. This is defined in IceTargetLoweringX8632.cpp because it /// Stack alignment. This is defined in IceTargetLoweringX8632.cpp because it
// is used as an argument to std::max(), and the default std::less<T> has an /// is used as an argument to std::max(), and the default std::less<T> has an
// operator(T const&, T const&) which requires this member to have an address. /// operator(T const&, T const&) which requires this member to have an
/// address.
static const uint32_t X86_STACK_ALIGNMENT_BYTES; static const uint32_t X86_STACK_ALIGNMENT_BYTES;
// Size of the return address on the stack /// Size of the return address on the stack
static const uint32_t X86_RET_IP_SIZE_BYTES = 4; static const uint32_t X86_RET_IP_SIZE_BYTES = 4;
// The number of different NOP instructions /// The number of different NOP instructions
static const uint32_t X86_NUM_NOP_VARIANTS = 5; static const uint32_t X86_NUM_NOP_VARIANTS = 5;
// Value is in bytes. Return Value adjusted to the next highest multiple /// Value is in bytes. Return Value adjusted to the next highest multiple
// of the stack alignment. /// of the stack alignment.
static uint32_t applyStackAlignment(uint32_t Value) { static uint32_t applyStackAlignment(uint32_t Value) {
return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES); return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
} }
// Return the type which the elements of the vector have in the X86 /// Return the type which the elements of the vector have in the X86
// representation of the vector. /// representation of the vector.
static Type getInVectorElementType(Type Ty) { static Type getInVectorElementType(Type Ty) {
assert(isVectorType(Ty)); assert(isVectorType(Ty));
size_t Index = static_cast<size_t>(Ty); size_t Index = static_cast<size_t>(Ty);
...@@ -287,51 +450,54 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -287,51 +450,54 @@ template <> struct MachineTraits<TargetX8632> {
// Note: The following data structures are defined in // Note: The following data structures are defined in
// IceTargetLoweringX8632.cpp. // IceTargetLoweringX8632.cpp.
// The following table summarizes the logic for lowering the fcmp /// The following table summarizes the logic for lowering the fcmp
// instruction. There is one table entry for each of the 16 conditions. /// instruction. There is one table entry for each of the 16 conditions.
// ///
// The first four columns describe the case when the operands are /// The first four columns describe the case when the operands are floating
// floating point scalar values. A comment in lowerFcmp() describes the /// point scalar values. A comment in lowerFcmp() describes the lowering
// lowering template. In the most general case, there is a compare /// template. In the most general case, there is a compare followed by two
// followed by two conditional branches, because some fcmp conditions /// conditional branches, because some fcmp conditions don't map to a single
// don't map to a single x86 conditional branch. However, in many cases /// x86 conditional branch. However, in many cases it is possible to swap the
// it is possible to swap the operands in the comparison and have a /// operands in the comparison and have a single conditional branch. Since
// single conditional branch. Since it's quite tedious to validate the /// it's quite tedious to validate the table by hand, good execution tests are
// table by hand, good execution tests are helpful. /// helpful.
// ///
// The last two columns describe the case when the operands are vectors /// The last two columns describe the case when the operands are vectors of
// of floating point values. For most fcmp conditions, there is a clear /// floating point values. For most fcmp conditions, there is a clear mapping
// mapping to a single x86 cmpps instruction variant. Some fcmp /// to a single x86 cmpps instruction variant. Some fcmp conditions require
// conditions require special code to handle and these are marked in the /// special code to handle and these are marked in the table with a
// table with a Cmpps_Invalid predicate. /// Cmpps_Invalid predicate.
/// {@
static const struct TableFcmpType { static const struct TableFcmpType {
uint32_t Default; uint32_t Default;
bool SwapScalarOperands; bool SwapScalarOperands;
CondX86::BrCond C1, C2; Cond::BrCond C1, C2;
bool SwapVectorOperands; bool SwapVectorOperands;
CondX86::CmppsCond Predicate; Cond::CmppsCond Predicate;
} TableFcmp[]; } TableFcmp[];
static const size_t TableFcmpSize; static const size_t TableFcmpSize;
/// @}
// The following table summarizes the logic for lowering the icmp instruction /// The following table summarizes the logic for lowering the icmp instruction
// for i32 and narrower types. Each icmp condition has a clear mapping to an /// for i32 and narrower types. Each icmp condition has a clear mapping to an
// x86 conditional branch instruction. /// x86 conditional branch instruction.
/// {@
static const struct TableIcmp32Type { static const struct TableIcmp32Type { Cond::BrCond Mapping; } TableIcmp32[];
CondX86::BrCond Mapping;
} TableIcmp32[];
static const size_t TableIcmp32Size; static const size_t TableIcmp32Size;
/// @}
// The following table summarizes the logic for lowering the icmp instruction /// The following table summarizes the logic for lowering the icmp instruction
// for the i64 type. For Eq and Ne, two separate 32-bit comparisons and /// for the i64 type. For Eq and Ne, two separate 32-bit comparisons and
// conditional branches are needed. For the other conditions, three separate /// conditional branches are needed. For the other conditions, three separate
// conditional branches are needed. /// conditional branches are needed.
/// {@
static const struct TableIcmp64Type { static const struct TableIcmp64Type {
CondX86::BrCond C1, C2, C3; Cond::BrCond C1, C2, C3;
} TableIcmp64[]; } TableIcmp64[];
static const size_t TableIcmp64Size; static const size_t TableIcmp64Size;
/// @}
static CondX86::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) { static Cond::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) {
size_t Index = static_cast<size_t>(Cond); size_t Index = static_cast<size_t>(Cond);
assert(Index < TableIcmp32Size); assert(Index < TableIcmp32Size);
return TableIcmp32[Index].Mapping; return TableIcmp32[Index].Mapping;
...@@ -341,6 +507,190 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -341,6 +507,190 @@ template <> struct MachineTraits<TargetX8632> {
Type InVectorElementType; Type InVectorElementType;
} TableTypeX8632Attributes[]; } TableTypeX8632Attributes[];
static const size_t TableTypeX8632AttributesSize; static const size_t TableTypeX8632AttributesSize;
//----------------------------------------------------------------------------
// __ __ __ ______ ______
// /\ \/\ "-.\ \/\ ___\/\__ _\
// \ \ \ \ \-. \ \___ \/_/\ \/
// \ \_\ \_\\"\_\/\_____\ \ \_\
// \/_/\/_/ \/_/\/_____/ \/_/
//
//----------------------------------------------------------------------------
using Insts = ::Ice::X86Internal::Insts<TargetX8632>;
using TargetLowering = TargetX8632;
using Assembler = X8632::AssemblerX8632;
/// X86Operand extends the Operand hierarchy. Its subclasses are
/// X86OperandMem and VariableSplit.
class X86Operand : public ::Ice::Operand {
X86Operand() = delete;
X86Operand(const X86Operand &) = delete;
X86Operand &operator=(const X86Operand &) = delete;
public:
enum OperandKindX8632 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit };
using ::Ice::Operand::dump;
void dump(const Cfg *, Ostream &Str) const override;
protected:
X86Operand(OperandKindX8632 Kind, Type Ty)
: Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {}
};
/// X86OperandMem represents the m32 addressing mode, with optional base and
/// index registers, a constant offset, and a fixed shift value for the index
/// register.
class X86OperandMem : public X86Operand {
X86OperandMem() = delete;
X86OperandMem(const X86OperandMem &) = delete;
X86OperandMem &operator=(const X86OperandMem &) = delete;
public:
enum SegmentRegisters {
DefaultSegment = -1,
#define X(val, name, prefix) val,
SEG_REGX8632_TABLE
#undef X
SegReg_NUM
};
static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
Constant *Offset, Variable *Index = nullptr,
uint16_t Shift = 0,
SegmentRegisters SegmentReg = DefaultSegment) {
return new (Func->allocate<X86OperandMem>())
X86OperandMem(Func, Ty, Base, Offset, Index, Shift, SegmentReg);
}
Variable *getBase() const { return Base; }
Constant *getOffset() const { return Offset; }
Variable *getIndex() const { return Index; }
uint16_t getShift() const { return Shift; }
SegmentRegisters getSegmentRegister() const { return SegmentReg; }
void emitSegmentOverride(Assembler *Asm) const;
Address toAsmAddress(Assembler *Asm) const;
void emit(const Cfg *Func) const override;
using X86Operand::dump;
void dump(const Cfg *Func, Ostream &Str) const override;
static bool classof(const Operand *Operand) {
return Operand->getKind() == static_cast<OperandKind>(kMem);
}
void setRandomized(bool R) { Randomized = R; }
bool getRandomized() const { return Randomized; }
private:
X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg);
Variable *Base;
Constant *Offset;
Variable *Index;
uint16_t Shift;
SegmentRegisters SegmentReg : 16;
/// A flag to show if this memory operand is a randomized one. Randomized
/// memory operands are generated in
/// TargetX86Base::randomizeOrPoolImmediate()
bool Randomized;
};
/// VariableSplit is a way to treat an f64 memory location as a pair of i32
/// locations (Low and High). This is needed for some cases of the Bitcast
/// instruction. Since it's not possible for integer registers to access the
/// XMM registers and vice versa, the lowering forces the f64 to be spilled to
/// the stack and then accesses through the VariableSplit.
// TODO(jpp): remove references to VariableSplit from IceInstX86Base as 64bit
// targets can natively handle these.
class VariableSplit : public X86Operand {
VariableSplit() = delete;
VariableSplit(const VariableSplit &) = delete;
VariableSplit &operator=(const VariableSplit &) = delete;
public:
enum Portion { Low, High };
static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) {
return new (Func->allocate<VariableSplit>())
VariableSplit(Func, Var, Part);
}
int32_t getOffset() const { return Part == High ? 4 : 0; }
Address toAsmAddress(const Cfg *Func) const;
void emit(const Cfg *Func) const override;
using X86Operand::dump;
void dump(const Cfg *Func, Ostream &Str) const override;
static bool classof(const Operand *Operand) {
return Operand->getKind() == static_cast<OperandKind>(kSplit);
}
private:
VariableSplit(Cfg *Func, Variable *Var, Portion Part)
: X86Operand(kSplit, IceType_i32), Var(Var), Part(Part) {
assert(Var->getType() == IceType_f64);
Vars = Func->allocateArrayOf<Variable *>(1);
Vars[0] = Var;
NumVars = 1;
}
Variable *Var;
Portion Part;
};
/// SpillVariable decorates a Variable by linking it to another Variable.
/// When stack frame offsets are computed, the SpillVariable is given a
/// distinct stack slot only if its linked Variable has a register. If the
/// linked Variable has a stack slot, then the Variable and SpillVariable
/// share that slot.
class SpillVariable : public Variable {
SpillVariable() = delete;
SpillVariable(const SpillVariable &) = delete;
SpillVariable &operator=(const SpillVariable &) = delete;
public:
static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<SpillVariable>()) SpillVariable(Ty, Index);
}
const static OperandKind SpillVariableKind =
static_cast<OperandKind>(kVariable_Target);
static bool classof(const Operand *Operand) {
return Operand->getKind() == SpillVariableKind;
}
void setLinkedTo(Variable *Var) { LinkedTo = Var; }
Variable *getLinkedTo() const { return LinkedTo; }
// Inherit dump() and emit() from Variable.
private:
SpillVariable(Type Ty, SizeT Index)
: Variable(SpillVariableKind, Ty, Index), LinkedTo(nullptr) {}
Variable *LinkedTo;
};
// Note: The following data structures are defined in IceInstX8632.cpp.
static const struct InstBrAttributesType {
Cond::BrCond Opposite;
const char *DisplayString;
const char *EmitString;
} InstBrAttributes[];
static const struct InstCmppsAttributesType {
const char *EmitString;
} InstCmppsAttributes[];
static const struct TypeAttributesType {
const char *CvtString; // i (integer), s (single FP), d (double FP)
const char *SdSsString; // ss, sd, or <blank>
const char *PackString; // b, w, d, or <blank>
const char *WidthString; // b, w, l, q, or <blank>
const char *FldString; // s, l, or <blank>
} TypeAttributes[];
static const char *InstSegmentRegNames[];
static uint8_t InstSegmentPrefixes[];
}; };
} // end of namespace X86Internal } // end of namespace X86Internal
......
...@@ -183,7 +183,7 @@ protected: ...@@ -183,7 +183,7 @@ protected:
void lowerSwitch(const InstSwitch *Inst) override; void lowerSwitch(const InstSwitch *Inst) override;
void lowerUnreachable(const InstUnreachable *Inst) override; void lowerUnreachable(const InstUnreachable *Inst) override;
void lowerOther(const Inst *Instr) override; void lowerOther(const Inst *Instr) override;
void lowerRMW(const InstX8632FakeRMW *RMW); void lowerRMW(const typename Traits::Insts::FakeRMW *RMW);
void prelowerPhis() override; void prelowerPhis() override;
void lowerPhiAssignments(CfgNode *Node, void lowerPhiAssignments(CfgNode *Node,
const AssignList &Assignments) override; const AssignList &Assignments) override;
...@@ -234,7 +234,7 @@ protected: ...@@ -234,7 +234,7 @@ protected:
/// Turn a pointer operand into a memory operand that can be /// Turn a pointer operand into a memory operand that can be
/// used by a real load/store operation. Legalizes the operand as well. /// used by a real load/store operation. Legalizes the operand as well.
/// This is a nop if the operand is already a legal memory operand. /// This is a nop if the operand is already a legal memory operand.
OperandX8632Mem *formMemoryOperand(Operand *Ptr, Type Ty, typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty,
bool DoLegalize = true); bool DoLegalize = true);
Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
...@@ -253,99 +253,99 @@ protected: ...@@ -253,99 +253,99 @@ protected:
int32_t RegNum = Variable::NoRegister); int32_t RegNum = Variable::NoRegister);
/// Return a memory operand corresponding to a stack allocated Variable. /// Return a memory operand corresponding to a stack allocated Variable.
OperandX8632Mem *getMemoryOperandForStackSlot(Type Ty, Variable *Slot, typename Traits::X86OperandMem *
uint32_t Offset = 0); getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0);
void makeRandomRegisterPermutation( void makeRandomRegisterPermutation(
llvm::SmallVectorImpl<int32_t> &Permutation, llvm::SmallVectorImpl<int32_t> &Permutation,
const llvm::SmallBitVector &ExcludeRegisters) const override; const llvm::SmallBitVector &ExcludeRegisters) const override;
// TODO(jpp): move the helper methods below to the MachineTraits.
/// The following are helpers that insert lowered x86 instructions /// The following are helpers that insert lowered x86 instructions
/// with minimal syntactic overhead, so that the lowering code can /// with minimal syntactic overhead, so that the lowering code can
/// look as close to assembly as practical. /// look as close to assembly as practical.
void _adc(Variable *Dest, Operand *Src0) { void _adc(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Adc::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Adc::create(Func, Dest, Src0));
} }
void _adc_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632AdcRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1));
} }
void _add(Variable *Dest, Operand *Src0) { void _add(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Add::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Add::create(Func, Dest, Src0));
} }
void _add_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632AddRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::AddRMW::create(Func, DestSrc0, Src1));
} }
void _adjust_stack(int32_t Amount) { void _adjust_stack(int32_t Amount) {
Context.insert(InstX8632AdjustStack::create( Context.insert(Traits::Insts::AdjustStack::create(
Func, Amount, getPhysicalRegister(Traits::RegisterSet::Reg_esp))); Func, Amount, getPhysicalRegister(Traits::RegisterSet::Reg_esp)));
} }
void _addps(Variable *Dest, Operand *Src0) { void _addps(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Addps::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Addps::create(Func, Dest, Src0));
} }
void _addss(Variable *Dest, Operand *Src0) { void _addss(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Addss::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Addss::create(Func, Dest, Src0));
} }
void _and(Variable *Dest, Operand *Src0) { void _and(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632And::create(Func, Dest, Src0)); Context.insert(Traits::Insts::And::create(Func, Dest, Src0));
} }
void _and_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _and_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632AndRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::AndRMW::create(Func, DestSrc0, Src1));
} }
void _blendvps(Variable *Dest, Operand *Src0, Operand *Src1) { void _blendvps(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Blendvps::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Blendvps::create(Func, Dest, Src0, Src1));
} }
void _br(typename Traits::Cond::BrCond Condition, CfgNode *TargetTrue, void _br(typename Traits::Cond::BrCond Condition, CfgNode *TargetTrue,
CfgNode *TargetFalse) { CfgNode *TargetFalse) {
Context.insert( Context.insert(
InstX8632Br::create(Func, TargetTrue, TargetFalse, Condition)); Traits::Insts::Br::create(Func, TargetTrue, TargetFalse, Condition));
} }
void _br(CfgNode *Target) { void _br(CfgNode *Target) {
Context.insert(InstX8632Br::create(Func, Target)); Context.insert(Traits::Insts::Br::create(Func, Target));
} }
void _br(typename Traits::Cond::BrCond Condition, CfgNode *Target) { void _br(typename Traits::Cond::BrCond Condition, CfgNode *Target) {
Context.insert(InstX8632Br::create(Func, Target, Condition)); Context.insert(Traits::Insts::Br::create(Func, Target, Condition));
} }
void _br(typename Traits::Cond::BrCond Condition, InstX8632Label *Label) { void _br(typename Traits::Cond::BrCond Condition,
Context.insert(InstX8632Br::create(Func, Label, Condition)); typename Traits::Insts::Label *Label) {
Context.insert(Traits::Insts::Br::create(Func, Label, Condition));
} }
void _bsf(Variable *Dest, Operand *Src0) { void _bsf(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Bsf::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Bsf::create(Func, Dest, Src0));
} }
void _bsr(Variable *Dest, Operand *Src0) { void _bsr(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Bsr::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Bsr::create(Func, Dest, Src0));
} }
void _bswap(Variable *SrcDest) { void _bswap(Variable *SrcDest) {
Context.insert(InstX8632Bswap::create(Func, SrcDest)); Context.insert(Traits::Insts::Bswap::create(Func, SrcDest));
} }
void _cbwdq(Variable *Dest, Operand *Src0) { void _cbwdq(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Cbwdq::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Cbwdq::create(Func, Dest, Src0));
} }
void _cmov(Variable *Dest, Operand *Src0, void _cmov(Variable *Dest, Operand *Src0,
typename Traits::Cond::BrCond Condition) { typename Traits::Cond::BrCond Condition) {
Context.insert(InstX8632Cmov::create(Func, Dest, Src0, Condition)); Context.insert(Traits::Insts::Cmov::create(Func, Dest, Src0, Condition));
} }
void _cmp(Operand *Src0, Operand *Src1) { void _cmp(Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Icmp::create(Func, Src0, Src1)); Context.insert(Traits::Insts::Icmp::create(Func, Src0, Src1));
} }
void _cmpps(Variable *Dest, Operand *Src0, void _cmpps(Variable *Dest, Operand *Src0,
typename Traits::Cond::CmppsCond Condition) { typename Traits::Cond::CmppsCond Condition) {
Context.insert(InstX8632Cmpps::create(Func, Dest, Src0, Condition)); Context.insert(Traits::Insts::Cmpps::create(Func, Dest, Src0, Condition));
} }
void _cmpxchg(Operand *DestOrAddr, Variable *Eax, Variable *Desired, void _cmpxchg(Operand *DestOrAddr, Variable *Eax, Variable *Desired,
bool Locked) { bool Locked) {
Context.insert( Context.insert(
InstX8632Cmpxchg::create(Func, DestOrAddr, Eax, Desired, Locked)); Traits::Insts::Cmpxchg::create(Func, DestOrAddr, Eax, Desired, Locked));
// Mark eax as possibly modified by cmpxchg. // Mark eax as possibly modified by cmpxchg.
Context.insert( Context.insert(
InstFakeDef::create(Func, Eax, llvm::dyn_cast<Variable>(DestOrAddr))); InstFakeDef::create(Func, Eax, llvm::dyn_cast<Variable>(DestOrAddr)));
_set_dest_nonkillable(); _set_dest_nonkillable();
Context.insert(InstFakeUse::create(Func, Eax)); Context.insert(InstFakeUse::create(Func, Eax));
} }
void _cmpxchg8b(OperandX8632Mem *Addr, Variable *Edx, Variable *Eax, void _cmpxchg8b(typename Traits::X86OperandMem *Addr, Variable *Edx,
Variable *Ecx, Variable *Ebx, bool Locked) { Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked) {
Context.insert( Context.insert(Traits::Insts::Cmpxchg8b::create(Func, Addr, Edx, Eax, Ecx,
InstX8632Cmpxchg8b::create(Func, Addr, Edx, Eax, Ecx, Ebx, Locked)); Ebx, Locked));
// Mark edx, and eax as possibly modified by cmpxchg8b. // Mark edx, and eax as possibly modified by cmpxchg8b.
Context.insert(InstFakeDef::create(Func, Edx)); Context.insert(InstFakeDef::create(Func, Edx));
_set_dest_nonkillable(); _set_dest_nonkillable();
...@@ -354,38 +354,41 @@ protected: ...@@ -354,38 +354,41 @@ protected:
_set_dest_nonkillable(); _set_dest_nonkillable();
Context.insert(InstFakeUse::create(Func, Eax)); Context.insert(InstFakeUse::create(Func, Eax));
} }
void _cvt(Variable *Dest, Operand *Src0, InstX8632Cvt::CvtVariant Variant) { void _cvt(Variable *Dest, Operand *Src0,
Context.insert(InstX8632Cvt::create(Func, Dest, Src0, Variant)); typename Traits::Insts::Cvt::CvtVariant Variant) {
Context.insert(Traits::Insts::Cvt::create(Func, Dest, Src0, Variant));
} }
void _div(Variable *Dest, Operand *Src0, Operand *Src1) { void _div(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Div::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Div::create(Func, Dest, Src0, Src1));
} }
void _divps(Variable *Dest, Operand *Src0) { void _divps(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Divps::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Divps::create(Func, Dest, Src0));
} }
void _divss(Variable *Dest, Operand *Src0) { void _divss(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Divss::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Divss::create(Func, Dest, Src0));
}
void _fld(Operand *Src0) {
Context.insert(Traits::Insts::Fld::create(Func, Src0));
} }
void _fld(Operand *Src0) { Context.insert(InstX8632Fld::create(Func, Src0)); }
void _fstp(Variable *Dest) { void _fstp(Variable *Dest) {
Context.insert(InstX8632Fstp::create(Func, Dest)); Context.insert(Traits::Insts::Fstp::create(Func, Dest));
} }
void _idiv(Variable *Dest, Operand *Src0, Operand *Src1) { void _idiv(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Idiv::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Idiv::create(Func, Dest, Src0, Src1));
} }
void _imul(Variable *Dest, Operand *Src0) { void _imul(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Imul::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Imul::create(Func, Dest, Src0));
} }
void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Insertps::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Insertps::create(Func, Dest, Src0, Src1));
} }
void _jmp(Operand *Target) { void _jmp(Operand *Target) {
Context.insert(InstX8632Jmp::create(Func, Target)); Context.insert(Traits::Insts::Jmp::create(Func, Target));
} }
void _lea(Variable *Dest, Operand *Src0) { void _lea(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Lea::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Lea::create(Func, Dest, Src0));
} }
void _mfence() { Context.insert(InstX8632Mfence::create(Func)); } void _mfence() { Context.insert(Traits::Insts::Mfence::create(Func)); }
/// If Dest=nullptr is passed in, then a new variable is created, /// If Dest=nullptr is passed in, then a new variable is created,
/// marked as infinite register allocation weight, and returned /// marked as infinite register allocation weight, and returned
/// through the in/out Dest argument. /// through the in/out Dest argument.
...@@ -393,175 +396,175 @@ protected: ...@@ -393,175 +396,175 @@ protected:
int32_t RegNum = Variable::NoRegister) { int32_t RegNum = Variable::NoRegister) {
if (Dest == nullptr) if (Dest == nullptr)
Dest = makeReg(Src0->getType(), RegNum); Dest = makeReg(Src0->getType(), RegNum);
Context.insert(InstX8632Mov::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Mov::create(Func, Dest, Src0));
} }
void _mov_nonkillable(Variable *Dest, Operand *Src0) { void _mov_nonkillable(Variable *Dest, Operand *Src0) {
Inst *NewInst = InstX8632Mov::create(Func, Dest, Src0); Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0);
NewInst->setDestNonKillable(); NewInst->setDestNonKillable();
Context.insert(NewInst); Context.insert(NewInst);
} }
void _movd(Variable *Dest, Operand *Src0) { void _movd(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Movd::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Movd::create(Func, Dest, Src0));
} }
void _movp(Variable *Dest, Operand *Src0) { void _movp(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Movp::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Movp::create(Func, Dest, Src0));
} }
void _movq(Variable *Dest, Operand *Src0) { void _movq(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Movq::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Movq::create(Func, Dest, Src0));
} }
void _movss(Variable *Dest, Variable *Src0) { void _movss(Variable *Dest, Variable *Src0) {
Context.insert(InstX8632MovssRegs::create(Func, Dest, Src0)); Context.insert(Traits::Insts::MovssRegs::create(Func, Dest, Src0));
} }
void _movsx(Variable *Dest, Operand *Src0) { void _movsx(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Movsx::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Movsx::create(Func, Dest, Src0));
} }
void _movzx(Variable *Dest, Operand *Src0) { void _movzx(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Movzx::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Movzx::create(Func, Dest, Src0));
} }
void _mul(Variable *Dest, Variable *Src0, Operand *Src1) { void _mul(Variable *Dest, Variable *Src0, Operand *Src1) {
Context.insert(InstX8632Mul::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Mul::create(Func, Dest, Src0, Src1));
} }
void _mulps(Variable *Dest, Operand *Src0) { void _mulps(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Mulps::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Mulps::create(Func, Dest, Src0));
} }
void _mulss(Variable *Dest, Operand *Src0) { void _mulss(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Mulss::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Mulss::create(Func, Dest, Src0));
} }
void _neg(Variable *SrcDest) { void _neg(Variable *SrcDest) {
Context.insert(InstX8632Neg::create(Func, SrcDest)); Context.insert(Traits::Insts::Neg::create(Func, SrcDest));
} }
void _nop(SizeT Variant) { void _nop(SizeT Variant) {
Context.insert(InstX8632Nop::create(Func, Variant)); Context.insert(Traits::Insts::Nop::create(Func, Variant));
} }
void _or(Variable *Dest, Operand *Src0) { void _or(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Or::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Or::create(Func, Dest, Src0));
} }
void _or_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _or_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632OrRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::OrRMW::create(Func, DestSrc0, Src1));
} }
void _padd(Variable *Dest, Operand *Src0) { void _padd(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Padd::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Padd::create(Func, Dest, Src0));
} }
void _pand(Variable *Dest, Operand *Src0) { void _pand(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pand::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pand::create(Func, Dest, Src0));
} }
void _pandn(Variable *Dest, Operand *Src0) { void _pandn(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pandn::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pandn::create(Func, Dest, Src0));
} }
void _pblendvb(Variable *Dest, Operand *Src0, Operand *Src1) { void _pblendvb(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Pblendvb::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Pblendvb::create(Func, Dest, Src0, Src1));
} }
void _pcmpeq(Variable *Dest, Operand *Src0) { void _pcmpeq(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pcmpeq::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pcmpeq::create(Func, Dest, Src0));
} }
void _pcmpgt(Variable *Dest, Operand *Src0) { void _pcmpgt(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pcmpgt::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pcmpgt::create(Func, Dest, Src0));
} }
void _pextr(Variable *Dest, Operand *Src0, Operand *Src1) { void _pextr(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Pextr::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Pextr::create(Func, Dest, Src0, Src1));
} }
void _pinsr(Variable *Dest, Operand *Src0, Operand *Src1) { void _pinsr(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Pinsr::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Pinsr::create(Func, Dest, Src0, Src1));
} }
void _pmull(Variable *Dest, Operand *Src0) { void _pmull(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pmull::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pmull::create(Func, Dest, Src0));
} }
void _pmuludq(Variable *Dest, Operand *Src0) { void _pmuludq(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pmuludq::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pmuludq::create(Func, Dest, Src0));
} }
void _pop(Variable *Dest) { void _pop(Variable *Dest) {
Context.insert(InstX8632Pop::create(Func, Dest)); Context.insert(Traits::Insts::Pop::create(Func, Dest));
} }
void _por(Variable *Dest, Operand *Src0) { void _por(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Por::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Por::create(Func, Dest, Src0));
} }
void _pshufd(Variable *Dest, Operand *Src0, Operand *Src1) { void _pshufd(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Pshufd::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Pshufd::create(Func, Dest, Src0, Src1));
} }
void _psll(Variable *Dest, Operand *Src0) { void _psll(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Psll::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Psll::create(Func, Dest, Src0));
} }
void _psra(Variable *Dest, Operand *Src0) { void _psra(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Psra::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Psra::create(Func, Dest, Src0));
} }
void _psrl(Variable *Dest, Operand *Src0) { void _psrl(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Psrl::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Psrl::create(Func, Dest, Src0));
} }
void _psub(Variable *Dest, Operand *Src0) { void _psub(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Psub::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Psub::create(Func, Dest, Src0));
} }
void _push(Variable *Src0) { void _push(Variable *Src0) {
Context.insert(InstX8632Push::create(Func, Src0)); Context.insert(Traits::Insts::Push::create(Func, Src0));
} }
void _pxor(Variable *Dest, Operand *Src0) { void _pxor(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Pxor::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Pxor::create(Func, Dest, Src0));
} }
void _ret(Variable *Src0 = nullptr) { void _ret(Variable *Src0 = nullptr) {
Context.insert(InstX8632Ret::create(Func, Src0)); Context.insert(Traits::Insts::Ret::create(Func, Src0));
} }
void _rol(Variable *Dest, Operand *Src0) { void _rol(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Rol::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Rol::create(Func, Dest, Src0));
} }
void _sar(Variable *Dest, Operand *Src0) { void _sar(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Sar::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Sar::create(Func, Dest, Src0));
} }
void _sbb(Variable *Dest, Operand *Src0) { void _sbb(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Sbb::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Sbb::create(Func, Dest, Src0));
} }
void _sbb_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _sbb_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632SbbRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::SbbRMW::create(Func, DestSrc0, Src1));
} }
void _setcc(Variable *Dest, typename Traits::Cond::BrCond Condition) { void _setcc(Variable *Dest, typename Traits::Cond::BrCond Condition) {
Context.insert(InstX8632Setcc::create(Func, Dest, Condition)); Context.insert(Traits::Insts::Setcc::create(Func, Dest, Condition));
} }
void _shl(Variable *Dest, Operand *Src0) { void _shl(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Shl::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Shl::create(Func, Dest, Src0));
} }
void _shld(Variable *Dest, Variable *Src0, Variable *Src1) { void _shld(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstX8632Shld::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Shld::create(Func, Dest, Src0, Src1));
} }
void _shr(Variable *Dest, Operand *Src0) { void _shr(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Shr::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Shr::create(Func, Dest, Src0));
} }
void _shrd(Variable *Dest, Variable *Src0, Variable *Src1) { void _shrd(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstX8632Shrd::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Shrd::create(Func, Dest, Src0, Src1));
} }
void _shufps(Variable *Dest, Operand *Src0, Operand *Src1) { void _shufps(Variable *Dest, Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Shufps::create(Func, Dest, Src0, Src1)); Context.insert(Traits::Insts::Shufps::create(Func, Dest, Src0, Src1));
} }
void _sqrtss(Variable *Dest, Operand *Src0) { void _sqrtss(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Sqrtss::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Sqrtss::create(Func, Dest, Src0));
} }
void _store(Operand *Value, OperandX8632 *Mem) { void _store(Operand *Value, typename Traits::X86Operand *Mem) {
Context.insert(InstX8632Store::create(Func, Value, Mem)); Context.insert(Traits::Insts::Store::create(Func, Value, Mem));
} }
void _storep(Variable *Value, OperandX8632Mem *Mem) { void _storep(Variable *Value, typename Traits::X86OperandMem *Mem) {
Context.insert(InstX8632StoreP::create(Func, Value, Mem)); Context.insert(Traits::Insts::StoreP::create(Func, Value, Mem));
} }
void _storeq(Variable *Value, OperandX8632Mem *Mem) { void _storeq(Variable *Value, typename Traits::X86OperandMem *Mem) {
Context.insert(InstX8632StoreQ::create(Func, Value, Mem)); Context.insert(Traits::Insts::StoreQ::create(Func, Value, Mem));
} }
void _sub(Variable *Dest, Operand *Src0) { void _sub(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Sub::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Sub::create(Func, Dest, Src0));
} }
void _sub_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _sub_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632SubRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::SubRMW::create(Func, DestSrc0, Src1));
} }
void _subps(Variable *Dest, Operand *Src0) { void _subps(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Subps::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Subps::create(Func, Dest, Src0));
} }
void _subss(Variable *Dest, Operand *Src0) { void _subss(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Subss::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Subss::create(Func, Dest, Src0));
} }
void _test(Operand *Src0, Operand *Src1) { void _test(Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Test::create(Func, Src0, Src1)); Context.insert(Traits::Insts::Test::create(Func, Src0, Src1));
} }
void _ucomiss(Operand *Src0, Operand *Src1) { void _ucomiss(Operand *Src0, Operand *Src1) {
Context.insert(InstX8632Ucomiss::create(Func, Src0, Src1)); Context.insert(Traits::Insts::Ucomiss::create(Func, Src0, Src1));
} }
void _ud2() { Context.insert(InstX8632UD2::create(Func)); } void _ud2() { Context.insert(Traits::Insts::UD2::create(Func)); }
void _xadd(Operand *Dest, Variable *Src, bool Locked) { void _xadd(Operand *Dest, Variable *Src, bool Locked) {
Context.insert(InstX8632Xadd::create(Func, Dest, Src, Locked)); Context.insert(Traits::Insts::Xadd::create(Func, Dest, Src, Locked));
// The xadd exchanges Dest and Src (modifying Src). // The xadd exchanges Dest and Src (modifying Src).
// Model that update with a FakeDef followed by a FakeUse. // Model that update with a FakeDef followed by a FakeUse.
Context.insert( Context.insert(
...@@ -570,7 +573,7 @@ protected: ...@@ -570,7 +573,7 @@ protected:
Context.insert(InstFakeUse::create(Func, Src)); Context.insert(InstFakeUse::create(Func, Src));
} }
void _xchg(Operand *Dest, Variable *Src) { void _xchg(Operand *Dest, Variable *Src) {
Context.insert(InstX8632Xchg::create(Func, Dest, Src)); Context.insert(Traits::Insts::Xchg::create(Func, Dest, Src));
// The xchg modifies Dest and Src -- model that update with a // The xchg modifies Dest and Src -- model that update with a
// FakeDef/FakeUse. // FakeDef/FakeUse.
Context.insert( Context.insert(
...@@ -579,10 +582,10 @@ protected: ...@@ -579,10 +582,10 @@ protected:
Context.insert(InstFakeUse::create(Func, Src)); Context.insert(InstFakeUse::create(Func, Src));
} }
void _xor(Variable *Dest, Operand *Src0) { void _xor(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Xor::create(Func, Dest, Src0)); Context.insert(Traits::Insts::Xor::create(Func, Dest, Src0));
} }
void _xor_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) { void _xor_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632XorRMW::create(Func, DestSrc0, Src1)); Context.insert(Traits::Insts::XorRMW::create(Func, DestSrc0, Src1));
} }
void _set_dest_nonkillable() { void _set_dest_nonkillable() {
Context.getLastInserted()->setDestNonKillable(); Context.getLastInserted()->setDestNonKillable();
...@@ -600,13 +603,12 @@ protected: ...@@ -600,13 +603,12 @@ protected:
llvm::SmallBitVector ScratchRegs; llvm::SmallBitVector ScratchRegs;
llvm::SmallBitVector RegsUsed; llvm::SmallBitVector RegsUsed;
VarList PhysicalRegisters[IceType_NUM]; VarList PhysicalRegisters[IceType_NUM];
static IceString RegNames[];
/// Randomize a given immediate operand /// Randomize a given immediate operand
Operand *randomizeOrPoolImmediate(Constant *Immediate, Operand *randomizeOrPoolImmediate(Constant *Immediate,
int32_t RegNum = Variable::NoRegister); int32_t RegNum = Variable::NoRegister);
OperandX8632Mem * typename Traits::X86OperandMem *
randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, randomizeOrPoolImmediate(typename Traits::X86OperandMem *MemOperand,
int32_t RegNum = Variable::NoRegister); int32_t RegNum = Variable::NoRegister);
bool RandomizationPoolingPaused = false; bool RandomizationPoolingPaused = false;
......
...@@ -23,20 +23,16 @@ ...@@ -23,20 +23,16 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h" #include "IceELFObjectWriter.h"
#include "IceGlobalInits.h" #include "IceGlobalInits.h"
#include "IceInstX8632.h"
#include "IceLiveness.h" #include "IceLiveness.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceRegistersX8632.h"
#include "IceTargetLoweringX8632.def"
#include "IceTargetLoweringX8632.h"
#include "IceUtils.h" #include "IceUtils.h"
#include "llvm/Support/MathExtras.h" #include "llvm/Support/MathExtras.h"
namespace Ice { namespace Ice {
namespace X86Internal { namespace X86Internal {
/// A helper class to ease the settings of RandomizationPoolingPause /// A helper class to ease the settings of RandomizationPoolingPause to disable
/// to disable constant blinding or pooling for some translation phases. /// constant blinding or pooling for some translation phases.
class BoolFlagSaver { class BoolFlagSaver {
BoolFlagSaver() = delete; BoolFlagSaver() = delete;
BoolFlagSaver(const BoolFlagSaver &) = delete; BoolFlagSaver(const BoolFlagSaver &) = delete;
...@@ -85,8 +81,7 @@ public: ...@@ -85,8 +81,7 @@ public:
}; };
/// Currently the actual enum values are not used (other than CK_None), but we /// Currently the actual enum values are not used (other than CK_None), but we
/// go /// go ahead and produce them anyway for symmetry with the
/// ahead and produce them anyway for symmetry with the
/// BoolFoldingProducerKind. /// BoolFoldingProducerKind.
enum BoolFoldingConsumerKind { CK_None, CK_Br, CK_Select, CK_Sext, CK_Zext }; enum BoolFoldingConsumerKind { CK_None, CK_Br, CK_Select, CK_Sext, CK_Zext };
...@@ -163,12 +158,11 @@ BoolFolding<MachineTraits>::getConsumerKind(const Inst *Instr) { ...@@ -163,12 +158,11 @@ BoolFolding<MachineTraits>::getConsumerKind(const Inst *Instr) {
return CK_None; return CK_None;
} }
/// Returns true if the producing instruction has a "complex" lowering /// Returns true if the producing instruction has a "complex" lowering sequence.
/// sequence. This generally means that its lowering sequence requires /// This generally means that its lowering sequence requires more than one
/// more than one conditional branch, namely 64-bit integer compares /// conditional branch, namely 64-bit integer compares and some floating-point
/// and some floating-point compares. When this is true, and there is /// compares. When this is true, and there is more than one consumer, we prefer
/// more than one consumer, we prefer to disable the folding /// to disable the folding optimization because it minimizes branches.
/// optimization because it minimizes branches.
template <class MachineTraits> template <class MachineTraits>
bool BoolFolding<MachineTraits>::hasComplexLowering(const Inst *Instr) { bool BoolFolding<MachineTraits>::hasComplexLowering(const Inst *Instr) {
switch (getProducerKind(Instr)) { switch (getProducerKind(Instr)) {
...@@ -226,10 +220,10 @@ void BoolFolding<MachineTraits>::init(CfgNode *Node) { ...@@ -226,10 +220,10 @@ void BoolFolding<MachineTraits>::init(CfgNode *Node) {
setInvalid(I.first); setInvalid(I.first);
continue; continue;
} }
// Mark as "dead" rather than outright deleting. This is so that // Mark as "dead" rather than outright deleting. This is so that other
// other peephole style optimizations during or before lowering // peephole style optimizations during or before lowering have access to
// have access to this instruction in undeleted form. See for // this instruction in undeleted form. See for example
// example tryOptimizedCmpxchgCmpBr(). // tryOptimizedCmpxchgCmpBr().
I.second.Instr->setDead(); I.second.Instr->setDead();
} }
} }
...@@ -283,24 +277,18 @@ TargetX86Base<Machine>::TargetX86Base(Cfg *Func) ...@@ -283,24 +277,18 @@ TargetX86Base<Machine>::TargetX86Base(Cfg *Func)
TargetInstructionSet::X86InstructionSet_Begin) + TargetInstructionSet::X86InstructionSet_Begin) +
Traits::InstructionSet::Begin); Traits::InstructionSet::Begin);
} }
// TODO: Don't initialize IntegerRegisters and friends every time. // TODO: Don't initialize IntegerRegisters and friends every time. Instead,
// Instead, initialize in some sort of static initializer for the // initialize in some sort of static initializer for the class.
// class.
llvm::SmallBitVector IntegerRegisters(Traits::RegisterSet::Reg_NUM); llvm::SmallBitVector IntegerRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector IntegerRegistersI8(Traits::RegisterSet::Reg_NUM); llvm::SmallBitVector IntegerRegistersI8(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector FloatRegisters(Traits::RegisterSet::Reg_NUM); llvm::SmallBitVector FloatRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector VectorRegisters(Traits::RegisterSet::Reg_NUM); llvm::SmallBitVector VectorRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector InvalidRegisters(Traits::RegisterSet::Reg_NUM); llvm::SmallBitVector InvalidRegisters(Traits::RegisterSet::Reg_NUM);
ScratchRegs.resize(Traits::RegisterSet::Reg_NUM); ScratchRegs.resize(Traits::RegisterSet::Reg_NUM);
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \ Traits::initRegisterSet(&IntegerRegisters, &IntegerRegistersI8,
IntegerRegisters[Traits::RegisterSet::val] = isInt; \ &FloatRegisters, &VectorRegisters, &ScratchRegs);
IntegerRegistersI8[Traits::RegisterSet::val] = isI8; \
FloatRegisters[Traits::RegisterSet::val] = isFP; \
VectorRegisters[Traits::RegisterSet::val] = isFP; \
ScratchRegs[Traits::RegisterSet::val] = scratch;
REGX8632_TABLE;
#undef X
TypeToRegisterSet[IceType_void] = InvalidRegisters; TypeToRegisterSet[IceType_void] = InvalidRegisters;
TypeToRegisterSet[IceType_i1] = IntegerRegistersI8; TypeToRegisterSet[IceType_i1] = IntegerRegistersI8;
TypeToRegisterSet[IceType_i8] = IntegerRegistersI8; TypeToRegisterSet[IceType_i8] = IntegerRegistersI8;
...@@ -348,19 +336,18 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() { ...@@ -348,19 +336,18 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
// Argument lowering // Argument lowering
Func->doArgLowering(); Func->doArgLowering();
// Target lowering. This requires liveness analysis for some parts // Target lowering. This requires liveness analysis for some parts of the
// of the lowering decisions, such as compare/branch fusing. If // lowering decisions, such as compare/branch fusing. If non-lightweight
// non-lightweight liveness analysis is used, the instructions need // liveness analysis is used, the instructions need to be renumbered first
// to be renumbered first. TODO: This renumbering should only be // TODO: This renumbering should only be necessary if we're actually
// necessary if we're actually calculating live intervals, which we // calculating live intervals, which we only do for register allocation.
// only do for register allocation.
Func->renumberInstructions(); Func->renumberInstructions();
if (Func->hasError()) if (Func->hasError())
return; return;
// TODO: It should be sufficient to use the fastest liveness // TODO: It should be sufficient to use the fastest liveness calculation, i.e.
// calculation, i.e. livenessLightweight(). However, for some // livenessLightweight(). However, for some reason that slows down the rest
// reason that slows down the rest of the translation. Investigate. // of the translation. Investigate.
Func->liveness(Liveness_Basic); Func->liveness(Liveness_Basic);
if (Func->hasError()) if (Func->hasError())
return; return;
...@@ -376,19 +363,19 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() { ...@@ -376,19 +363,19 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
return; return;
Func->dump("After x86 codegen"); Func->dump("After x86 codegen");
// Register allocation. This requires instruction renumbering and // Register allocation. This requires instruction renumbering and full
// full liveness analysis. // liveness analysis.
Func->renumberInstructions(); Func->renumberInstructions();
if (Func->hasError()) if (Func->hasError())
return; return;
Func->liveness(Liveness_Intervals); Func->liveness(Liveness_Intervals);
if (Func->hasError()) if (Func->hasError())
return; return;
// Validate the live range computations. The expensive validation // Validate the live range computations. The expensive validation call is
// call is deliberately only made when assertions are enabled. // deliberately only made when assertions are enabled.
assert(Func->validateLiveness()); assert(Func->validateLiveness());
// The post-codegen dump is done here, after liveness analysis and // The post-codegen dump is done here, after liveness analysis and associated
// associated cleanup, to make the dump cleaner and more useful. // cleanup, to make the dump cleaner and more useful.
Func->dump("After initial x8632 codegen"); Func->dump("After initial x8632 codegen");
Func->getVMetadata()->init(VMK_All); Func->getVMetadata()->init(VMK_All);
regAlloc(RAK_Global); regAlloc(RAK_Global);
...@@ -397,9 +384,9 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() { ...@@ -397,9 +384,9 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
Func->dump("After linear scan regalloc"); Func->dump("After linear scan regalloc");
if (Ctx->getFlags().getPhiEdgeSplit()) { if (Ctx->getFlags().getPhiEdgeSplit()) {
// We need to pause constant blinding or pooling during advanced // We need to pause constant blinding or pooling during advanced phi
// phi lowering, unless the lowering assignment has a physical // lowering, unless the lowering assignment has a physical register for the
// register for the dest Variable. // dest Variable.
{ {
BoolFlagSaver B(RandomizationPoolingPaused, true); BoolFlagSaver B(RandomizationPoolingPaused, true);
Func->advancedPhiLowering(); Func->advancedPhiLowering();
...@@ -416,11 +403,10 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() { ...@@ -416,11 +403,10 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
Func->contractEmptyNodes(); Func->contractEmptyNodes();
Func->reorderNodes(); Func->reorderNodes();
// Branch optimization. This needs to be done just before code // Branch optimization. This needs to be done just before code emission. In
// emission. In particular, no transformations that insert or // particular, no transformations that insert or reorder CfgNodes should be
// reorder CfgNodes should be done after branch optimization. We go // done after branch optimization. We go ahead and do it before nop insertion
// ahead and do it before nop insertion to reduce the amount of work // to reduce the amount of work needed for searching for opportunities.
// needed for searching for opportunities.
Func->doBranchOpt(); Func->doBranchOpt();
Func->dump("After branch optimization"); Func->dump("After branch optimization");
...@@ -468,8 +454,7 @@ template <class Machine> void TargetX86Base<Machine>::translateOm1() { ...@@ -468,8 +454,7 @@ template <class Machine> void TargetX86Base<Machine>::translateOm1() {
bool canRMW(const InstArithmetic *Arith) { bool canRMW(const InstArithmetic *Arith) {
Type Ty = Arith->getDest()->getType(); Type Ty = Arith->getDest()->getType();
// X86 vector instructions write to a register and have no RMW // X86 vector instructions write to a register and have no RMW option.
// option.
if (isVectorType(Ty)) if (isVectorType(Ty))
return false; return false;
bool isI64 = Ty == IceType_i64; bool isI64 = Ty == IceType_i64;
...@@ -496,11 +481,14 @@ bool canRMW(const InstArithmetic *Arith) { ...@@ -496,11 +481,14 @@ bool canRMW(const InstArithmetic *Arith) {
} }
} }
template <class Machine>
bool isSameMemAddressOperand(const Operand *A, const Operand *B) { bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
if (A == B) if (A == B)
return true; return true;
if (auto *MemA = llvm::dyn_cast<OperandX8632Mem>(A)) { if (auto *MemA = llvm::dyn_cast<
if (auto *MemB = llvm::dyn_cast<OperandX8632Mem>(B)) { typename TargetX86Base<Machine>::Traits::X86OperandMem>(A)) {
if (auto *MemB = llvm::dyn_cast<
typename TargetX86Base<Machine>::Traits::X86OperandMem>(B)) {
return MemA->getBase() == MemB->getBase() && return MemA->getBase() == MemB->getBase() &&
MemA->getOffset() == MemB->getOffset() && MemA->getOffset() == MemB->getOffset() &&
MemA->getIndex() == MemB->getIndex() && MemA->getIndex() == MemB->getIndex() &&
...@@ -565,7 +553,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() { ...@@ -565,7 +553,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() {
// still trigger, resulting in two loads and one store, which is // still trigger, resulting in two loads and one store, which is
// worse than the original one load and one store. However, this is // worse than the original one load and one store. However, this is
// probably rare, and caching probably keeps it just as fast. // probably rare, and caching probably keeps it just as fast.
if (!isSameMemAddressOperand(Load->getSourceAddress(), if (!isSameMemAddressOperand<Machine>(Load->getSourceAddress(),
Store->getAddr())) Store->getAddr()))
continue; continue;
Operand *ArithSrcFromLoad = Arith->getSrc(0); Operand *ArithSrcFromLoad = Arith->getSrc(0);
...@@ -593,7 +581,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() { ...@@ -593,7 +581,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() {
Store->setRmwBeacon(Beacon); Store->setRmwBeacon(Beacon);
InstFakeDef *BeaconDef = InstFakeDef::create(Func, Beacon); InstFakeDef *BeaconDef = InstFakeDef::create(Func, Beacon);
Node->getInsts().insert(I3, BeaconDef); Node->getInsts().insert(I3, BeaconDef);
InstX8632FakeRMW *RMW = InstX8632FakeRMW::create( auto *RMW = Traits::Insts::FakeRMW::create(
Func, ArithSrcOther, Store->getAddr(), Beacon, Arith->getOp()); Func, ArithSrcOther, Store->getAddr(), Beacon, Arith->getOp());
Node->getInsts().insert(I3, RMW); Node->getInsts().insert(I3, RMW);
} }
...@@ -721,22 +709,13 @@ template <class Machine> void TargetX86Base<Machine>::doLoadOpt() { ...@@ -721,22 +709,13 @@ template <class Machine> void TargetX86Base<Machine>::doLoadOpt() {
template <class Machine> template <class Machine>
bool TargetX86Base<Machine>::doBranchOpt(Inst *I, const CfgNode *NextNode) { bool TargetX86Base<Machine>::doBranchOpt(Inst *I, const CfgNode *NextNode) {
if (InstX8632Br *Br = llvm::dyn_cast<InstX8632Br>(I)) { if (auto *Br = llvm::dyn_cast<typename Traits::Insts::Br>(I)) {
return Br->optimizeBranch(NextNode); return Br->optimizeBranch(NextNode);
} }
return false; return false;
} }
template <class Machine> template <class Machine>
IceString TargetX86Base<Machine>::RegNames[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name,
REGX8632_TABLE
#undef X
};
template <class Machine>
Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) { Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) {
if (Ty == IceType_void) if (Ty == IceType_void)
Ty = IceType_i32; Ty = IceType_i32;
...@@ -760,30 +739,7 @@ Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) { ...@@ -760,30 +739,7 @@ Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) {
template <class Machine> template <class Machine>
IceString TargetX86Base<Machine>::getRegName(SizeT RegNum, Type Ty) const { IceString TargetX86Base<Machine>::getRegName(SizeT RegNum, Type Ty) const {
assert(RegNum < Traits::RegisterSet::Reg_NUM); return Traits::getRegName(RegNum, Ty);
static IceString RegNames8[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name8,
REGX8632_TABLE
#undef X
};
static IceString RegNames16[] = {
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
name16,
REGX8632_TABLE
#undef X
};
switch (Ty) {
case IceType_i1:
case IceType_i8:
return RegNames8[RegNum];
case IceType_i16:
return RegNames16[RegNum];
default:
return RegNames[RegNum];
}
} }
template <class Machine> template <class Machine>
...@@ -884,17 +840,16 @@ void TargetX86Base<Machine>::finishArgumentLowering(Variable *Arg, ...@@ -884,17 +840,16 @@ void TargetX86Base<Machine>::finishArgumentLowering(Variable *Arg,
InArgsSizeBytes += typeWidthInBytesOnStack(Ty); InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
if (Arg->hasReg()) { if (Arg->hasReg()) {
assert(Ty != IceType_i64); assert(Ty != IceType_i64);
OperandX8632Mem *Mem = OperandX8632Mem::create( typename Traits::X86OperandMem *Mem = Traits::X86OperandMem::create(
Func, Ty, FramePtr, Ctx->getConstantInt32(Arg->getStackOffset())); Func, Ty, FramePtr, Ctx->getConstantInt32(Arg->getStackOffset()));
if (isVectorType(Arg->getType())) { if (isVectorType(Arg->getType())) {
_movp(Arg, Mem); _movp(Arg, Mem);
} else { } else {
_mov(Arg, Mem); _mov(Arg, Mem);
} }
// This argument-copying instruction uses an explicit // This argument-copying instruction uses an explicit Traits::X86OperandMem
// OperandX8632Mem operand instead of a Variable, so its // operand instead of a Variable, so its fill-from-stack operation has to be
// fill-from-stack operation has to be tracked separately for // tracked separately for statistics.
// statistics.
Ctx->statsUpdateFills(); Ctx->statsUpdateFills();
} }
} }
...@@ -965,7 +920,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) { ...@@ -965,7 +920,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) {
// that stack slot. // that stack slot.
std::function<bool(Variable *)> TargetVarHook = std::function<bool(Variable *)> TargetVarHook =
[&VariablesLinkedToSpillSlots](Variable *Var) { [&VariablesLinkedToSpillSlots](Variable *Var) {
if (SpillVariable *SpillVar = llvm::dyn_cast<SpillVariable>(Var)) { if (auto *SpillVar =
llvm::dyn_cast<typename Traits::SpillVariable>(Var)) {
assert(Var->getWeight().isZero()); assert(Var->getWeight().isZero());
if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) { if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
VariablesLinkedToSpillSlots.push_back(Var); VariablesLinkedToSpillSlots.push_back(Var);
...@@ -1069,7 +1025,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) { ...@@ -1069,7 +1025,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) {
// Assign stack offsets to variables that have been linked to spilled // Assign stack offsets to variables that have been linked to spilled
// variables. // variables.
for (Variable *Var : VariablesLinkedToSpillSlots) { for (Variable *Var : VariablesLinkedToSpillSlots) {
Variable *Linked = (llvm::cast<SpillVariable>(Var))->getLinkedTo(); Variable *Linked =
(llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
Var->setStackOffset(Linked->getStackOffset()); Var->setStackOffset(Linked->getStackOffset());
} }
this->HasComputedFrame = true; this->HasComputedFrame = true;
...@@ -1106,7 +1063,7 @@ template <class Machine> void TargetX86Base<Machine>::addEpilog(CfgNode *Node) { ...@@ -1106,7 +1063,7 @@ template <class Machine> void TargetX86Base<Machine>::addEpilog(CfgNode *Node) {
InstList &Insts = Node->getInsts(); InstList &Insts = Node->getInsts();
InstList::reverse_iterator RI, E; InstList::reverse_iterator RI, E;
for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) { for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
if (llvm::isa<InstX8632Ret>(*RI)) if (llvm::isa<typename Traits::Insts::Ret>(*RI))
break; break;
} }
if (RI == E) if (RI == E)
...@@ -1216,8 +1173,8 @@ Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) { ...@@ -1216,8 +1173,8 @@ Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) {
Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue()))); Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue())));
return legalize(ConstInt); return legalize(ConstInt);
} }
if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) { if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) {
OperandX8632Mem *MemOperand = OperandX8632Mem::create( auto *MemOperand = Traits::X86OperandMem::create(
Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(), Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(),
Mem->getShift(), Mem->getSegmentRegister()); Mem->getShift(), Mem->getSegmentRegister());
// Test if we should randomize or pool the offset, if so randomize it or // Test if we should randomize or pool the offset, if so randomize it or
...@@ -1245,7 +1202,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) { ...@@ -1245,7 +1202,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
// check if we need to blind/pool the constant // check if we need to blind/pool the constant
return legalize(ConstInt); return legalize(ConstInt);
} }
if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) { if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) {
Constant *Offset = Mem->getOffset(); Constant *Offset = Mem->getOffset();
if (Offset == nullptr) { if (Offset == nullptr) {
Offset = Ctx->getConstantInt32(4); Offset = Ctx->getConstantInt32(4);
...@@ -1259,7 +1216,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) { ...@@ -1259,7 +1216,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(), Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(),
SymOffset->getSuppressMangling()); SymOffset->getSuppressMangling());
} }
OperandX8632Mem *MemOperand = OperandX8632Mem::create( auto *MemOperand = Traits::X86OperandMem::create(
Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(), Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(),
Mem->getShift(), Mem->getSegmentRegister()); Mem->getShift(), Mem->getSegmentRegister());
// Test if the Offset is an eligible i32 constants for randomization and // Test if the Offset is an eligible i32 constants for randomization and
...@@ -1275,32 +1232,7 @@ template <class Machine> ...@@ -1275,32 +1232,7 @@ template <class Machine>
llvm::SmallBitVector llvm::SmallBitVector
TargetX86Base<Machine>::getRegisterSet(RegSetMask Include, TargetX86Base<Machine>::getRegisterSet(RegSetMask Include,
RegSetMask Exclude) const { RegSetMask Exclude) const {
llvm::SmallBitVector Registers(Traits::RegisterSet::Reg_NUM); return Traits::getRegisterSet(Include, Exclude);
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
if (scratch && (Include & RegSet_CallerSave)) \
Registers[Traits::RegisterSet::val] = true; \
if (preserved && (Include & RegSet_CalleeSave)) \
Registers[Traits::RegisterSet::val] = true; \
if (stackptr && (Include & RegSet_StackPointer)) \
Registers[Traits::RegisterSet::val] = true; \
if (frameptr && (Include & RegSet_FramePointer)) \
Registers[Traits::RegisterSet::val] = true; \
if (scratch && (Exclude & RegSet_CallerSave)) \
Registers[Traits::RegisterSet::val] = false; \
if (preserved && (Exclude & RegSet_CalleeSave)) \
Registers[Traits::RegisterSet::val] = false; \
if (stackptr && (Exclude & RegSet_StackPointer)) \
Registers[Traits::RegisterSet::val] = false; \
if (frameptr && (Exclude & RegSet_FramePointer)) \
Registers[Traits::RegisterSet::val] = false;
REGX8632_TABLE
#undef X
return Registers;
} }
template <class Machine> template <class Machine>
...@@ -1423,17 +1355,20 @@ bool TargetX86Base<Machine>::optimizeScalarMul(Variable *Dest, Operand *Src0, ...@@ -1423,17 +1355,20 @@ bool TargetX86Base<Machine>::optimizeScalarMul(Variable *Dest, Operand *Src0,
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
for (uint32_t i = 0; i < Count9; ++i) { for (uint32_t i = 0; i < Count9; ++i) {
const uint16_t Shift = 3; // log2(9-1) const uint16_t Shift = 3; // log2(9-1)
_lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); _lea(T,
Traits::X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
_set_dest_nonkillable(); _set_dest_nonkillable();
} }
for (uint32_t i = 0; i < Count5; ++i) { for (uint32_t i = 0; i < Count5; ++i) {
const uint16_t Shift = 2; // log2(5-1) const uint16_t Shift = 2; // log2(5-1)
_lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); _lea(T,
Traits::X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
_set_dest_nonkillable(); _set_dest_nonkillable();
} }
for (uint32_t i = 0; i < Count3; ++i) { for (uint32_t i = 0; i < Count3; ++i) {
const uint16_t Shift = 1; // log2(3-1) const uint16_t Shift = 1; // log2(3-1)
_lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); _lea(T,
Traits::X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
_set_dest_nonkillable(); _set_dest_nonkillable();
} }
if (Count2) { if (Count2) {
...@@ -1601,7 +1536,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -1601,7 +1536,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr; Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20); Constant *BitTest = Ctx->getConstantInt32(0x20);
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
_mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx); _mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx);
_mov(T_2, Src0Lo); _mov(T_2, Src0Lo);
_mov(T_3, Src0Hi); _mov(T_3, Src0Hi);
...@@ -1636,7 +1572,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -1636,7 +1572,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr; Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20); Constant *BitTest = Ctx->getConstantInt32(0x20);
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
_mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx); _mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx);
_mov(T_2, Src0Lo); _mov(T_2, Src0Lo);
_mov(T_3, Src0Hi); _mov(T_3, Src0Hi);
...@@ -1671,7 +1608,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -1671,7 +1608,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr; Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20); Constant *BitTest = Ctx->getConstantInt32(0x20);
Constant *SignExtend = Ctx->getConstantInt32(0x1f); Constant *SignExtend = Ctx->getConstantInt32(0x1f);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
_mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx); _mov(T_1, Src1Lo, Traits::RegisterSet::Reg_ecx);
_mov(T_2, Src0Lo); _mov(T_2, Src0Lo);
_mov(T_3, Src0Hi); _mov(T_3, Src0Hi);
...@@ -1709,7 +1647,7 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -1709,7 +1647,7 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
if (isVectorType(Dest->getType())) { if (isVectorType(Dest->getType())) {
// TODO: Trap on integer divide and integer modulo by zero. // TODO: Trap on integer divide and integer modulo by zero.
// See: https://code.google.com/p/nativeclient/issues/detail?id=3899 // See: https://code.google.com/p/nativeclient/issues/detail?id=3899
if (llvm::isa<OperandX8632Mem>(Src1)) if (llvm::isa<typename Traits::X86OperandMem>(Src1))
Src1 = legalizeToVar(Src1); Src1 = legalizeToVar(Src1);
switch (Inst->getOp()) { switch (Inst->getOp()) {
case InstArithmetic::_num: case InstArithmetic::_num:
...@@ -2208,7 +2146,8 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) { ...@@ -2208,7 +2146,8 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) {
Variable *esp = Variable *esp =
Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp);
Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes); Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
StackArgLocations.push_back(OperandX8632Mem::create(Func, Ty, esp, Loc)); StackArgLocations.push_back(
Traits::X86OperandMem::create(Func, Ty, esp, Loc));
ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
} }
} }
...@@ -2305,7 +2244,7 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) { ...@@ -2305,7 +2244,7 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) {
CallTarget = CallTargetVar; CallTarget = CallTargetVar;
} }
} }
Inst *NewCall = InstX8632Call::create(Func, ReturnReg, CallTarget); Inst *NewCall = Traits::Insts::Call::create(Func, ReturnReg, CallTarget);
Context.insert(NewCall); Context.insert(NewCall);
if (NeedSandboxing) if (NeedSandboxing)
_bundle_unlock(); _bundle_unlock();
...@@ -2532,7 +2471,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2532,7 +2471,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem); Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// t1 = cvt Src0RM; Dest = t1 // t1 = cvt Src0RM; Dest = t1
Variable *T = makeReg(Dest->getType()); Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Float2float); _cvt(T, Src0RM, Traits::Insts::Cvt::Float2float);
_mov(Dest, T); _mov(Dest, T);
break; break;
} }
...@@ -2541,10 +2480,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2541,10 +2480,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
assert(Dest->getType() == IceType_v4i32 && assert(Dest->getType() == IceType_v4i32 &&
Inst->getSrc(0)->getType() == IceType_v4f32); Inst->getSrc(0)->getType() == IceType_v4f32);
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem); Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
if (llvm::isa<OperandX8632Mem>(Src0RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM); Src0RM = legalizeToVar(Src0RM);
Variable *T = makeReg(Dest->getType()); Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Tps2dq); _cvt(T, Src0RM, Traits::Insts::Cvt::Tps2dq);
_movp(Dest, T); _movp(Dest, T);
} else if (Dest->getType() == IceType_i64) { } else if (Dest->getType() == IceType_i64) {
// Use a helper for converting floating-point values to 64-bit // Use a helper for converting floating-point values to 64-bit
...@@ -2567,7 +2506,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2567,7 +2506,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
Variable *T_2 = makeReg(Dest->getType()); Variable *T_2 = makeReg(Dest->getType());
_cvt(T_1, Src0RM, InstX8632Cvt::Tss2si); _cvt(T_1, Src0RM, Traits::Insts::Cvt::Tss2si);
_mov(T_2, T_1); // T_1 and T_2 may have different integer types _mov(T_2, T_1); // T_1 and T_2 may have different integer types
if (Dest->getType() == IceType_i1) if (Dest->getType() == IceType_i1)
_and(T_2, Ctx->getConstantInt1(1)); _and(T_2, Ctx->getConstantInt1(1));
...@@ -2606,7 +2545,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2606,7 +2545,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32); Variable *T_1 = makeReg(IceType_i32);
Variable *T_2 = makeReg(Dest->getType()); Variable *T_2 = makeReg(Dest->getType());
_cvt(T_1, Src0RM, InstX8632Cvt::Tss2si); _cvt(T_1, Src0RM, Traits::Insts::Cvt::Tss2si);
_mov(T_2, T_1); // T_1 and T_2 may have different integer types _mov(T_2, T_1); // T_1 and T_2 may have different integer types
if (Dest->getType() == IceType_i1) if (Dest->getType() == IceType_i1)
_and(T_2, Ctx->getConstantInt1(1)); _and(T_2, Ctx->getConstantInt1(1));
...@@ -2618,10 +2557,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2618,10 +2557,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
assert(Dest->getType() == IceType_v4f32 && assert(Dest->getType() == IceType_v4f32 &&
Inst->getSrc(0)->getType() == IceType_v4i32); Inst->getSrc(0)->getType() == IceType_v4i32);
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem); Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
if (llvm::isa<OperandX8632Mem>(Src0RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM); Src0RM = legalizeToVar(Src0RM);
Variable *T = makeReg(Dest->getType()); Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Dq2ps); _cvt(T, Src0RM, Traits::Insts::Cvt::Dq2ps);
_movp(Dest, T); _movp(Dest, T);
} else if (Inst->getSrc(0)->getType() == IceType_i64) { } else if (Inst->getSrc(0)->getType() == IceType_i64) {
// Use a helper for x86-32. // Use a helper for x86-32.
...@@ -2645,7 +2584,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2645,7 +2584,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
_mov(T_1, Src0RM); _mov(T_1, Src0RM);
else else
_movsx(T_1, Src0RM); _movsx(T_1, Src0RM);
_cvt(T_2, T_1, InstX8632Cvt::Si2ss); _cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
_mov(Dest, T_2); _mov(Dest, T_2);
} }
break; break;
...@@ -2686,7 +2625,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2686,7 +2625,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
_mov(T_1, Src0RM); _mov(T_1, Src0RM);
else else
_movzx(T_1, Src0RM); _movzx(T_1, Src0RM);
_cvt(T_2, T_1, InstX8632Cvt::Si2ss); _cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
_mov(Dest, T_2); _mov(Dest, T_2);
} }
break; break;
...@@ -2728,8 +2667,8 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2728,8 +2667,8 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
Variable *T = nullptr; Variable *T = nullptr;
// TODO: Should be able to force a spill setup by calling legalize() with // TODO: Should be able to force a spill setup by calling legalize() with
// Legal_Mem and not Legal_Reg or Legal_Imm. // Legal_Mem and not Legal_Reg or Legal_Imm.
SpillVariable *SpillVar = typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(SrcType); Func->template makeVariable<typename Traits::SpillVariable>(SrcType);
SpillVar->setLinkedTo(Dest); SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar; Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero); Spill->setWeight(RegWeight::Zero);
...@@ -2748,14 +2687,17 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2748,14 +2687,17 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// a_hi.i32 = t_hi.i32 // a_hi.i32 = t_hi.i32
Operand *SpillLo, *SpillHi; Operand *SpillLo, *SpillHi;
if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) { if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
SpillVariable *SpillVar = typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(IceType_f64); Func->template makeVariable<typename Traits::SpillVariable>(
IceType_f64);
SpillVar->setLinkedTo(Src0Var); SpillVar->setLinkedTo(Src0Var);
Variable *Spill = SpillVar; Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero); Spill->setWeight(RegWeight::Zero);
_movq(Spill, Src0RM); _movq(Spill, Src0RM);
SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low); SpillLo = Traits::VariableSplit::create(Func, Spill,
SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High); Traits::VariableSplit::Low);
SpillHi = Traits::VariableSplit::create(Func, Spill,
Traits::VariableSplit::High);
} else { } else {
SpillLo = loOperand(Src0RM); SpillLo = loOperand(Src0RM);
SpillHi = hiOperand(Src0RM); SpillHi = hiOperand(Src0RM);
...@@ -2774,7 +2716,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2774,7 +2716,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
case IceType_f64: { case IceType_f64: {
Src0 = legalize(Src0); Src0 = legalize(Src0);
assert(Src0->getType() == IceType_i64); assert(Src0->getType() == IceType_i64);
if (llvm::isa<OperandX8632Mem>(Src0)) { if (llvm::isa<typename Traits::X86OperandMem>(Src0)) {
Variable *T = Func->template makeVariable(Dest->getType()); Variable *T = Func->template makeVariable(Dest->getType());
_movq(T, Src0); _movq(T, Src0);
_movq(Dest, T); _movq(Dest, T);
...@@ -2787,17 +2729,18 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) { ...@@ -2787,17 +2729,18 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t_hi.i32 = b_hi.i32 // t_hi.i32 = b_hi.i32
// hi(s.f64) = t_hi.i32 // hi(s.f64) = t_hi.i32
// a.f64 = s.f64 // a.f64 = s.f64
SpillVariable *SpillVar = typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(IceType_f64); Func->template makeVariable<typename Traits::SpillVariable>(
IceType_f64);
SpillVar->setLinkedTo(Dest); SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar; Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero); Spill->setWeight(RegWeight::Zero);
Variable *T_Lo = nullptr, *T_Hi = nullptr; Variable *T_Lo = nullptr, *T_Hi = nullptr;
VariableSplit *SpillLo = typename Traits::VariableSplit *SpillLo = Traits::VariableSplit::create(
VariableSplit::create(Func, Spill, VariableSplit::Low); Func, Spill, Traits::VariableSplit::Low);
VariableSplit *SpillHi = typename Traits::VariableSplit *SpillHi = Traits::VariableSplit::create(
VariableSplit::create(Func, Spill, VariableSplit::High); Func, Spill, Traits::VariableSplit::High);
_mov(T_Lo, loOperand(Src0)); _mov(T_Lo, loOperand(Src0));
// Technically, the Spill is defined after the _store happens, but // Technically, the Spill is defined after the _store happens, but
// SpillLo is considered a "use" of Spill so define Spill before it // SpillLo is considered a "use" of Spill so define Spill before it
...@@ -2897,7 +2840,7 @@ void TargetX86Base<Machine>::lowerExtractElement( ...@@ -2897,7 +2840,7 @@ void TargetX86Base<Machine>::lowerExtractElement(
// Compute the location of the element in memory. // Compute the location of the element in memory.
unsigned Offset = Index * typeWidthInBytes(InVectorElementTy); unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
OperandX8632Mem *Loc = typename Traits::X86OperandMem *Loc =
getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset); getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
_mov(ExtractedElementR, Loc); _mov(ExtractedElementR, Loc);
} }
...@@ -2943,7 +2886,7 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) { ...@@ -2943,7 +2886,7 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) {
} else { } else {
Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem); Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem); Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
if (llvm::isa<OperandX8632Mem>(Src1RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM); Src1RM = legalizeToVar(Src1RM);
switch (Condition) { switch (Condition) {
...@@ -3018,7 +2961,8 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) { ...@@ -3018,7 +2961,8 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) {
Constant *Default = Ctx->getConstantInt32(Traits::TableFcmp[Index].Default); Constant *Default = Ctx->getConstantInt32(Traits::TableFcmp[Index].Default);
_mov(Dest, Default); _mov(Dest, Default);
if (HasC1) { if (HasC1) {
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
_br(Traits::TableFcmp[Index].C1, Label); _br(Traits::TableFcmp[Index].C1, Label);
if (HasC2) { if (HasC2) {
_br(Traits::TableFcmp[Index].C2, Label); _br(Traits::TableFcmp[Index].C2, Label);
...@@ -3091,13 +3035,13 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3091,13 +3035,13 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
llvm_unreachable("unexpected condition"); llvm_unreachable("unexpected condition");
break; break;
case InstIcmp::Eq: { case InstIcmp::Eq: {
if (llvm::isa<OperandX8632Mem>(Src1RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM); Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM); _movp(T, Src0RM);
_pcmpeq(T, Src1RM); _pcmpeq(T, Src1RM);
} break; } break;
case InstIcmp::Ne: { case InstIcmp::Ne: {
if (llvm::isa<OperandX8632Mem>(Src1RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM); Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM); _movp(T, Src0RM);
_pcmpeq(T, Src1RM); _pcmpeq(T, Src1RM);
...@@ -3106,7 +3050,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3106,7 +3050,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
} break; } break;
case InstIcmp::Ugt: case InstIcmp::Ugt:
case InstIcmp::Sgt: { case InstIcmp::Sgt: {
if (llvm::isa<OperandX8632Mem>(Src1RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM); Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM); _movp(T, Src0RM);
_pcmpgt(T, Src1RM); _pcmpgt(T, Src1RM);
...@@ -3114,7 +3058,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3114,7 +3058,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
case InstIcmp::Uge: case InstIcmp::Uge:
case InstIcmp::Sge: { case InstIcmp::Sge: {
// !(Src1RM > Src0RM) // !(Src1RM > Src0RM)
if (llvm::isa<OperandX8632Mem>(Src0RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM); Src0RM = legalizeToVar(Src0RM);
_movp(T, Src1RM); _movp(T, Src1RM);
_pcmpgt(T, Src0RM); _pcmpgt(T, Src0RM);
...@@ -3123,7 +3067,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3123,7 +3067,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
} break; } break;
case InstIcmp::Ult: case InstIcmp::Ult:
case InstIcmp::Slt: { case InstIcmp::Slt: {
if (llvm::isa<OperandX8632Mem>(Src0RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM); Src0RM = legalizeToVar(Src0RM);
_movp(T, Src1RM); _movp(T, Src1RM);
_pcmpgt(T, Src0RM); _pcmpgt(T, Src0RM);
...@@ -3131,7 +3075,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3131,7 +3075,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
case InstIcmp::Ule: case InstIcmp::Ule:
case InstIcmp::Sle: { case InstIcmp::Sle: {
// !(Src0RM > Src1RM) // !(Src0RM > Src1RM)
if (llvm::isa<OperandX8632Mem>(Src1RM)) if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM); Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM); _movp(T, Src0RM);
_pcmpgt(T, Src1RM); _pcmpgt(T, Src1RM);
...@@ -3156,8 +3100,10 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) { ...@@ -3156,8 +3100,10 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
Operand *Src1HiRI = legalize(hiOperand(Src1), Legal_Reg | Legal_Imm); Operand *Src1HiRI = legalize(hiOperand(Src1), Legal_Reg | Legal_Imm);
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
Constant *One = Ctx->getConstantInt32(1); Constant *One = Ctx->getConstantInt32(1);
InstX8632Label *LabelFalse = InstX8632Label::create(Func, this); typename Traits::Insts::Label *LabelFalse =
InstX8632Label *LabelTrue = InstX8632Label::create(Func, this); Traits::Insts::Label::create(Func, this);
typename Traits::Insts::Label *LabelTrue =
Traits::Insts::Label::create(Func, this);
_mov(Dest, One); _mov(Dest, One);
_cmp(Src0HiRM, Src1HiRI); _cmp(Src0HiRM, Src1HiRI);
if (Traits::TableIcmp64[Index].C1 != Traits::Cond::Br_None) if (Traits::TableIcmp64[Index].C1 != Traits::Cond::Br_None)
...@@ -3293,7 +3239,7 @@ void TargetX86Base<Machine>::lowerInsertElement(const InstInsertElement *Inst) { ...@@ -3293,7 +3239,7 @@ void TargetX86Base<Machine>::lowerInsertElement(const InstInsertElement *Inst) {
// Compute the location of the position to insert in memory. // Compute the location of the position to insert in memory.
unsigned Offset = Index * typeWidthInBytes(InVectorElementTy); unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
OperandX8632Mem *Loc = typename Traits::X86OperandMem *Loc =
getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset); getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
_store(legalizeToVar(ElementToInsertNotLegalized), Loc); _store(legalizeToVar(ElementToInsertNotLegalized), Loc);
...@@ -3383,7 +3329,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3383,7 +3329,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
// can't happen anyway, since this is x86-32 and integer arithmetic only // can't happen anyway, since this is x86-32 and integer arithmetic only
// happens on 32-bit quantities. // happens on 32-bit quantities.
Variable *T = makeReg(IceType_f64); Variable *T = makeReg(IceType_f64);
OperandX8632Mem *Addr = formMemoryOperand(Instr->getArg(0), IceType_f64); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Instr->getArg(0), IceType_f64);
_movq(T, Addr); _movq(T, Addr);
// Then cast the bits back out of the XMM register to the i64 Dest. // Then cast the bits back out of the XMM register to the i64 Dest.
InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T); InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T);
...@@ -3433,7 +3380,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3433,7 +3380,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value); InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value);
lowerCast(Cast); lowerCast(Cast);
// Then store XMM w/ a movq. // Then store XMM w/ a movq.
OperandX8632Mem *Addr = formMemoryOperand(Ptr, IceType_f64); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, IceType_f64);
_storeq(T, Addr); _storeq(T, Addr);
_mfence(); _mfence();
return; return;
...@@ -3535,7 +3483,7 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3535,7 +3483,7 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
// The pand instruction operates on an m128 memory operand, so if // The pand instruction operates on an m128 memory operand, so if
// Src is an f32 or f64, we need to make sure it's in a register. // Src is an f32 or f64, we need to make sure it's in a register.
if (isVectorType(Ty)) { if (isVectorType(Ty)) {
if (llvm::isa<OperandX8632Mem>(Src)) if (llvm::isa<typename Traits::X86OperandMem>(Src))
Src = legalizeToVar(Src); Src = legalizeToVar(Src);
} else { } else {
Src = legalizeToVar(Src); Src = legalizeToVar(Src);
...@@ -3590,9 +3538,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall( ...@@ -3590,9 +3538,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
case Intrinsics::NaClReadTP: { case Intrinsics::NaClReadTP: {
if (Ctx->getFlags().getUseSandboxing()) { if (Ctx->getFlags().getUseSandboxing()) {
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
Operand *Src = Operand *Src = Traits::X86OperandMem::create(
OperandX8632Mem::create(Func, IceType_i32, nullptr, Zero, nullptr, 0, Func, IceType_i32, nullptr, Zero, nullptr, 0,
OperandX8632Mem::SegReg_GS); Traits::X86OperandMem::SegReg_GS);
Variable *Dest = Instr->getDest(); Variable *Dest = Instr->getDest();
Variable *T = nullptr; Variable *T = nullptr;
_mov(T, Src); _mov(T, Src);
...@@ -3655,7 +3603,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev, ...@@ -3655,7 +3603,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev,
_mov(T_edx, hiOperand(Expected)); _mov(T_edx, hiOperand(Expected));
_mov(T_ebx, loOperand(Desired)); _mov(T_ebx, loOperand(Desired));
_mov(T_ecx, hiOperand(Desired)); _mov(T_ecx, hiOperand(Desired));
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Expected->getType()); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Expected->getType());
const bool Locked = true; const bool Locked = true;
_cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked); _cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
Variable *DestLo = llvm::cast<Variable>(loOperand(DestPrev)); Variable *DestLo = llvm::cast<Variable>(loOperand(DestPrev));
...@@ -3666,7 +3615,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev, ...@@ -3666,7 +3615,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev,
} }
Variable *T_eax = makeReg(Expected->getType(), Traits::RegisterSet::Reg_eax); Variable *T_eax = makeReg(Expected->getType(), Traits::RegisterSet::Reg_eax);
_mov(T_eax, Expected); _mov(T_eax, Expected);
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Expected->getType()); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Expected->getType());
Variable *DesiredReg = legalizeToVar(Desired); Variable *DesiredReg = legalizeToVar(Desired);
const bool Locked = true; const bool Locked = true;
_cmpxchg(Addr, T_eax, DesiredReg, Locked); _cmpxchg(Addr, T_eax, DesiredReg, Locked);
...@@ -3768,7 +3718,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation, ...@@ -3768,7 +3718,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = &TargetX86Base<Machine>::_adc; Op_Hi = &TargetX86Base<Machine>::_adc;
break; break;
} }
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType()); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
const bool Locked = true; const bool Locked = true;
Variable *T = nullptr; Variable *T = nullptr;
_mov(T, Val); _mov(T, Val);
...@@ -3783,7 +3734,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation, ...@@ -3783,7 +3734,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = &TargetX86Base<Machine>::_sbb; Op_Hi = &TargetX86Base<Machine>::_sbb;
break; break;
} }
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType()); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
const bool Locked = true; const bool Locked = true;
Variable *T = nullptr; Variable *T = nullptr;
_mov(T, Val); _mov(T, Val);
...@@ -3821,7 +3773,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation, ...@@ -3821,7 +3773,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = nullptr; Op_Hi = nullptr;
break; break;
} }
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType()); typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
Variable *T = nullptr; Variable *T = nullptr;
_mov(T, Val); _mov(T, Val);
_xchg(Addr, T); _xchg(Addr, T);
...@@ -3869,12 +3822,13 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, ...@@ -3869,12 +3822,13 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Variable *T_edx = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx); Variable *T_edx = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
Variable *T_eax = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax); Variable *T_eax = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax);
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Ty); typename Traits::X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
_mov(T_eax, loOperand(Addr)); _mov(T_eax, loOperand(Addr));
_mov(T_edx, hiOperand(Addr)); _mov(T_edx, hiOperand(Addr));
Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx); Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
Variable *T_ebx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ebx); Variable *T_ebx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ebx);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
const bool IsXchg8b = Op_Lo == nullptr && Op_Hi == nullptr; const bool IsXchg8b = Op_Lo == nullptr && Op_Hi == nullptr;
if (!IsXchg8b) { if (!IsXchg8b) {
Context.insert(Label); Context.insert(Label);
...@@ -3916,10 +3870,11 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, ...@@ -3916,10 +3870,11 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
_mov(DestHi, T_edx); _mov(DestHi, T_edx);
return; return;
} }
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Ty); typename Traits::X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
Variable *T_eax = makeReg(Ty, Traits::RegisterSet::Reg_eax); Variable *T_eax = makeReg(Ty, Traits::RegisterSet::Reg_eax);
_mov(T_eax, Addr); _mov(T_eax, Addr);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
Context.insert(Label); Context.insert(Label);
// We want to pick a different register for T than Eax, so don't use // We want to pick a different register for T than Eax, so don't use
// _mov(T == nullptr, T_eax). // _mov(T == nullptr, T_eax).
...@@ -4260,11 +4215,11 @@ void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base, ...@@ -4260,11 +4215,11 @@ void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base,
template <class Machine> template <class Machine>
void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) { void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) {
// A Load instruction can be treated the same as an Assign // A Load instruction can be treated the same as an Assign instruction, after
// instruction, after the source operand is transformed into an // the source operand is transformed into an Traits::X86OperandMem operand.
// OperandX8632Mem operand. Note that the address mode // Note that the address mode optimization already creates an
// optimization already creates an OperandX8632Mem operand, so it // Traits::X86OperandMem operand, so it doesn't need another level of
// doesn't need another level of transformation. // transformation.
Variable *DestLoad = Load->getDest(); Variable *DestLoad = Load->getDest();
Type Ty = DestLoad->getType(); Type Ty = DestLoad->getType();
Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
...@@ -4279,19 +4234,19 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() { ...@@ -4279,19 +4234,19 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() {
Variable *Index = nullptr; Variable *Index = nullptr;
uint16_t Shift = 0; uint16_t Shift = 0;
int32_t Offset = 0; // TODO: make Constant int32_t Offset = 0; // TODO: make Constant
// Vanilla ICE load instructions should not use the segment registers, // Vanilla ICE load instructions should not use the segment registers, and
// and computeAddressOpt only works at the level of Variables and Constants, // computeAddressOpt only works at the level of Variables and Constants, not
// not other OperandX8632Mem, so there should be no mention of segment // other Traits::X86OperandMem, so there should be no mention of segment
// registers there either. // registers there either.
const OperandX8632Mem::SegmentRegisters SegmentReg = const typename Traits::X86OperandMem::SegmentRegisters SegmentReg =
OperandX8632Mem::DefaultSegment; Traits::X86OperandMem::DefaultSegment;
Variable *Base = llvm::dyn_cast<Variable>(Addr); Variable *Base = llvm::dyn_cast<Variable>(Addr);
computeAddressOpt(Func, Inst, Base, Index, Shift, Offset); computeAddressOpt(Func, Inst, Base, Index, Shift, Offset);
if (Base && Addr != Base) { if (Base && Addr != Base) {
Inst->setDeleted(); Inst->setDeleted();
Constant *OffsetOp = Ctx->getConstantInt32(Offset); Constant *OffsetOp = Ctx->getConstantInt32(Offset);
Addr = OperandX8632Mem::create(Func, Dest->getType(), Base, OffsetOp, Index, Addr = Traits::X86OperandMem::create(Func, Dest->getType(), Base, OffsetOp,
Shift, SegmentReg); Index, Shift, SegmentReg);
Context.insert(InstLoad::create(Func, Dest, Addr)); Context.insert(InstLoad::create(Func, Dest, Addr));
} }
} }
...@@ -4438,7 +4393,8 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) { ...@@ -4438,7 +4393,8 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
// The cmov instruction doesn't allow 8-bit or FP operands, so // The cmov instruction doesn't allow 8-bit or FP operands, so
// we need explicit control flow. // we need explicit control flow.
// d=cmp e,f; a=d?b:c ==> cmp e,f; a=b; jne L1; a=c; L1: // d=cmp e,f; a=d?b:c ==> cmp e,f; a=b; jne L1; a=c; L1:
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
SrcT = legalize(SrcT, Legal_Reg | Legal_Imm); SrcT = legalize(SrcT, Legal_Reg | Legal_Imm);
_mov(Dest, SrcT); _mov(Dest, SrcT);
_br(Cond, Label); _br(Cond, Label);
...@@ -4453,7 +4409,7 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) { ...@@ -4453,7 +4409,7 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
// mov t, SrcT; cmov_!cond t, SrcF; mov dest, t // mov t, SrcT; cmov_!cond t, SrcF; mov dest, t
if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) { if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) {
std::swap(SrcT, SrcF); std::swap(SrcT, SrcF);
Cond = InstX8632::getOppositeCondition(Cond); Cond = InstX86Base<Machine>::getOppositeCondition(Cond);
} }
if (DestTy == IceType_i64) { if (DestTy == IceType_i64) {
// Set the low portion. // Set the low portion.
...@@ -4488,15 +4444,18 @@ template <class Machine> ...@@ -4488,15 +4444,18 @@ template <class Machine>
void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) { void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
Operand *Value = Inst->getData(); Operand *Value = Inst->getData();
Operand *Addr = Inst->getAddr(); Operand *Addr = Inst->getAddr();
OperandX8632Mem *NewAddr = formMemoryOperand(Addr, Value->getType()); typename Traits::X86OperandMem *NewAddr =
formMemoryOperand(Addr, Value->getType());
Type Ty = NewAddr->getType(); Type Ty = NewAddr->getType();
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Value = legalize(Value); Value = legalize(Value);
Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm); Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm); Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
_store(ValueHi, llvm::cast<OperandX8632Mem>(hiOperand(NewAddr))); _store(ValueHi,
_store(ValueLo, llvm::cast<OperandX8632Mem>(loOperand(NewAddr))); llvm::cast<typename Traits::X86OperandMem>(hiOperand(NewAddr)));
_store(ValueLo,
llvm::cast<typename Traits::X86OperandMem>(loOperand(NewAddr)));
} else if (isVectorType(Ty)) { } else if (isVectorType(Ty)) {
_storep(legalizeToVar(Value), NewAddr); _storep(legalizeToVar(Value), NewAddr);
} else { } else {
...@@ -4513,18 +4472,18 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptStore() { ...@@ -4513,18 +4472,18 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptStore() {
uint16_t Shift = 0; uint16_t Shift = 0;
int32_t Offset = 0; // TODO: make Constant int32_t Offset = 0; // TODO: make Constant
Variable *Base = llvm::dyn_cast<Variable>(Addr); Variable *Base = llvm::dyn_cast<Variable>(Addr);
// Vanilla ICE store instructions should not use the segment registers, // Vanilla ICE store instructions should not use the segment registers, and
// and computeAddressOpt only works at the level of Variables and Constants, // computeAddressOpt only works at the level of Variables and Constants, not
// not other OperandX8632Mem, so there should be no mention of segment // other Traits::X86OperandMem, so there should be no mention of segment
// registers there either. // registers there either.
const OperandX8632Mem::SegmentRegisters SegmentReg = const typename Traits::X86OperandMem::SegmentRegisters SegmentReg =
OperandX8632Mem::DefaultSegment; Traits::X86OperandMem::DefaultSegment;
computeAddressOpt(Func, Inst, Base, Index, Shift, Offset); computeAddressOpt(Func, Inst, Base, Index, Shift, Offset);
if (Base && Addr != Base) { if (Base && Addr != Base) {
Inst->setDeleted(); Inst->setDeleted();
Constant *OffsetOp = Ctx->getConstantInt32(Offset); Constant *OffsetOp = Ctx->getConstantInt32(Offset);
Addr = OperandX8632Mem::create(Func, Data->getType(), Base, OffsetOp, Index, Addr = Traits::X86OperandMem::create(Func, Data->getType(), Base, OffsetOp,
Shift, SegmentReg); Index, Shift, SegmentReg);
InstStore *NewStore = InstStore::create(Func, Data, Addr); InstStore *NewStore = InstStore::create(Func, Data, Addr);
if (Inst->getDest()) if (Inst->getDest())
NewStore->setRmwBeacon(Inst->getRmwBeacon()); NewStore->setRmwBeacon(Inst->getRmwBeacon());
...@@ -4552,7 +4511,8 @@ void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) { ...@@ -4552,7 +4511,8 @@ void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) {
for (SizeT I = 0; I < NumCases; ++I) { for (SizeT I = 0; I < NumCases; ++I) {
Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I)); Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
InstX8632Label *Label = InstX8632Label::create(Func, this); typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
_cmp(Src0Lo, ValueLo); _cmp(Src0Lo, ValueLo);
_br(Traits::Cond::Br_ne, Label); _br(Traits::Cond::Br_ne, Label);
_cmp(Src0Hi, ValueHi); _cmp(Src0Hi, ValueHi);
...@@ -4639,7 +4599,8 @@ void TargetX86Base<Machine>::lowerUnreachable( ...@@ -4639,7 +4599,8 @@ void TargetX86Base<Machine>::lowerUnreachable(
} }
template <class Machine> template <class Machine>
void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) { void TargetX86Base<Machine>::lowerRMW(
const typename Traits::Insts::FakeRMW *RMW) {
// If the beacon variable's live range does not end in this // If the beacon variable's live range does not end in this
// instruction, then it must end in the modified Store instruction // instruction, then it must end in the modified Store instruction
// that follows. This means that the original Store instruction is // that follows. This means that the original Store instruction is
...@@ -4651,12 +4612,14 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) { ...@@ -4651,12 +4612,14 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) {
return; return;
Operand *Src = RMW->getData(); Operand *Src = RMW->getData();
Type Ty = Src->getType(); Type Ty = Src->getType();
OperandX8632Mem *Addr = formMemoryOperand(RMW->getAddr(), Ty); typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
if (Ty == IceType_i64) { if (Ty == IceType_i64) {
Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm); Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm); Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
OperandX8632Mem *AddrLo = llvm::cast<OperandX8632Mem>(loOperand(Addr)); typename Traits::X86OperandMem *AddrLo =
OperandX8632Mem *AddrHi = llvm::cast<OperandX8632Mem>(hiOperand(Addr)); llvm::cast<typename Traits::X86OperandMem>(loOperand(Addr));
typename Traits::X86OperandMem *AddrHi =
llvm::cast<typename Traits::X86OperandMem>(hiOperand(Addr));
switch (RMW->getOp()) { switch (RMW->getOp()) {
default: default:
// TODO(stichnot): Implement other arithmetic operators. // TODO(stichnot): Implement other arithmetic operators.
...@@ -4715,7 +4678,8 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) { ...@@ -4715,7 +4678,8 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) {
template <class Machine> template <class Machine>
void TargetX86Base<Machine>::lowerOther(const Inst *Instr) { void TargetX86Base<Machine>::lowerOther(const Inst *Instr) {
if (const auto *RMW = llvm::dyn_cast<InstX8632FakeRMW>(Instr)) { if (const auto *RMW =
llvm::dyn_cast<typename Traits::Insts::FakeRMW>(Instr)) {
lowerRMW(RMW); lowerRMW(RMW);
} else { } else {
TargetLowering::lowerOther(Instr); TargetLowering::lowerOther(Instr);
...@@ -4991,7 +4955,7 @@ Variable *TargetX86Base<Machine>::makeVectorOfFabsMask(Type Ty, ...@@ -4991,7 +4955,7 @@ Variable *TargetX86Base<Machine>::makeVectorOfFabsMask(Type Ty,
} }
template <class Machine> template <class Machine>
OperandX8632Mem * typename TargetX86Base<Machine>::Traits::X86OperandMem *
TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot, TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
uint32_t Offset) { uint32_t Offset) {
// Ensure that Loc is a stack slot. // Ensure that Loc is a stack slot.
...@@ -5005,7 +4969,7 @@ TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot, ...@@ -5005,7 +4969,7 @@ TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
Variable *Loc = makeReg(PointerType); Variable *Loc = makeReg(PointerType);
_lea(Loc, Slot); _lea(Loc, Slot);
Constant *ConstantOffset = Ctx->getConstantInt32(Offset); Constant *ConstantOffset = Ctx->getConstantInt32(Offset);
return OperandX8632Mem::create(Func, Ty, Loc, ConstantOffset); return Traits::X86OperandMem::create(Func, Ty, Loc, ConstantOffset);
} }
/// Helper for legalize() to emit the right code to lower an operand to a /// Helper for legalize() to emit the right code to lower an operand to a
...@@ -5037,7 +5001,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5037,7 +5001,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
// or in ecx.) // or in ecx.)
assert(RegNum == Variable::NoRegister || Allowed == Legal_Reg); assert(RegNum == Variable::NoRegister || Allowed == Legal_Reg);
if (auto Mem = llvm::dyn_cast<OperandX8632Mem>(From)) { if (auto Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(From)) {
// Before doing anything with a Mem operand, we need to ensure // Before doing anything with a Mem operand, we need to ensure
// that the Base and Index components are in physical registers. // that the Base and Index components are in physical registers.
Variable *Base = Mem->getBase(); Variable *Base = Mem->getBase();
...@@ -5051,9 +5015,9 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5051,9 +5015,9 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
RegIndex = legalizeToVar(Index); RegIndex = legalizeToVar(Index);
} }
if (Base != RegBase || Index != RegIndex) { if (Base != RegBase || Index != RegIndex) {
Mem = Mem = Traits::X86OperandMem::create(Func, Ty, RegBase, Mem->getOffset(),
OperandX8632Mem::create(Func, Ty, RegBase, Mem->getOffset(), RegIndex, RegIndex, Mem->getShift(),
Mem->getShift(), Mem->getSegmentRegister()); Mem->getSegmentRegister());
} }
// For all Memory Operands, we do randomization/pooling here // For all Memory Operands, we do randomization/pooling here
...@@ -5103,7 +5067,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed, ...@@ -5103,7 +5067,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
llvm::cast<Constant>(From)->emitPoolLabel(StrBuf); llvm::cast<Constant>(From)->emitPoolLabel(StrBuf);
llvm::cast<Constant>(From)->setShouldBePooled(true); llvm::cast<Constant>(From)->setShouldBePooled(true);
Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true);
From = OperandX8632Mem::create(Func, Ty, Base, Offset); From = Traits::X86OperandMem::create(Func, Ty, Base, Offset);
} }
bool NeedsReg = false; bool NeedsReg = false;
if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty)) if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
...@@ -5162,13 +5126,13 @@ Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0, ...@@ -5162,13 +5126,13 @@ Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0,
} }
template <class Machine> template <class Machine>
OperandX8632Mem *TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, typename TargetX86Base<Machine>::Traits::X86OperandMem *
Type Ty, TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, Type Ty,
bool DoLegalize) { bool DoLegalize) {
OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Opnd); auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Opnd);
// It may be the case that address mode optimization already creates // It may be the case that address mode optimization already creates an
// an OperandX8632Mem, so in that case it wouldn't need another level // Traits::X86OperandMem, so in that case it wouldn't need another level of
// of transformation. // transformation.
if (!Mem) { if (!Mem) {
Variable *Base = llvm::dyn_cast<Variable>(Opnd); Variable *Base = llvm::dyn_cast<Variable>(Opnd);
Constant *Offset = llvm::dyn_cast<Constant>(Opnd); Constant *Offset = llvm::dyn_cast<Constant>(Opnd);
...@@ -5188,11 +5152,11 @@ OperandX8632Mem *TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, ...@@ -5188,11 +5152,11 @@ OperandX8632Mem *TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd,
assert(llvm::isa<ConstantInteger32>(Offset) || assert(llvm::isa<ConstantInteger32>(Offset) ||
llvm::isa<ConstantRelocatable>(Offset)); llvm::isa<ConstantRelocatable>(Offset));
} }
Mem = OperandX8632Mem::create(Func, Ty, Base, Offset); Mem = Traits::X86OperandMem::create(Func, Ty, Base, Offset);
} }
// Do legalization, which contains randomization/pooling // Do legalization, which contains randomization/pooling
// or do randomization/pooling. // or do randomization/pooling.
return llvm::cast<OperandX8632Mem>( return llvm::cast<typename Traits::X86OperandMem>(
DoLegalize ? legalize(Mem) : randomizeOrPoolImmediate(Mem)); DoLegalize ? legalize(Mem) : randomizeOrPoolImmediate(Mem));
} }
...@@ -5218,68 +5182,8 @@ template <class Machine> ...@@ -5218,68 +5182,8 @@ template <class Machine>
void TargetX86Base<Machine>::makeRandomRegisterPermutation( void TargetX86Base<Machine>::makeRandomRegisterPermutation(
llvm::SmallVectorImpl<int32_t> &Permutation, llvm::SmallVectorImpl<int32_t> &Permutation,
const llvm::SmallBitVector &ExcludeRegisters) const { const llvm::SmallBitVector &ExcludeRegisters) const {
// TODO(stichnot): Declaring Permutation this way loses type/size Traits::makeRandomRegisterPermutation(Ctx, Func, Permutation,
// information. Fix this in conjunction with the caller-side TODO. ExcludeRegisters);
assert(Permutation.size() >= Traits::RegisterSet::Reg_NUM);
// Expected upper bound on the number of registers in a single
// equivalence class. For x86-32, this would comprise the 8 XMM
// registers. This is for performance, not correctness.
static const unsigned MaxEquivalenceClassSize = 8;
typedef llvm::SmallVector<int32_t, MaxEquivalenceClassSize> RegisterList;
typedef std::map<uint32_t, RegisterList> EquivalenceClassMap;
EquivalenceClassMap EquivalenceClasses;
SizeT NumShuffled = 0, NumPreserved = 0;
// Build up the equivalence classes of registers by looking at the
// register properties as well as whether the registers should be
// explicitly excluded from shuffling.
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
if (ExcludeRegisters[Traits::RegisterSet::val]) { \
/* val stays the same in the resulting permutation. */ \
Permutation[Traits::RegisterSet::val] = Traits::RegisterSet::val; \
++NumPreserved; \
} else { \
const uint32_t Index = (scratch << 0) | (preserved << 1) | (isI8 << 2) | \
(isInt << 3) | (isFP << 4); \
/* val is assigned to an equivalence class based on its properties. */ \
EquivalenceClasses[Index].push_back(Traits::RegisterSet::val); \
}
REGX8632_TABLE
#undef X
RandomNumberGeneratorWrapper RNG(Ctx->getRNG());
// Shuffle the resulting equivalence classes.
for (auto I : EquivalenceClasses) {
const RegisterList &List = I.second;
RegisterList Shuffled(List);
RandomShuffle(Shuffled.begin(), Shuffled.end(), RNG);
for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) {
Permutation[List[SI]] = Shuffled[SI];
++NumShuffled;
}
}
assert(NumShuffled + NumPreserved == Traits::RegisterSet::Reg_NUM);
if (Func->isVerbose(IceV_Random)) {
OstreamLocker L(Func->getContext());
Ostream &Str = Func->getContext()->getStrDump();
Str << "Register equivalence classes:\n";
for (auto I : EquivalenceClasses) {
Str << "{";
const RegisterList &List = I.second;
bool First = true;
for (int32_t Register : List) {
if (!First)
Str << " ";
First = false;
Str << getRegName(Register, IceType_i32);
}
Str << "}\n";
}
}
} }
template <class Machine> template <class Machine>
...@@ -5350,8 +5254,8 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate, ...@@ -5350,8 +5254,8 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
uint32_t Cookie = Ctx->getRandomizationCookie(); uint32_t Cookie = Ctx->getRandomizationCookie();
_mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value)); _mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value));
Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie); Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie);
_lea(Reg, _lea(Reg, Traits::X86OperandMem::create(Func, IceType_i32, Reg, Offset,
OperandX8632Mem::create(Func, IceType_i32, Reg, Offset, nullptr, 0)); nullptr, 0));
// make sure liveness analysis won't kill this variable, otherwise a // make sure liveness analysis won't kill this variable, otherwise a
// liveness // liveness
// assertion will be triggered. // assertion will be triggered.
...@@ -5384,8 +5288,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate, ...@@ -5384,8 +5288,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
const bool SuppressMangling = true; const bool SuppressMangling = true;
Constant *Symbol = Constant *Symbol =
Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling);
OperandX8632Mem *MemOperand = typename Traits::X86OperandMem *MemOperand =
OperandX8632Mem::create(Func, Immediate->getType(), nullptr, Symbol); Traits::X86OperandMem::create(Func, Immediate->getType(), nullptr,
Symbol);
_mov(Reg, MemOperand); _mov(Reg, MemOperand);
return Reg; return Reg;
} }
...@@ -5396,9 +5301,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate, ...@@ -5396,9 +5301,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
} }
template <class Machine> template <class Machine>
OperandX8632Mem * typename TargetX86Base<Machine>::Traits::X86OperandMem *
TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, TargetX86Base<Machine>::randomizeOrPoolImmediate(
int32_t RegNum) { typename Traits::X86OperandMem *MemOperand, int32_t RegNum) {
assert(MemOperand); assert(MemOperand);
if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None || if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
RandomizationPoolingPaused == true) { RandomizationPoolingPaused == true) {
...@@ -5432,8 +5337,9 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, ...@@ -5432,8 +5337,9 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
Constant *Mask2 = Constant *Mask2 =
Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie); Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie);
OperandX8632Mem *TempMemOperand = OperandX8632Mem::create( typename Traits::X86OperandMem *TempMemOperand =
Func, MemOperand->getType(), MemOperand->getBase(), Mask1); Traits::X86OperandMem::create(Func, MemOperand->getType(),
MemOperand->getBase(), Mask1);
// If we have already assigned a physical register, we must come from // If we have already assigned a physical register, we must come from
// advancedPhiLowering()=>lowerAssign(). In this case we should reuse // advancedPhiLowering()=>lowerAssign(). In this case we should reuse
// the assigned register as this assignment is that start of its use-def // the assigned register as this assignment is that start of its use-def
...@@ -5447,9 +5353,11 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, ...@@ -5447,9 +5353,11 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
if (RegNum != Variable::NoRegister) if (RegNum != Variable::NoRegister)
_set_dest_nonkillable(); _set_dest_nonkillable();
OperandX8632Mem *NewMemOperand = OperandX8632Mem::create( typename Traits::X86OperandMem *NewMemOperand =
Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(), Traits::X86OperandMem::create(Func, MemOperand->getType(), RegTemp,
MemOperand->getShift(), MemOperand->getSegmentRegister()); Mask2, MemOperand->getIndex(),
MemOperand->getShift(),
MemOperand->getSegmentRegister());
// Label this memory operand as randomize, so we won't randomize it // Label this memory operand as randomize, so we won't randomize it
// again in case we call legalize() mutiple times on this memory // again in case we call legalize() mutiple times on this memory
...@@ -5484,22 +5392,25 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, ...@@ -5484,22 +5392,25 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
bool SuppressMangling = true; bool SuppressMangling = true;
Constant *Symbol = Ctx->getConstantSym(SymOffset, Label_stream.str(), Constant *Symbol = Ctx->getConstantSym(SymOffset, Label_stream.str(),
SuppressMangling); SuppressMangling);
OperandX8632Mem *SymbolOperand = OperandX8632Mem::create( typename Traits::X86OperandMem *SymbolOperand =
Traits::X86OperandMem::create(
Func, MemOperand->getOffset()->getType(), nullptr, Symbol); Func, MemOperand->getOffset()->getType(), nullptr, Symbol);
_mov(RegTemp, SymbolOperand); _mov(RegTemp, SymbolOperand);
// If we have a base variable here, we should add the lea instruction // If we have a base variable here, we should add the lea instruction
// to add the value of the base variable to RegTemp. If there is no // to add the value of the base variable to RegTemp. If there is no
// base variable, we won't need this lea instruction. // base variable, we won't need this lea instruction.
if (MemOperand->getBase()) { if (MemOperand->getBase()) {
OperandX8632Mem *CalculateOperand = OperandX8632Mem::create( typename Traits::X86OperandMem *CalculateOperand =
Traits::X86OperandMem::create(
Func, MemOperand->getType(), MemOperand->getBase(), nullptr, Func, MemOperand->getType(), MemOperand->getBase(), nullptr,
RegTemp, 0, MemOperand->getSegmentRegister()); RegTemp, 0, MemOperand->getSegmentRegister());
_lea(RegTemp, CalculateOperand); _lea(RegTemp, CalculateOperand);
_set_dest_nonkillable(); _set_dest_nonkillable();
} }
OperandX8632Mem *NewMemOperand = OperandX8632Mem::create( typename Traits::X86OperandMem *NewMemOperand =
Func, MemOperand->getType(), RegTemp, nullptr, Traits::X86OperandMem::create(Func, MemOperand->getType(), RegTemp,
MemOperand->getIndex(), MemOperand->getShift(), nullptr, MemOperand->getIndex(),
MemOperand->getShift(),
MemOperand->getSegmentRegister()); MemOperand->getSegmentRegister());
return NewMemOperand; return NewMemOperand;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment