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;
namespace X8632 {
using Immediate = ::Ice::X86Internal::Immediate;
using Label = ::Ice::X86Internal::Label;
class AssemblerX8632 : public X86Internal::AssemblerX86Base<TargetX8632> {
AssemblerX8632(const AssemblerX8632 &) = delete;
AssemblerX8632 &operator=(const AssemblerX8632 &) = delete;
......
......@@ -948,10 +948,6 @@ inline void AssemblerX86Base<Machine>::emitOperandSizeOverride() {
} // end of namespace X86Internal
namespace X8632 {
using Immediate = ::Ice::X86Internal::Immediate;
using Label = ::Ice::X86Internal::Label;
} // end of namespace X8632
} // end of namespace Ice
#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 @@
//===----------------------------------------------------------------------===//
///
/// \file
/// This file declares the InstX8632 and OperandX8632 classes and
/// their subclasses. This represents the machine instructions and
/// operands used for x86-32 code selection.
/// This file used to house all the X8632 instructions. Subzero has been
/// modified to use templates for X86 instructions, so all those definitions are
/// 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
#define SUBZERO_SRC_ICEINSTX8632_H
#include "IceAssemblerX8632.h"
#include "IceConditionCodesX8632.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceInstX8632.def"
#include "IceInstX86Base.h"
#include "IceOperand.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
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 =
llvm::array_lengthof(TableTypeX8632Attributes);
const uint32_t MachineTraits<TargetX8632>::X86_STACK_ALIGNMENT_BYTES = 16;
const char *MachineTraits<TargetX8632>::TargetName = "X8632";
} // end of namespace X86Internal
......
......@@ -6,9 +6,10 @@
// 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
......@@ -19,15 +20,22 @@
#include "IceDefs.h"
#include "IceInst.h"
#include "IceInstX8632.def"
#include "IceOperand.h"
#include "IceRegistersX8632.h"
#include "IceTargetLoweringX8632.def"
#include "IceTargetLowering.h"
namespace Ice {
class TargetX8632;
namespace X8632 {
class AssemblerX8632;
} // end of namespace X8632
namespace X86Internal {
template <class Machine> struct Insts;
template <class Machine> struct MachineTraits;
template <> struct MachineTraits<TargetX8632> {
......@@ -56,7 +64,7 @@ template <> struct MachineTraits<TargetX8632> {
class Operand {
public:
Operand(const Operand &other)
: length_(other.length_), fixup_(other.fixup_) {
: fixup_(other.fixup_), length_(other.length_) {
memmove(&encoding_[0], &other.encoding_[0], other.length_);
}
......@@ -98,7 +106,7 @@ template <> struct MachineTraits<TargetX8632> {
AssemblerFixup *fixup() const { return fixup_; }
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) {
assert((mod & ~3) == 0);
......@@ -128,20 +136,20 @@ template <> struct MachineTraits<TargetX8632> {
void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; }
private:
uint8_t length_;
uint8_t encoding_[6];
AssemblerFixup *fixup_;
uint8_t encoding_[6];
uint8_t length_;
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 {
assert(index >= 0 && index < length_);
return encoding_[index];
}
// Returns whether or not this operand is really the given register in
// disguise. Used from the assembler to generate better encodings.
/// Returns whether or not this operand is really the given register in
/// disguise. Used from the assembler to generate better encodings.
bool IsRegister(GPRRegister reg) const {
return ((encoding_[0] & 0xF8) ==
0xC0) // Addressing mode is register only.
......@@ -205,8 +213,8 @@ template <> struct MachineTraits<TargetX8632> {
}
}
// AbsoluteTag is a special tag used by clients to create an absolute
// Address.
/// AbsoluteTag is a special tag used by clients to create an absolute
/// Address.
enum AbsoluteTag { ABSOLUTE };
Address(AbsoluteTag, const uintptr_t Addr) {
......@@ -255,27 +263,182 @@ template <> struct MachineTraits<TargetX8632> {
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;
// The number of bits in a byte
/// The number of bits in a byte
static const uint32_t X86_CHAR_BIT = 8;
// 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
// operator(T const&, T const&) which requires this member to have an address.
/// 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
/// operator(T const&, T const&) which requires this member to have an
/// address.
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;
// The number of different NOP instructions
/// The number of different NOP instructions
static const uint32_t X86_NUM_NOP_VARIANTS = 5;
// Value is in bytes. Return Value adjusted to the next highest multiple
// of the stack alignment.
/// Value is in bytes. Return Value adjusted to the next highest multiple
/// of the stack alignment.
static uint32_t applyStackAlignment(uint32_t Value) {
return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
}
// Return the type which the elements of the vector have in the X86
// representation of the vector.
/// Return the type which the elements of the vector have in the X86
/// representation of the vector.
static Type getInVectorElementType(Type Ty) {
assert(isVectorType(Ty));
size_t Index = static_cast<size_t>(Ty);
......@@ -287,51 +450,54 @@ template <> struct MachineTraits<TargetX8632> {
// Note: The following data structures are defined in
// IceTargetLoweringX8632.cpp.
// The following table summarizes the logic for lowering the fcmp
// instruction. There is one table entry for each of the 16 conditions.
//
// The first four columns describe the case when the operands are
// floating point scalar values. A comment in lowerFcmp() describes the
// lowering template. In the most general case, there is a compare
// followed by two conditional branches, because some fcmp conditions
// don't map to a single x86 conditional branch. However, in many cases
// it is possible to swap the operands in the comparison and have a
// single conditional branch. Since it's quite tedious to validate the
// table by hand, good execution tests are helpful.
//
// The last two columns describe the case when the operands are vectors
// of floating point values. For most fcmp conditions, there is a clear
// mapping to a single x86 cmpps instruction variant. Some fcmp
// conditions require special code to handle and these are marked in the
// table with a Cmpps_Invalid predicate.
/// The following table summarizes the logic for lowering the fcmp
/// instruction. There is one table entry for each of the 16 conditions.
///
/// The first four columns describe the case when the operands are floating
/// point scalar values. A comment in lowerFcmp() describes the lowering
/// template. In the most general case, there is a compare followed by two
/// conditional branches, because some fcmp conditions don't map to a single
/// x86 conditional branch. However, in many cases it is possible to swap the
/// operands in the comparison and have a single conditional branch. Since
/// it's quite tedious to validate the table by hand, good execution tests are
/// helpful.
///
/// The last two columns describe the case when the operands are vectors of
/// floating point values. For most fcmp conditions, there is a clear mapping
/// to a single x86 cmpps instruction variant. Some fcmp conditions require
/// special code to handle and these are marked in the table with a
/// Cmpps_Invalid predicate.
/// {@
static const struct TableFcmpType {
uint32_t Default;
bool SwapScalarOperands;
CondX86::BrCond C1, C2;
Cond::BrCond C1, C2;
bool SwapVectorOperands;
CondX86::CmppsCond Predicate;
Cond::CmppsCond Predicate;
} TableFcmp[];
static const size_t TableFcmpSize;
/// @}
// 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
// x86 conditional branch instruction.
static const struct TableIcmp32Type {
CondX86::BrCond Mapping;
} TableIcmp32[];
/// 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
/// x86 conditional branch instruction.
/// {@
static const struct TableIcmp32Type { Cond::BrCond Mapping; } TableIcmp32[];
static const size_t TableIcmp32Size;
/// @}
// 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
// conditional branches are needed. For the other conditions, three separate
// conditional branches are needed.
/// 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
/// conditional branches are needed. For the other conditions, three separate
/// conditional branches are needed.
/// {@
static const struct TableIcmp64Type {
CondX86::BrCond C1, C2, C3;
Cond::BrCond C1, C2, C3;
} TableIcmp64[];
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);
assert(Index < TableIcmp32Size);
return TableIcmp32[Index].Mapping;
......@@ -341,6 +507,190 @@ template <> struct MachineTraits<TargetX8632> {
Type InVectorElementType;
} TableTypeX8632Attributes[];
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
......
......@@ -183,7 +183,7 @@ protected:
void lowerSwitch(const InstSwitch *Inst) override;
void lowerUnreachable(const InstUnreachable *Inst) override;
void lowerOther(const Inst *Instr) override;
void lowerRMW(const InstX8632FakeRMW *RMW);
void lowerRMW(const typename Traits::Insts::FakeRMW *RMW);
void prelowerPhis() override;
void lowerPhiAssignments(CfgNode *Node,
const AssignList &Assignments) override;
......@@ -234,7 +234,7 @@ protected:
/// Turn a pointer operand into a memory operand that can be
/// 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.
OperandX8632Mem *formMemoryOperand(Operand *Ptr, Type Ty,
typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty,
bool DoLegalize = true);
Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
......@@ -253,99 +253,99 @@ protected:
int32_t RegNum = Variable::NoRegister);
/// Return a memory operand corresponding to a stack allocated Variable.
OperandX8632Mem *getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
uint32_t Offset = 0);
typename Traits::X86OperandMem *
getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0);
void makeRandomRegisterPermutation(
llvm::SmallVectorImpl<int32_t> &Permutation,
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
/// with minimal syntactic overhead, so that the lowering code can
/// look as close to assembly as practical.
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) {
Context.insert(InstX8632AdcRMW::create(Func, DestSrc0, Src1));
void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1));
}
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) {
Context.insert(InstX8632AddRMW::create(Func, DestSrc0, Src1));
void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::AddRMW::create(Func, DestSrc0, Src1));
}
void _adjust_stack(int32_t Amount) {
Context.insert(InstX8632AdjustStack::create(
Context.insert(Traits::Insts::AdjustStack::create(
Func, Amount, getPhysicalRegister(Traits::RegisterSet::Reg_esp)));
}
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) {
Context.insert(InstX8632Addss::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Addss::create(Func, Dest, 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) {
Context.insert(InstX8632AndRMW::create(Func, DestSrc0, Src1));
void _and_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::AndRMW::create(Func, DestSrc0, 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,
CfgNode *TargetFalse) {
Context.insert(
InstX8632Br::create(Func, TargetTrue, TargetFalse, Condition));
Traits::Insts::Br::create(Func, TargetTrue, TargetFalse, Condition));
}
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) {
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) {
Context.insert(InstX8632Br::create(Func, Label, Condition));
void _br(typename Traits::Cond::BrCond Condition,
typename Traits::Insts::Label *Label) {
Context.insert(Traits::Insts::Br::create(Func, Label, Condition));
}
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) {
Context.insert(InstX8632Bsr::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Bsr::create(Func, Dest, Src0));
}
void _bswap(Variable *SrcDest) {
Context.insert(InstX8632Bswap::create(Func, SrcDest));
Context.insert(Traits::Insts::Bswap::create(Func, SrcDest));
}
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,
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) {
Context.insert(InstX8632Icmp::create(Func, Src0, Src1));
Context.insert(Traits::Insts::Icmp::create(Func, Src0, Src1));
}
void _cmpps(Variable *Dest, Operand *Src0,
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,
bool Locked) {
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.
Context.insert(
InstFakeDef::create(Func, Eax, llvm::dyn_cast<Variable>(DestOrAddr)));
_set_dest_nonkillable();
Context.insert(InstFakeUse::create(Func, Eax));
}
void _cmpxchg8b(OperandX8632Mem *Addr, Variable *Edx, Variable *Eax,
Variable *Ecx, Variable *Ebx, bool Locked) {
Context.insert(
InstX8632Cmpxchg8b::create(Func, Addr, Edx, Eax, Ecx, Ebx, Locked));
void _cmpxchg8b(typename Traits::X86OperandMem *Addr, Variable *Edx,
Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked) {
Context.insert(Traits::Insts::Cmpxchg8b::create(Func, Addr, Edx, Eax, Ecx,
Ebx, Locked));
// Mark edx, and eax as possibly modified by cmpxchg8b.
Context.insert(InstFakeDef::create(Func, Edx));
_set_dest_nonkillable();
......@@ -354,38 +354,41 @@ protected:
_set_dest_nonkillable();
Context.insert(InstFakeUse::create(Func, Eax));
}
void _cvt(Variable *Dest, Operand *Src0, InstX8632Cvt::CvtVariant Variant) {
Context.insert(InstX8632Cvt::create(Func, Dest, Src0, Variant));
void _cvt(Variable *Dest, Operand *Src0,
typename Traits::Insts::Cvt::CvtVariant Variant) {
Context.insert(Traits::Insts::Cvt::create(Func, Dest, Src0, Variant));
}
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) {
Context.insert(InstX8632Divps::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Divps::create(Func, Dest, 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) {
Context.insert(InstX8632Fstp::create(Func, Dest));
Context.insert(Traits::Insts::Fstp::create(Func, Dest));
}
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) {
Context.insert(InstX8632Imul::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Imul::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Jmp::create(Func, Target));
Context.insert(Traits::Insts::Jmp::create(Func, Target));
}
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,
/// marked as infinite register allocation weight, and returned
/// through the in/out Dest argument.
......@@ -393,175 +396,175 @@ protected:
int32_t RegNum = Variable::NoRegister) {
if (Dest == nullptr)
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) {
Inst *NewInst = InstX8632Mov::create(Func, Dest, Src0);
Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0);
NewInst->setDestNonKillable();
Context.insert(NewInst);
}
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) {
Context.insert(InstX8632Movp::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Movp::create(Func, Dest, 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) {
Context.insert(InstX8632MovssRegs::create(Func, Dest, Src0));
Context.insert(Traits::Insts::MovssRegs::create(Func, Dest, 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) {
Context.insert(InstX8632Movzx::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Movzx::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Mulps::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Mulps::create(Func, Dest, 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) {
Context.insert(InstX8632Neg::create(Func, SrcDest));
Context.insert(Traits::Insts::Neg::create(Func, SrcDest));
}
void _nop(SizeT Variant) {
Context.insert(InstX8632Nop::create(Func, Variant));
Context.insert(Traits::Insts::Nop::create(Func, Variant));
}
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) {
Context.insert(InstX8632OrRMW::create(Func, DestSrc0, Src1));
void _or_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::OrRMW::create(Func, DestSrc0, Src1));
}
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) {
Context.insert(InstX8632Pand::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Pand::create(Func, Dest, 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) {
Context.insert(InstX8632Pblendvb::create(Func, Dest, Src0, Src1));
Context.insert(Traits::Insts::Pblendvb::create(Func, Dest, Src0, Src1));
}
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) {
Context.insert(InstX8632Pcmpgt::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Pcmpgt::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Pinsr::create(Func, Dest, Src0, Src1));
Context.insert(Traits::Insts::Pinsr::create(Func, Dest, Src0, Src1));
}
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) {
Context.insert(InstX8632Pmuludq::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Pmuludq::create(Func, Dest, Src0));
}
void _pop(Variable *Dest) {
Context.insert(InstX8632Pop::create(Func, Dest));
Context.insert(Traits::Insts::Pop::create(Func, Dest));
}
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) {
Context.insert(InstX8632Pshufd::create(Func, Dest, Src0, Src1));
Context.insert(Traits::Insts::Pshufd::create(Func, Dest, Src0, Src1));
}
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) {
Context.insert(InstX8632Psra::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Psra::create(Func, Dest, 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) {
Context.insert(InstX8632Psub::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Psub::create(Func, Dest, 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) {
Context.insert(InstX8632Pxor::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Pxor::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Rol::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Rol::create(Func, Dest, 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) {
Context.insert(InstX8632Sbb::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Sbb::create(Func, Dest, Src0));
}
void _sbb_rmw(OperandX8632Mem *DestSrc0, Operand *Src1) {
Context.insert(InstX8632SbbRMW::create(Func, DestSrc0, Src1));
void _sbb_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::SbbRMW::create(Func, DestSrc0, Src1));
}
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) {
Context.insert(InstX8632Shl::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Shl::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Shr::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Shr::create(Func, Dest, Src0));
}
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) {
Context.insert(InstX8632Shufps::create(Func, Dest, Src0, Src1));
Context.insert(Traits::Insts::Shufps::create(Func, Dest, Src0, Src1));
}
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) {
Context.insert(InstX8632Store::create(Func, Value, Mem));
void _store(Operand *Value, typename Traits::X86Operand *Mem) {
Context.insert(Traits::Insts::Store::create(Func, Value, Mem));
}
void _storep(Variable *Value, OperandX8632Mem *Mem) {
Context.insert(InstX8632StoreP::create(Func, Value, Mem));
void _storep(Variable *Value, typename Traits::X86OperandMem *Mem) {
Context.insert(Traits::Insts::StoreP::create(Func, Value, Mem));
}
void _storeq(Variable *Value, OperandX8632Mem *Mem) {
Context.insert(InstX8632StoreQ::create(Func, Value, Mem));
void _storeq(Variable *Value, typename Traits::X86OperandMem *Mem) {
Context.insert(Traits::Insts::StoreQ::create(Func, Value, Mem));
}
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) {
Context.insert(InstX8632SubRMW::create(Func, DestSrc0, Src1));
void _sub_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::SubRMW::create(Func, DestSrc0, Src1));
}
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) {
Context.insert(InstX8632Subss::create(Func, Dest, Src0));
Context.insert(Traits::Insts::Subss::create(Func, Dest, Src0));
}
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) {
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) {
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).
// Model that update with a FakeDef followed by a FakeUse.
Context.insert(
......@@ -570,7 +573,7 @@ protected:
Context.insert(InstFakeUse::create(Func, 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
// FakeDef/FakeUse.
Context.insert(
......@@ -579,10 +582,10 @@ protected:
Context.insert(InstFakeUse::create(Func, Src));
}
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) {
Context.insert(InstX8632XorRMW::create(Func, DestSrc0, Src1));
void _xor_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) {
Context.insert(Traits::Insts::XorRMW::create(Func, DestSrc0, Src1));
}
void _set_dest_nonkillable() {
Context.getLastInserted()->setDestNonKillable();
......@@ -600,13 +603,12 @@ protected:
llvm::SmallBitVector ScratchRegs;
llvm::SmallBitVector RegsUsed;
VarList PhysicalRegisters[IceType_NUM];
static IceString RegNames[];
/// Randomize a given immediate operand
Operand *randomizeOrPoolImmediate(Constant *Immediate,
int32_t RegNum = Variable::NoRegister);
OperandX8632Mem *
randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
typename Traits::X86OperandMem *
randomizeOrPoolImmediate(typename Traits::X86OperandMem *MemOperand,
int32_t RegNum = Variable::NoRegister);
bool RandomizationPoolingPaused = false;
......
......@@ -23,20 +23,16 @@
#include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceGlobalInits.h"
#include "IceInstX8632.h"
#include "IceLiveness.h"
#include "IceOperand.h"
#include "IceRegistersX8632.h"
#include "IceTargetLoweringX8632.def"
#include "IceTargetLoweringX8632.h"
#include "IceUtils.h"
#include "llvm/Support/MathExtras.h"
namespace Ice {
namespace X86Internal {
/// A helper class to ease the settings of RandomizationPoolingPause
/// to disable constant blinding or pooling for some translation phases.
/// A helper class to ease the settings of RandomizationPoolingPause to disable
/// constant blinding or pooling for some translation phases.
class BoolFlagSaver {
BoolFlagSaver() = delete;
BoolFlagSaver(const BoolFlagSaver &) = delete;
......@@ -85,8 +81,7 @@ public:
};
/// Currently the actual enum values are not used (other than CK_None), but we
/// go
/// ahead and produce them anyway for symmetry with the
/// go ahead and produce them anyway for symmetry with the
/// BoolFoldingProducerKind.
enum BoolFoldingConsumerKind { CK_None, CK_Br, CK_Select, CK_Sext, CK_Zext };
......@@ -163,12 +158,11 @@ BoolFolding<MachineTraits>::getConsumerKind(const Inst *Instr) {
return CK_None;
}
/// Returns true if the producing instruction has a "complex" lowering
/// sequence. This generally means that its lowering sequence requires
/// more than one conditional branch, namely 64-bit integer compares
/// and some floating-point compares. When this is true, and there is
/// more than one consumer, we prefer to disable the folding
/// optimization because it minimizes branches.
/// Returns true if the producing instruction has a "complex" lowering sequence.
/// This generally means that its lowering sequence requires more than one
/// conditional branch, namely 64-bit integer compares and some floating-point
/// compares. When this is true, and there is more than one consumer, we prefer
/// to disable the folding optimization because it minimizes branches.
template <class MachineTraits>
bool BoolFolding<MachineTraits>::hasComplexLowering(const Inst *Instr) {
switch (getProducerKind(Instr)) {
......@@ -226,10 +220,10 @@ void BoolFolding<MachineTraits>::init(CfgNode *Node) {
setInvalid(I.first);
continue;
}
// Mark as "dead" rather than outright deleting. This is so that
// other peephole style optimizations during or before lowering
// have access to this instruction in undeleted form. See for
// example tryOptimizedCmpxchgCmpBr().
// Mark as "dead" rather than outright deleting. This is so that other
// peephole style optimizations during or before lowering have access to
// this instruction in undeleted form. See for example
// tryOptimizedCmpxchgCmpBr().
I.second.Instr->setDead();
}
}
......@@ -283,24 +277,18 @@ TargetX86Base<Machine>::TargetX86Base(Cfg *Func)
TargetInstructionSet::X86InstructionSet_Begin) +
Traits::InstructionSet::Begin);
}
// TODO: Don't initialize IntegerRegisters and friends every time.
// Instead, initialize in some sort of static initializer for the
// class.
// TODO: Don't initialize IntegerRegisters and friends every time. Instead,
// initialize in some sort of static initializer for the class.
llvm::SmallBitVector IntegerRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector IntegerRegistersI8(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector FloatRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector VectorRegisters(Traits::RegisterSet::Reg_NUM);
llvm::SmallBitVector InvalidRegisters(Traits::RegisterSet::Reg_NUM);
ScratchRegs.resize(Traits::RegisterSet::Reg_NUM);
#define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
frameptr, isI8, isInt, isFP) \
IntegerRegisters[Traits::RegisterSet::val] = isInt; \
IntegerRegistersI8[Traits::RegisterSet::val] = isI8; \
FloatRegisters[Traits::RegisterSet::val] = isFP; \
VectorRegisters[Traits::RegisterSet::val] = isFP; \
ScratchRegs[Traits::RegisterSet::val] = scratch;
REGX8632_TABLE;
#undef X
Traits::initRegisterSet(&IntegerRegisters, &IntegerRegistersI8,
&FloatRegisters, &VectorRegisters, &ScratchRegs);
TypeToRegisterSet[IceType_void] = InvalidRegisters;
TypeToRegisterSet[IceType_i1] = IntegerRegistersI8;
TypeToRegisterSet[IceType_i8] = IntegerRegistersI8;
......@@ -348,19 +336,18 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
// Argument lowering
Func->doArgLowering();
// Target lowering. This requires liveness analysis for some parts
// of the lowering decisions, such as compare/branch fusing. If
// non-lightweight liveness analysis is used, the instructions need
// to be renumbered first. TODO: This renumbering should only be
// necessary if we're actually calculating live intervals, which we
// only do for register allocation.
// Target lowering. This requires liveness analysis for some parts of the
// lowering decisions, such as compare/branch fusing. If non-lightweight
// liveness analysis is used, the instructions need to be renumbered first
// TODO: This renumbering should only be necessary if we're actually
// calculating live intervals, which we only do for register allocation.
Func->renumberInstructions();
if (Func->hasError())
return;
// TODO: It should be sufficient to use the fastest liveness
// calculation, i.e. livenessLightweight(). However, for some
// reason that slows down the rest of the translation. Investigate.
// TODO: It should be sufficient to use the fastest liveness calculation, i.e.
// livenessLightweight(). However, for some reason that slows down the rest
// of the translation. Investigate.
Func->liveness(Liveness_Basic);
if (Func->hasError())
return;
......@@ -376,19 +363,19 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
return;
Func->dump("After x86 codegen");
// Register allocation. This requires instruction renumbering and
// full liveness analysis.
// Register allocation. This requires instruction renumbering and full
// liveness analysis.
Func->renumberInstructions();
if (Func->hasError())
return;
Func->liveness(Liveness_Intervals);
if (Func->hasError())
return;
// Validate the live range computations. The expensive validation
// call is deliberately only made when assertions are enabled.
// Validate the live range computations. The expensive validation call is
// deliberately only made when assertions are enabled.
assert(Func->validateLiveness());
// The post-codegen dump is done here, after liveness analysis and
// associated cleanup, to make the dump cleaner and more useful.
// The post-codegen dump is done here, after liveness analysis and associated
// cleanup, to make the dump cleaner and more useful.
Func->dump("After initial x8632 codegen");
Func->getVMetadata()->init(VMK_All);
regAlloc(RAK_Global);
......@@ -397,9 +384,9 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
Func->dump("After linear scan regalloc");
if (Ctx->getFlags().getPhiEdgeSplit()) {
// We need to pause constant blinding or pooling during advanced
// phi lowering, unless the lowering assignment has a physical
// register for the dest Variable.
// We need to pause constant blinding or pooling during advanced phi
// lowering, unless the lowering assignment has a physical register for the
// dest Variable.
{
BoolFlagSaver B(RandomizationPoolingPaused, true);
Func->advancedPhiLowering();
......@@ -416,11 +403,10 @@ template <class Machine> void TargetX86Base<Machine>::translateO2() {
Func->contractEmptyNodes();
Func->reorderNodes();
// Branch optimization. This needs to be done just before code
// emission. In particular, no transformations that insert or
// reorder CfgNodes should be done after branch optimization. We go
// ahead and do it before nop insertion to reduce the amount of work
// needed for searching for opportunities.
// Branch optimization. This needs to be done just before code emission. In
// particular, no transformations that insert or reorder CfgNodes should be
// done after branch optimization. We go ahead and do it before nop insertion
// to reduce the amount of work needed for searching for opportunities.
Func->doBranchOpt();
Func->dump("After branch optimization");
......@@ -468,8 +454,7 @@ template <class Machine> void TargetX86Base<Machine>::translateOm1() {
bool canRMW(const InstArithmetic *Arith) {
Type Ty = Arith->getDest()->getType();
// X86 vector instructions write to a register and have no RMW
// option.
// X86 vector instructions write to a register and have no RMW option.
if (isVectorType(Ty))
return false;
bool isI64 = Ty == IceType_i64;
......@@ -496,11 +481,14 @@ bool canRMW(const InstArithmetic *Arith) {
}
}
template <class Machine>
bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
if (A == B)
return true;
if (auto *MemA = llvm::dyn_cast<OperandX8632Mem>(A)) {
if (auto *MemB = llvm::dyn_cast<OperandX8632Mem>(B)) {
if (auto *MemA = llvm::dyn_cast<
typename TargetX86Base<Machine>::Traits::X86OperandMem>(A)) {
if (auto *MemB = llvm::dyn_cast<
typename TargetX86Base<Machine>::Traits::X86OperandMem>(B)) {
return MemA->getBase() == MemB->getBase() &&
MemA->getOffset() == MemB->getOffset() &&
MemA->getIndex() == MemB->getIndex() &&
......@@ -565,7 +553,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() {
// still trigger, resulting in two loads and one store, which is
// worse than the original one load and one store. However, this is
// probably rare, and caching probably keeps it just as fast.
if (!isSameMemAddressOperand(Load->getSourceAddress(),
if (!isSameMemAddressOperand<Machine>(Load->getSourceAddress(),
Store->getAddr()))
continue;
Operand *ArithSrcFromLoad = Arith->getSrc(0);
......@@ -593,7 +581,7 @@ template <class Machine> void TargetX86Base<Machine>::findRMW() {
Store->setRmwBeacon(Beacon);
InstFakeDef *BeaconDef = InstFakeDef::create(Func, Beacon);
Node->getInsts().insert(I3, BeaconDef);
InstX8632FakeRMW *RMW = InstX8632FakeRMW::create(
auto *RMW = Traits::Insts::FakeRMW::create(
Func, ArithSrcOther, Store->getAddr(), Beacon, Arith->getOp());
Node->getInsts().insert(I3, RMW);
}
......@@ -721,22 +709,13 @@ template <class Machine> void TargetX86Base<Machine>::doLoadOpt() {
template <class Machine>
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 false;
}
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) {
if (Ty == IceType_void)
Ty = IceType_i32;
......@@ -760,30 +739,7 @@ Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) {
template <class Machine>
IceString TargetX86Base<Machine>::getRegName(SizeT RegNum, Type Ty) const {
assert(RegNum < Traits::RegisterSet::Reg_NUM);
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];
}
return Traits::getRegName(RegNum, Ty);
}
template <class Machine>
......@@ -884,17 +840,16 @@ void TargetX86Base<Machine>::finishArgumentLowering(Variable *Arg,
InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
if (Arg->hasReg()) {
assert(Ty != IceType_i64);
OperandX8632Mem *Mem = OperandX8632Mem::create(
typename Traits::X86OperandMem *Mem = Traits::X86OperandMem::create(
Func, Ty, FramePtr, Ctx->getConstantInt32(Arg->getStackOffset()));
if (isVectorType(Arg->getType())) {
_movp(Arg, Mem);
} else {
_mov(Arg, Mem);
}
// This argument-copying instruction uses an explicit
// OperandX8632Mem operand instead of a Variable, so its
// fill-from-stack operation has to be tracked separately for
// statistics.
// This argument-copying instruction uses an explicit Traits::X86OperandMem
// operand instead of a Variable, so its fill-from-stack operation has to be
// tracked separately for statistics.
Ctx->statsUpdateFills();
}
}
......@@ -965,7 +920,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) {
// that stack slot.
std::function<bool(Variable *)> TargetVarHook =
[&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());
if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
VariablesLinkedToSpillSlots.push_back(Var);
......@@ -1069,7 +1025,8 @@ template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) {
// Assign stack offsets to variables that have been linked to spilled
// variables.
for (Variable *Var : VariablesLinkedToSpillSlots) {
Variable *Linked = (llvm::cast<SpillVariable>(Var))->getLinkedTo();
Variable *Linked =
(llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
Var->setStackOffset(Linked->getStackOffset());
}
this->HasComputedFrame = true;
......@@ -1106,7 +1063,7 @@ template <class Machine> void TargetX86Base<Machine>::addEpilog(CfgNode *Node) {
InstList &Insts = Node->getInsts();
InstList::reverse_iterator RI, E;
for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
if (llvm::isa<InstX8632Ret>(*RI))
if (llvm::isa<typename Traits::Insts::Ret>(*RI))
break;
}
if (RI == E)
......@@ -1216,8 +1173,8 @@ Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) {
Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue())));
return legalize(ConstInt);
}
if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) {
OperandX8632Mem *MemOperand = OperandX8632Mem::create(
if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Operand)) {
auto *MemOperand = Traits::X86OperandMem::create(
Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(),
Mem->getShift(), Mem->getSegmentRegister());
// Test if we should randomize or pool the offset, if so randomize it or
......@@ -1245,7 +1202,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
// check if we need to blind/pool the constant
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();
if (Offset == nullptr) {
Offset = Ctx->getConstantInt32(4);
......@@ -1259,7 +1216,7 @@ Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(),
SymOffset->getSuppressMangling());
}
OperandX8632Mem *MemOperand = OperandX8632Mem::create(
auto *MemOperand = Traits::X86OperandMem::create(
Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(),
Mem->getShift(), Mem->getSegmentRegister());
// Test if the Offset is an eligible i32 constants for randomization and
......@@ -1275,32 +1232,7 @@ template <class Machine>
llvm::SmallBitVector
TargetX86Base<Machine>::getRegisterSet(RegSetMask Include,
RegSetMask Exclude) const {
llvm::SmallBitVector Registers(Traits::RegisterSet::Reg_NUM);
#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;
return Traits::getRegisterSet(Include, Exclude);
}
template <class Machine>
......@@ -1423,17 +1355,20 @@ bool TargetX86Base<Machine>::optimizeScalarMul(Variable *Dest, Operand *Src0,
Constant *Zero = Ctx->getConstantZero(IceType_i32);
for (uint32_t i = 0; i < Count9; ++i) {
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();
}
for (uint32_t i = 0; i < Count5; ++i) {
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();
}
for (uint32_t i = 0; i < Count3; ++i) {
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();
}
if (Count2) {
......@@ -1601,7 +1536,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20);
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_2, Src0Lo);
_mov(T_3, Src0Hi);
......@@ -1636,7 +1572,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20);
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_2, Src0Lo);
_mov(T_3, Src0Hi);
......@@ -1671,7 +1608,8 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
Constant *BitTest = Ctx->getConstantInt32(0x20);
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_2, Src0Lo);
_mov(T_3, Src0Hi);
......@@ -1709,7 +1647,7 @@ void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
if (isVectorType(Dest->getType())) {
// TODO: Trap on integer divide and integer modulo by zero.
// 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);
switch (Inst->getOp()) {
case InstArithmetic::_num:
......@@ -2208,7 +2146,8 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) {
Variable *esp =
Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp);
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());
}
}
......@@ -2305,7 +2244,7 @@ void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) {
CallTarget = CallTargetVar;
}
}
Inst *NewCall = InstX8632Call::create(Func, ReturnReg, CallTarget);
Inst *NewCall = Traits::Insts::Call::create(Func, ReturnReg, CallTarget);
Context.insert(NewCall);
if (NeedSandboxing)
_bundle_unlock();
......@@ -2532,7 +2471,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
// t1 = cvt Src0RM; Dest = t1
Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Float2float);
_cvt(T, Src0RM, Traits::Insts::Cvt::Float2float);
_mov(Dest, T);
break;
}
......@@ -2541,10 +2480,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
assert(Dest->getType() == IceType_v4i32 &&
Inst->getSrc(0)->getType() == IceType_v4f32);
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);
Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Tps2dq);
_cvt(T, Src0RM, Traits::Insts::Cvt::Tps2dq);
_movp(Dest, T);
} else if (Dest->getType() == IceType_i64) {
// Use a helper for converting floating-point values to 64-bit
......@@ -2567,7 +2506,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32);
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
if (Dest->getType() == IceType_i1)
_and(T_2, Ctx->getConstantInt1(1));
......@@ -2606,7 +2545,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
Variable *T_1 = makeReg(IceType_i32);
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
if (Dest->getType() == IceType_i1)
_and(T_2, Ctx->getConstantInt1(1));
......@@ -2618,10 +2557,10 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
assert(Dest->getType() == IceType_v4f32 &&
Inst->getSrc(0)->getType() == IceType_v4i32);
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);
Variable *T = makeReg(Dest->getType());
_cvt(T, Src0RM, InstX8632Cvt::Dq2ps);
_cvt(T, Src0RM, Traits::Insts::Cvt::Dq2ps);
_movp(Dest, T);
} else if (Inst->getSrc(0)->getType() == IceType_i64) {
// Use a helper for x86-32.
......@@ -2645,7 +2584,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
_mov(T_1, Src0RM);
else
_movsx(T_1, Src0RM);
_cvt(T_2, T_1, InstX8632Cvt::Si2ss);
_cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
_mov(Dest, T_2);
}
break;
......@@ -2686,7 +2625,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
_mov(T_1, Src0RM);
else
_movzx(T_1, Src0RM);
_cvt(T_2, T_1, InstX8632Cvt::Si2ss);
_cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
_mov(Dest, T_2);
}
break;
......@@ -2728,8 +2667,8 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
Variable *T = nullptr;
// TODO: Should be able to force a spill setup by calling legalize() with
// Legal_Mem and not Legal_Reg or Legal_Imm.
SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(SrcType);
typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<typename Traits::SpillVariable>(SrcType);
SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero);
......@@ -2748,14 +2687,17 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// a_hi.i32 = t_hi.i32
Operand *SpillLo, *SpillHi;
if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(IceType_f64);
typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<typename Traits::SpillVariable>(
IceType_f64);
SpillVar->setLinkedTo(Src0Var);
Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero);
_movq(Spill, Src0RM);
SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low);
SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High);
SpillLo = Traits::VariableSplit::create(Func, Spill,
Traits::VariableSplit::Low);
SpillHi = Traits::VariableSplit::create(Func, Spill,
Traits::VariableSplit::High);
} else {
SpillLo = loOperand(Src0RM);
SpillHi = hiOperand(Src0RM);
......@@ -2774,7 +2716,7 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
case IceType_f64: {
Src0 = legalize(Src0);
assert(Src0->getType() == IceType_i64);
if (llvm::isa<OperandX8632Mem>(Src0)) {
if (llvm::isa<typename Traits::X86OperandMem>(Src0)) {
Variable *T = Func->template makeVariable(Dest->getType());
_movq(T, Src0);
_movq(Dest, T);
......@@ -2787,17 +2729,18 @@ void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
// t_hi.i32 = b_hi.i32
// hi(s.f64) = t_hi.i32
// a.f64 = s.f64
SpillVariable *SpillVar =
Func->template makeVariable<SpillVariable>(IceType_f64);
typename Traits::SpillVariable *SpillVar =
Func->template makeVariable<typename Traits::SpillVariable>(
IceType_f64);
SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar;
Spill->setWeight(RegWeight::Zero);
Variable *T_Lo = nullptr, *T_Hi = nullptr;
VariableSplit *SpillLo =
VariableSplit::create(Func, Spill, VariableSplit::Low);
VariableSplit *SpillHi =
VariableSplit::create(Func, Spill, VariableSplit::High);
typename Traits::VariableSplit *SpillLo = Traits::VariableSplit::create(
Func, Spill, Traits::VariableSplit::Low);
typename Traits::VariableSplit *SpillHi = Traits::VariableSplit::create(
Func, Spill, Traits::VariableSplit::High);
_mov(T_Lo, loOperand(Src0));
// Technically, the Spill is defined after the _store happens, but
// SpillLo is considered a "use" of Spill so define Spill before it
......@@ -2897,7 +2840,7 @@ void TargetX86Base<Machine>::lowerExtractElement(
// Compute the location of the element in memory.
unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
OperandX8632Mem *Loc =
typename Traits::X86OperandMem *Loc =
getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
_mov(ExtractedElementR, Loc);
}
......@@ -2943,7 +2886,7 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) {
} else {
Operand *Src0RM = legalize(Src0, 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);
switch (Condition) {
......@@ -3018,7 +2961,8 @@ void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) {
Constant *Default = Ctx->getConstantInt32(Traits::TableFcmp[Index].Default);
_mov(Dest, Default);
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);
if (HasC2) {
_br(Traits::TableFcmp[Index].C2, Label);
......@@ -3091,13 +3035,13 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
llvm_unreachable("unexpected condition");
break;
case InstIcmp::Eq: {
if (llvm::isa<OperandX8632Mem>(Src1RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM);
_pcmpeq(T, Src1RM);
} break;
case InstIcmp::Ne: {
if (llvm::isa<OperandX8632Mem>(Src1RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM);
_pcmpeq(T, Src1RM);
......@@ -3106,7 +3050,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
} break;
case InstIcmp::Ugt:
case InstIcmp::Sgt: {
if (llvm::isa<OperandX8632Mem>(Src1RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM);
_pcmpgt(T, Src1RM);
......@@ -3114,7 +3058,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
case InstIcmp::Uge:
case InstIcmp::Sge: {
// !(Src1RM > Src0RM)
if (llvm::isa<OperandX8632Mem>(Src0RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM);
_movp(T, Src1RM);
_pcmpgt(T, Src0RM);
......@@ -3123,7 +3067,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
} break;
case InstIcmp::Ult:
case InstIcmp::Slt: {
if (llvm::isa<OperandX8632Mem>(Src0RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src0RM))
Src0RM = legalizeToVar(Src0RM);
_movp(T, Src1RM);
_pcmpgt(T, Src0RM);
......@@ -3131,7 +3075,7 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
case InstIcmp::Ule:
case InstIcmp::Sle: {
// !(Src0RM > Src1RM)
if (llvm::isa<OperandX8632Mem>(Src1RM))
if (llvm::isa<typename Traits::X86OperandMem>(Src1RM))
Src1RM = legalizeToVar(Src1RM);
_movp(T, Src0RM);
_pcmpgt(T, Src1RM);
......@@ -3156,8 +3100,10 @@ void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
Operand *Src1HiRI = legalize(hiOperand(Src1), Legal_Reg | Legal_Imm);
Constant *Zero = Ctx->getConstantZero(IceType_i32);
Constant *One = Ctx->getConstantInt32(1);
InstX8632Label *LabelFalse = InstX8632Label::create(Func, this);
InstX8632Label *LabelTrue = InstX8632Label::create(Func, this);
typename Traits::Insts::Label *LabelFalse =
Traits::Insts::Label::create(Func, this);
typename Traits::Insts::Label *LabelTrue =
Traits::Insts::Label::create(Func, this);
_mov(Dest, One);
_cmp(Src0HiRM, Src1HiRI);
if (Traits::TableIcmp64[Index].C1 != Traits::Cond::Br_None)
......@@ -3293,7 +3239,7 @@ void TargetX86Base<Machine>::lowerInsertElement(const InstInsertElement *Inst) {
// Compute the location of the position to insert in memory.
unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
OperandX8632Mem *Loc =
typename Traits::X86OperandMem *Loc =
getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
_store(legalizeToVar(ElementToInsertNotLegalized), Loc);
......@@ -3383,7 +3329,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
// can't happen anyway, since this is x86-32 and integer arithmetic only
// happens on 32-bit quantities.
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);
// Then cast the bits back out of the XMM register to the i64 Dest.
InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T);
......@@ -3433,7 +3380,8 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value);
lowerCast(Cast);
// Then store XMM w/ a movq.
OperandX8632Mem *Addr = formMemoryOperand(Ptr, IceType_f64);
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, IceType_f64);
_storeq(T, Addr);
_mfence();
return;
......@@ -3535,7 +3483,7 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
// 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.
if (isVectorType(Ty)) {
if (llvm::isa<OperandX8632Mem>(Src))
if (llvm::isa<typename Traits::X86OperandMem>(Src))
Src = legalizeToVar(Src);
} else {
Src = legalizeToVar(Src);
......@@ -3590,9 +3538,9 @@ void TargetX86Base<Machine>::lowerIntrinsicCall(
case Intrinsics::NaClReadTP: {
if (Ctx->getFlags().getUseSandboxing()) {
Constant *Zero = Ctx->getConstantZero(IceType_i32);
Operand *Src =
OperandX8632Mem::create(Func, IceType_i32, nullptr, Zero, nullptr, 0,
OperandX8632Mem::SegReg_GS);
Operand *Src = Traits::X86OperandMem::create(
Func, IceType_i32, nullptr, Zero, nullptr, 0,
Traits::X86OperandMem::SegReg_GS);
Variable *Dest = Instr->getDest();
Variable *T = nullptr;
_mov(T, Src);
......@@ -3655,7 +3603,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev,
_mov(T_edx, hiOperand(Expected));
_mov(T_ebx, loOperand(Desired));
_mov(T_ecx, hiOperand(Desired));
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Expected->getType());
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Expected->getType());
const bool Locked = true;
_cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
Variable *DestLo = llvm::cast<Variable>(loOperand(DestPrev));
......@@ -3666,7 +3615,8 @@ void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev,
}
Variable *T_eax = makeReg(Expected->getType(), Traits::RegisterSet::Reg_eax);
_mov(T_eax, Expected);
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Expected->getType());
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Expected->getType());
Variable *DesiredReg = legalizeToVar(Desired);
const bool Locked = true;
_cmpxchg(Addr, T_eax, DesiredReg, Locked);
......@@ -3768,7 +3718,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = &TargetX86Base<Machine>::_adc;
break;
}
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType());
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
const bool Locked = true;
Variable *T = nullptr;
_mov(T, Val);
......@@ -3783,7 +3734,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = &TargetX86Base<Machine>::_sbb;
break;
}
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType());
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
const bool Locked = true;
Variable *T = nullptr;
_mov(T, Val);
......@@ -3821,7 +3773,8 @@ void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
Op_Hi = nullptr;
break;
}
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType());
typename Traits::X86OperandMem *Addr =
formMemoryOperand(Ptr, Dest->getType());
Variable *T = nullptr;
_mov(T, Val);
_xchg(Addr, T);
......@@ -3869,12 +3822,13 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
if (Ty == IceType_i64) {
Variable *T_edx = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
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_edx, hiOperand(Addr));
Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
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;
if (!IsXchg8b) {
Context.insert(Label);
......@@ -3916,10 +3870,11 @@ void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
_mov(DestHi, T_edx);
return;
}
OperandX8632Mem *Addr = formMemoryOperand(Ptr, Ty);
typename Traits::X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
Variable *T_eax = makeReg(Ty, Traits::RegisterSet::Reg_eax);
_mov(T_eax, Addr);
InstX8632Label *Label = InstX8632Label::create(Func, this);
typename Traits::Insts::Label *Label =
Traits::Insts::Label::create(Func, this);
Context.insert(Label);
// We want to pick a different register for T than Eax, so don't use
// _mov(T == nullptr, T_eax).
......@@ -4260,11 +4215,11 @@ void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base,
template <class Machine>
void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) {
// A Load instruction can be treated the same as an Assign
// instruction, after the source operand is transformed into an
// OperandX8632Mem operand. Note that the address mode
// optimization already creates an OperandX8632Mem operand, so it
// doesn't need another level of transformation.
// A Load instruction can be treated the same as an Assign instruction, after
// the source operand is transformed into an Traits::X86OperandMem operand.
// Note that the address mode optimization already creates an
// Traits::X86OperandMem operand, so it doesn't need another level of
// transformation.
Variable *DestLoad = Load->getDest();
Type Ty = DestLoad->getType();
Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
......@@ -4279,19 +4234,19 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() {
Variable *Index = nullptr;
uint16_t Shift = 0;
int32_t Offset = 0; // TODO: make Constant
// Vanilla ICE load instructions should not use the segment registers,
// and computeAddressOpt only works at the level of Variables and Constants,
// not other OperandX8632Mem, so there should be no mention of segment
// Vanilla ICE load instructions should not use the segment registers, and
// computeAddressOpt only works at the level of Variables and Constants, not
// other Traits::X86OperandMem, so there should be no mention of segment
// registers there either.
const OperandX8632Mem::SegmentRegisters SegmentReg =
OperandX8632Mem::DefaultSegment;
const typename Traits::X86OperandMem::SegmentRegisters SegmentReg =
Traits::X86OperandMem::DefaultSegment;
Variable *Base = llvm::dyn_cast<Variable>(Addr);
computeAddressOpt(Func, Inst, Base, Index, Shift, Offset);
if (Base && Addr != Base) {
Inst->setDeleted();
Constant *OffsetOp = Ctx->getConstantInt32(Offset);
Addr = OperandX8632Mem::create(Func, Dest->getType(), Base, OffsetOp, Index,
Shift, SegmentReg);
Addr = Traits::X86OperandMem::create(Func, Dest->getType(), Base, OffsetOp,
Index, Shift, SegmentReg);
Context.insert(InstLoad::create(Func, Dest, Addr));
}
}
......@@ -4438,7 +4393,8 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
// The cmov instruction doesn't allow 8-bit or FP operands, so
// we need explicit control flow.
// 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);
_mov(Dest, SrcT);
_br(Cond, Label);
......@@ -4453,7 +4409,7 @@ void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
// mov t, SrcT; cmov_!cond t, SrcF; mov dest, t
if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) {
std::swap(SrcT, SrcF);
Cond = InstX8632::getOppositeCondition(Cond);
Cond = InstX86Base<Machine>::getOppositeCondition(Cond);
}
if (DestTy == IceType_i64) {
// Set the low portion.
......@@ -4488,15 +4444,18 @@ template <class Machine>
void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
Operand *Value = Inst->getData();
Operand *Addr = Inst->getAddr();
OperandX8632Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
typename Traits::X86OperandMem *NewAddr =
formMemoryOperand(Addr, Value->getType());
Type Ty = NewAddr->getType();
if (Ty == IceType_i64) {
Value = legalize(Value);
Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
_store(ValueHi, llvm::cast<OperandX8632Mem>(hiOperand(NewAddr)));
_store(ValueLo, llvm::cast<OperandX8632Mem>(loOperand(NewAddr)));
_store(ValueHi,
llvm::cast<typename Traits::X86OperandMem>(hiOperand(NewAddr)));
_store(ValueLo,
llvm::cast<typename Traits::X86OperandMem>(loOperand(NewAddr)));
} else if (isVectorType(Ty)) {
_storep(legalizeToVar(Value), NewAddr);
} else {
......@@ -4513,18 +4472,18 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptStore() {
uint16_t Shift = 0;
int32_t Offset = 0; // TODO: make Constant
Variable *Base = llvm::dyn_cast<Variable>(Addr);
// Vanilla ICE store instructions should not use the segment registers,
// and computeAddressOpt only works at the level of Variables and Constants,
// not other OperandX8632Mem, so there should be no mention of segment
// Vanilla ICE store instructions should not use the segment registers, and
// computeAddressOpt only works at the level of Variables and Constants, not
// other Traits::X86OperandMem, so there should be no mention of segment
// registers there either.
const OperandX8632Mem::SegmentRegisters SegmentReg =
OperandX8632Mem::DefaultSegment;
const typename Traits::X86OperandMem::SegmentRegisters SegmentReg =
Traits::X86OperandMem::DefaultSegment;
computeAddressOpt(Func, Inst, Base, Index, Shift, Offset);
if (Base && Addr != Base) {
Inst->setDeleted();
Constant *OffsetOp = Ctx->getConstantInt32(Offset);
Addr = OperandX8632Mem::create(Func, Data->getType(), Base, OffsetOp, Index,
Shift, SegmentReg);
Addr = Traits::X86OperandMem::create(Func, Data->getType(), Base, OffsetOp,
Index, Shift, SegmentReg);
InstStore *NewStore = InstStore::create(Func, Data, Addr);
if (Inst->getDest())
NewStore->setRmwBeacon(Inst->getRmwBeacon());
......@@ -4552,7 +4511,8 @@ void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) {
for (SizeT I = 0; I < NumCases; ++I) {
Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
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);
_br(Traits::Cond::Br_ne, Label);
_cmp(Src0Hi, ValueHi);
......@@ -4639,7 +4599,8 @@ void TargetX86Base<Machine>::lowerUnreachable(
}
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
// instruction, then it must end in the modified Store instruction
// that follows. This means that the original Store instruction is
......@@ -4651,12 +4612,14 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) {
return;
Operand *Src = RMW->getData();
Type Ty = Src->getType();
OperandX8632Mem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
if (Ty == IceType_i64) {
Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
OperandX8632Mem *AddrLo = llvm::cast<OperandX8632Mem>(loOperand(Addr));
OperandX8632Mem *AddrHi = llvm::cast<OperandX8632Mem>(hiOperand(Addr));
typename Traits::X86OperandMem *AddrLo =
llvm::cast<typename Traits::X86OperandMem>(loOperand(Addr));
typename Traits::X86OperandMem *AddrHi =
llvm::cast<typename Traits::X86OperandMem>(hiOperand(Addr));
switch (RMW->getOp()) {
default:
// TODO(stichnot): Implement other arithmetic operators.
......@@ -4715,7 +4678,8 @@ void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *RMW) {
template <class Machine>
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);
} else {
TargetLowering::lowerOther(Instr);
......@@ -4991,7 +4955,7 @@ Variable *TargetX86Base<Machine>::makeVectorOfFabsMask(Type Ty,
}
template <class Machine>
OperandX8632Mem *
typename TargetX86Base<Machine>::Traits::X86OperandMem *
TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
uint32_t Offset) {
// Ensure that Loc is a stack slot.
......@@ -5005,7 +4969,7 @@ TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
Variable *Loc = makeReg(PointerType);
_lea(Loc, Slot);
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
......@@ -5037,7 +5001,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
// or in ecx.)
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
// that the Base and Index components are in physical registers.
Variable *Base = Mem->getBase();
......@@ -5051,9 +5015,9 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
RegIndex = legalizeToVar(Index);
}
if (Base != RegBase || Index != RegIndex) {
Mem =
OperandX8632Mem::create(Func, Ty, RegBase, Mem->getOffset(), RegIndex,
Mem->getShift(), Mem->getSegmentRegister());
Mem = Traits::X86OperandMem::create(Func, Ty, RegBase, Mem->getOffset(),
RegIndex, Mem->getShift(),
Mem->getSegmentRegister());
}
// For all Memory Operands, we do randomization/pooling here
......@@ -5103,7 +5067,7 @@ Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
llvm::cast<Constant>(From)->emitPoolLabel(StrBuf);
llvm::cast<Constant>(From)->setShouldBePooled(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;
if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
......@@ -5162,13 +5126,13 @@ Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0,
}
template <class Machine>
OperandX8632Mem *TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd,
Type Ty,
typename TargetX86Base<Machine>::Traits::X86OperandMem *
TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd, Type Ty,
bool DoLegalize) {
OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Opnd);
// It may be the case that address mode optimization already creates
// an OperandX8632Mem, so in that case it wouldn't need another level
// of transformation.
auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Opnd);
// It may be the case that address mode optimization already creates an
// Traits::X86OperandMem, so in that case it wouldn't need another level of
// transformation.
if (!Mem) {
Variable *Base = llvm::dyn_cast<Variable>(Opnd);
Constant *Offset = llvm::dyn_cast<Constant>(Opnd);
......@@ -5188,11 +5152,11 @@ OperandX8632Mem *TargetX86Base<Machine>::formMemoryOperand(Operand *Opnd,
assert(llvm::isa<ConstantInteger32>(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
// or do randomization/pooling.
return llvm::cast<OperandX8632Mem>(
return llvm::cast<typename Traits::X86OperandMem>(
DoLegalize ? legalize(Mem) : randomizeOrPoolImmediate(Mem));
}
......@@ -5218,68 +5182,8 @@ template <class Machine>
void TargetX86Base<Machine>::makeRandomRegisterPermutation(
llvm::SmallVectorImpl<int32_t> &Permutation,
const llvm::SmallBitVector &ExcludeRegisters) const {
// TODO(stichnot): Declaring Permutation this way loses type/size
// information. Fix this in conjunction with the caller-side TODO.
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";
}
}
Traits::makeRandomRegisterPermutation(Ctx, Func, Permutation,
ExcludeRegisters);
}
template <class Machine>
......@@ -5350,8 +5254,8 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
uint32_t Cookie = Ctx->getRandomizationCookie();
_mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value));
Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie);
_lea(Reg,
OperandX8632Mem::create(Func, IceType_i32, Reg, Offset, nullptr, 0));
_lea(Reg, Traits::X86OperandMem::create(Func, IceType_i32, Reg, Offset,
nullptr, 0));
// make sure liveness analysis won't kill this variable, otherwise a
// liveness
// assertion will be triggered.
......@@ -5384,8 +5288,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
const bool SuppressMangling = true;
Constant *Symbol =
Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling);
OperandX8632Mem *MemOperand =
OperandX8632Mem::create(Func, Immediate->getType(), nullptr, Symbol);
typename Traits::X86OperandMem *MemOperand =
Traits::X86OperandMem::create(Func, Immediate->getType(), nullptr,
Symbol);
_mov(Reg, MemOperand);
return Reg;
}
......@@ -5396,9 +5301,9 @@ Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
}
template <class Machine>
OperandX8632Mem *
TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
int32_t RegNum) {
typename TargetX86Base<Machine>::Traits::X86OperandMem *
TargetX86Base<Machine>::randomizeOrPoolImmediate(
typename Traits::X86OperandMem *MemOperand, int32_t RegNum) {
assert(MemOperand);
if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
RandomizationPoolingPaused == true) {
......@@ -5432,8 +5337,9 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
Constant *Mask2 =
Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie);
OperandX8632Mem *TempMemOperand = OperandX8632Mem::create(
Func, MemOperand->getType(), MemOperand->getBase(), Mask1);
typename Traits::X86OperandMem *TempMemOperand =
Traits::X86OperandMem::create(Func, MemOperand->getType(),
MemOperand->getBase(), Mask1);
// If we have already assigned a physical register, we must come from
// advancedPhiLowering()=>lowerAssign(). In this case we should reuse
// the assigned register as this assignment is that start of its use-def
......@@ -5447,9 +5353,11 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
if (RegNum != Variable::NoRegister)
_set_dest_nonkillable();
OperandX8632Mem *NewMemOperand = OperandX8632Mem::create(
Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(),
MemOperand->getShift(), MemOperand->getSegmentRegister());
typename Traits::X86OperandMem *NewMemOperand =
Traits::X86OperandMem::create(Func, MemOperand->getType(), RegTemp,
Mask2, MemOperand->getIndex(),
MemOperand->getShift(),
MemOperand->getSegmentRegister());
// Label this memory operand as randomize, so we won't randomize it
// again in case we call legalize() mutiple times on this memory
......@@ -5484,22 +5392,25 @@ TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
bool SuppressMangling = true;
Constant *Symbol = Ctx->getConstantSym(SymOffset, Label_stream.str(),
SuppressMangling);
OperandX8632Mem *SymbolOperand = OperandX8632Mem::create(
typename Traits::X86OperandMem *SymbolOperand =
Traits::X86OperandMem::create(
Func, MemOperand->getOffset()->getType(), nullptr, Symbol);
_mov(RegTemp, SymbolOperand);
// 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
// base variable, we won't need this lea instruction.
if (MemOperand->getBase()) {
OperandX8632Mem *CalculateOperand = OperandX8632Mem::create(
typename Traits::X86OperandMem *CalculateOperand =
Traits::X86OperandMem::create(
Func, MemOperand->getType(), MemOperand->getBase(), nullptr,
RegTemp, 0, MemOperand->getSegmentRegister());
_lea(RegTemp, CalculateOperand);
_set_dest_nonkillable();
}
OperandX8632Mem *NewMemOperand = OperandX8632Mem::create(
Func, MemOperand->getType(), RegTemp, nullptr,
MemOperand->getIndex(), MemOperand->getShift(),
typename Traits::X86OperandMem *NewMemOperand =
Traits::X86OperandMem::create(Func, MemOperand->getType(), RegTemp,
nullptr, MemOperand->getIndex(),
MemOperand->getShift(),
MemOperand->getSegmentRegister());
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