| Index: src/IceTargetLoweringX86BaseImpl.h
|
| diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX86BaseImpl.h
|
| similarity index 88%
|
| copy from src/IceTargetLoweringX8632.cpp
|
| copy to src/IceTargetLoweringX86BaseImpl.h
|
| index c1ba40429a8f788b78ed600e2a8f731d1f3ac83b..b787c03b4572e9d166ee96b3d8cf90cf63cf5e23 100644
|
| --- a/src/IceTargetLoweringX8632.cpp
|
| +++ b/src/IceTargetLoweringX86BaseImpl.h
|
| @@ -1,4 +1,4 @@
|
| -//===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 lowering -----------===//
|
| +//===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- C++ -*-==//
|
| //
|
| // The Subzero Code Generator
|
| //
|
| @@ -7,12 +7,15 @@
|
| //
|
| //===----------------------------------------------------------------------===//
|
| //
|
| -// This file implements the TargetLoweringX8632 class, which
|
| +// This file implements the TargetLoweringX86Base class, which
|
| // consists almost entirely of the lowering sequence for each
|
| // high-level instruction.
|
| //
|
| //===----------------------------------------------------------------------===//
|
|
|
| +#ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
|
| +#define SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
|
| +
|
| #include "llvm/Support/MathExtras.h"
|
|
|
| #include "IceCfg.h"
|
| @@ -30,221 +33,7 @@
|
| #include "IceUtils.h"
|
|
|
| namespace Ice {
|
| -
|
| -namespace {
|
| -
|
| -// 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.
|
| -const struct TableFcmp_ {
|
| - uint32_t Default;
|
| - bool SwapScalarOperands;
|
| - CondX86::BrCond C1, C2;
|
| - bool SwapVectorOperands;
|
| - CondX86::CmppsCond Predicate;
|
| -} TableFcmp[] = {
|
| -#define X(val, dflt, swapS, C1, C2, swapV, pred) \
|
| - { dflt, swapS, CondX86::C1, CondX86::C2, swapV, CondX86::pred } \
|
| - ,
|
| - FCMPX8632_TABLE
|
| -#undef X
|
| -};
|
| -const size_t TableFcmpSize = llvm::array_lengthof(TableFcmp);
|
| -
|
| -// 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.
|
| -
|
| -const struct TableIcmp32_ {
|
| - CondX86::BrCond Mapping;
|
| -} TableIcmp32[] = {
|
| -#define X(val, C_32, C1_64, C2_64, C3_64) \
|
| - { CondX86::C_32 } \
|
| - ,
|
| - ICMPX8632_TABLE
|
| -#undef X
|
| -};
|
| -const size_t TableIcmp32Size = llvm::array_lengthof(TableIcmp32);
|
| -
|
| -// 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.
|
| -const struct TableIcmp64_ {
|
| - CondX86::BrCond C1, C2, C3;
|
| -} TableIcmp64[] = {
|
| -#define X(val, C_32, C1_64, C2_64, C3_64) \
|
| - { CondX86::C1_64, CondX86::C2_64, CondX86::C3_64 } \
|
| - ,
|
| - ICMPX8632_TABLE
|
| -#undef X
|
| -};
|
| -const size_t TableIcmp64Size = llvm::array_lengthof(TableIcmp64);
|
| -
|
| -CondX86::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) {
|
| - size_t Index = static_cast<size_t>(Cond);
|
| - assert(Index < TableIcmp32Size);
|
| - return TableIcmp32[Index].Mapping;
|
| -}
|
| -
|
| -const struct TableTypeX8632Attributes_ {
|
| - Type InVectorElementType;
|
| -} TableTypeX8632Attributes[] = {
|
| -#define X(tag, elementty, cvt, sdss, pack, width, fld) \
|
| - { elementty } \
|
| - ,
|
| - ICETYPEX8632_TABLE
|
| -#undef X
|
| -};
|
| -const size_t TableTypeX8632AttributesSize =
|
| - llvm::array_lengthof(TableTypeX8632Attributes);
|
| -
|
| -// Return the type which the elements of the vector have in the X86
|
| -// representation of the vector.
|
| -Type getInVectorElementType(Type Ty) {
|
| - assert(isVectorType(Ty));
|
| - size_t Index = static_cast<size_t>(Ty);
|
| - (void)Index;
|
| - assert(Index < TableTypeX8632AttributesSize);
|
| - return TableTypeX8632Attributes[Ty].InVectorElementType;
|
| -}
|
| -
|
| -// The maximum number of arguments to pass in XMM registers
|
| -const uint32_t X86_MAX_XMM_ARGS = 4;
|
| -// The number of bits in a byte
|
| -const uint32_t X86_CHAR_BIT = 8;
|
| -// Stack alignment
|
| -const uint32_t X86_STACK_ALIGNMENT_BYTES = 16;
|
| -// Size of the return address on the stack
|
| -const uint32_t X86_RET_IP_SIZE_BYTES = 4;
|
| -// The number of different NOP instructions
|
| -const uint32_t X86_NUM_NOP_VARIANTS = 5;
|
| -
|
| -// Value is in bytes. Return Value adjusted to the next highest multiple
|
| -// of the stack alignment.
|
| -uint32_t applyStackAlignment(uint32_t Value) {
|
| - return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
|
| -}
|
| -
|
| -// In some cases, there are x-macros tables for both high-level and
|
| -// low-level instructions/operands that use the same enum key value.
|
| -// The tables are kept separate to maintain a proper separation
|
| -// between abstraction layers. There is a risk that the tables could
|
| -// get out of sync if enum values are reordered or if entries are
|
| -// added or deleted. The following dummy namespaces use
|
| -// static_asserts to ensure everything is kept in sync.
|
| -
|
| -// Validate the enum values in FCMPX8632_TABLE.
|
| -namespace dummy1 {
|
| -// Define a temporary set of enum values based on low-level table
|
| -// entries.
|
| -enum _tmp_enum {
|
| -#define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val,
|
| - FCMPX8632_TABLE
|
| -#undef X
|
| - _num
|
| -};
|
| -// Define a set of constants based on high-level table entries.
|
| -#define X(tag, str) static const int _table1_##tag = InstFcmp::tag;
|
| -ICEINSTFCMP_TABLE
|
| -#undef X
|
| -// Define a set of constants based on low-level table entries, and
|
| -// ensure the table entry keys are consistent.
|
| -#define X(val, dflt, swapS, C1, C2, swapV, pred) \
|
| - static const int _table2_##val = _tmp_##val; \
|
| - static_assert( \
|
| - _table1_##val == _table2_##val, \
|
| - "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE");
|
| -FCMPX8632_TABLE
|
| -#undef X
|
| -// Repeat the static asserts with respect to the high-level table
|
| -// entries in case the high-level table has extra entries.
|
| -#define X(tag, str) \
|
| - static_assert( \
|
| - _table1_##tag == _table2_##tag, \
|
| - "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE");
|
| -ICEINSTFCMP_TABLE
|
| -#undef X
|
| -} // end of namespace dummy1
|
| -
|
| -// Validate the enum values in ICMPX8632_TABLE.
|
| -namespace dummy2 {
|
| -// Define a temporary set of enum values based on low-level table
|
| -// entries.
|
| -enum _tmp_enum {
|
| -#define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val,
|
| - ICMPX8632_TABLE
|
| -#undef X
|
| - _num
|
| -};
|
| -// Define a set of constants based on high-level table entries.
|
| -#define X(tag, str) static const int _table1_##tag = InstIcmp::tag;
|
| -ICEINSTICMP_TABLE
|
| -#undef X
|
| -// Define a set of constants based on low-level table entries, and
|
| -// ensure the table entry keys are consistent.
|
| -#define X(val, C_32, C1_64, C2_64, C3_64) \
|
| - static const int _table2_##val = _tmp_##val; \
|
| - static_assert( \
|
| - _table1_##val == _table2_##val, \
|
| - "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE");
|
| -ICMPX8632_TABLE
|
| -#undef X
|
| -// Repeat the static asserts with respect to the high-level table
|
| -// entries in case the high-level table has extra entries.
|
| -#define X(tag, str) \
|
| - static_assert( \
|
| - _table1_##tag == _table2_##tag, \
|
| - "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE");
|
| -ICEINSTICMP_TABLE
|
| -#undef X
|
| -} // end of namespace dummy2
|
| -
|
| -// Validate the enum values in ICETYPEX8632_TABLE.
|
| -namespace dummy3 {
|
| -// Define a temporary set of enum values based on low-level table
|
| -// entries.
|
| -enum _tmp_enum {
|
| -#define X(tag, elementty, cvt, sdss, pack, width, fld) _tmp_##tag,
|
| - ICETYPEX8632_TABLE
|
| -#undef X
|
| - _num
|
| -};
|
| -// Define a set of constants based on high-level table entries.
|
| -#define X(tag, size, align, elts, elty, str) \
|
| - static const int _table1_##tag = tag;
|
| -ICETYPE_TABLE
|
| -#undef X
|
| -// Define a set of constants based on low-level table entries, and
|
| -// ensure the table entry keys are consistent.
|
| -#define X(tag, elementty, cvt, sdss, pack, width, fld) \
|
| - static const int _table2_##tag = _tmp_##tag; \
|
| - static_assert(_table1_##tag == _table2_##tag, \
|
| - "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE");
|
| -ICETYPEX8632_TABLE
|
| -#undef X
|
| -// Repeat the static asserts with respect to the high-level table
|
| -// entries in case the high-level table has extra entries.
|
| -#define X(tag, size, align, elts, elty, str) \
|
| - static_assert(_table1_##tag == _table2_##tag, \
|
| - "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE");
|
| -ICETYPE_TABLE
|
| -#undef X
|
| -} // end of namespace dummy3
|
| +namespace X86Internal {
|
|
|
| // A helper class to ease the settings of RandomizationPoolingPause
|
| // to disable constant blinding or pooling for some translation phases.
|
| @@ -262,13 +51,76 @@ private:
|
| bool &Flag;
|
| };
|
|
|
| -} // end of anonymous namespace
|
| +template <class MachineTraits> class BoolFoldingEntry {
|
| + BoolFoldingEntry(const BoolFoldingEntry &) = delete;
|
| +
|
| +public:
|
| + BoolFoldingEntry() = default;
|
| + explicit BoolFoldingEntry(Inst *I);
|
| + BoolFoldingEntry &operator=(const BoolFoldingEntry &) = default;
|
| + // Instr is the instruction producing the i1-type variable of interest.
|
| + Inst *Instr = nullptr;
|
| + // IsComplex is the cached result of BoolFolding::hasComplexLowering(Instr).
|
| + bool IsComplex = false;
|
| + // IsLiveOut is initialized conservatively to true, and is set to false when
|
| + // we encounter an instruction that ends Var's live range. We disable the
|
| + // folding optimization when Var is live beyond this basic block. Note that
|
| + // if liveness analysis is not performed (e.g. in Om1 mode), IsLiveOut will
|
| + // always be true and the folding optimization will never be performed.
|
| + bool IsLiveOut = true;
|
| + // NumUses counts the number of times Var is used as a source operand in the
|
| + // basic block. If IsComplex is true and there is more than one use of Var,
|
| + // then the folding optimization is disabled for Var.
|
| + uint32_t NumUses = 0;
|
| +};
|
| +
|
| +template <class MachineTraits> class BoolFolding {
|
| +public:
|
| + enum BoolFoldingProducerKind {
|
| + PK_None,
|
| + PK_Icmp32,
|
| + PK_Icmp64,
|
| + PK_Fcmp,
|
| + PK_Trunc
|
| + };
|
|
|
| -BoolFoldingEntry::BoolFoldingEntry(Inst *I)
|
| - : Instr(I), IsComplex(BoolFolding::hasComplexLowering(I)) {}
|
| + // Currently the actual enum values are not used (other than CK_None), but we
|
| + // go
|
| + // ahead and produce them anyway for symmetry with the
|
| + // BoolFoldingProducerKind.
|
| + enum BoolFoldingConsumerKind { CK_None, CK_Br, CK_Select, CK_Sext, CK_Zext };
|
| +
|
| +private:
|
| + BoolFolding(const BoolFolding &) = delete;
|
| + BoolFolding &operator=(const BoolFolding &) = delete;
|
|
|
| -BoolFolding::BoolFoldingProducerKind
|
| -BoolFolding::getProducerKind(const Inst *Instr) {
|
| +public:
|
| + BoolFolding() = default;
|
| + static BoolFoldingProducerKind getProducerKind(const Inst *Instr);
|
| + static BoolFoldingConsumerKind getConsumerKind(const Inst *Instr);
|
| + static bool hasComplexLowering(const Inst *Instr);
|
| + void init(CfgNode *Node);
|
| + const Inst *getProducerFor(const Operand *Opnd) const;
|
| + void dump(const Cfg *Func) const;
|
| +
|
| +private:
|
| + // Returns true if Producers contains a valid entry for the given VarNum.
|
| + bool containsValid(SizeT VarNum) const {
|
| + auto Element = Producers.find(VarNum);
|
| + return Element != Producers.end() && Element->second.Instr != nullptr;
|
| + }
|
| + void setInvalid(SizeT VarNum) { Producers[VarNum].Instr = nullptr; }
|
| + // Producers maps Variable::Number to a BoolFoldingEntry.
|
| + std::unordered_map<SizeT, BoolFoldingEntry<MachineTraits>> Producers;
|
| +};
|
| +
|
| +template <class MachineTraits>
|
| +BoolFoldingEntry<MachineTraits>::BoolFoldingEntry(Inst *I)
|
| + : Instr(I), IsComplex(BoolFolding<MachineTraits>::hasComplexLowering(I)) {}
|
| +
|
| +template <class MachineTraits>
|
| +typename BoolFolding<MachineTraits>::BoolFoldingProducerKind
|
| +BoolFolding<MachineTraits>::getProducerKind(const Inst *Instr) {
|
| if (llvm::isa<InstIcmp>(Instr)) {
|
| if (Instr->getSrc(0)->getType() != IceType_i64)
|
| return PK_Icmp32;
|
| @@ -289,8 +141,9 @@ BoolFolding::getProducerKind(const Inst *Instr) {
|
| return PK_None;
|
| }
|
|
|
| -BoolFolding::BoolFoldingConsumerKind
|
| -BoolFolding::getConsumerKind(const Inst *Instr) {
|
| +template <class MachineTraits>
|
| +typename BoolFolding<MachineTraits>::BoolFoldingConsumerKind
|
| +BoolFolding<MachineTraits>::getConsumerKind(const Inst *Instr) {
|
| if (llvm::isa<InstBr>(Instr))
|
| return CK_Br;
|
| if (llvm::isa<InstSelect>(Instr))
|
| @@ -316,19 +169,21 @@ BoolFolding::getConsumerKind(const Inst *Instr) {
|
| // 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.
|
| -bool BoolFolding::hasComplexLowering(const Inst *Instr) {
|
| +template <class MachineTraits>
|
| +bool BoolFolding<MachineTraits>::hasComplexLowering(const Inst *Instr) {
|
| switch (getProducerKind(Instr)) {
|
| default:
|
| return false;
|
| case PK_Icmp64:
|
| return true;
|
| case PK_Fcmp:
|
| - return TableFcmp[llvm::cast<InstFcmp>(Instr)->getCondition()].C2 !=
|
| - CondX86::Br_None;
|
| + return MachineTraits::TableFcmp[llvm::cast<InstFcmp>(Instr)->getCondition()]
|
| + .C2 != CondX86::Br_None;
|
| }
|
| }
|
|
|
| -void BoolFolding::init(CfgNode *Node) {
|
| +template <class MachineTraits>
|
| +void BoolFolding<MachineTraits>::init(CfgNode *Node) {
|
| Producers.clear();
|
| for (Inst &Instr : Node->getInsts()) {
|
| // Check whether Instr is a valid producer.
|
| @@ -337,7 +192,7 @@ void BoolFolding::init(CfgNode *Node) {
|
| && Var // only instructions with an actual dest var
|
| && Var->getType() == IceType_i1 // only bool-type dest vars
|
| && getProducerKind(&Instr) != PK_None) { // white-listed instructions
|
| - Producers[Var->getIndex()] = BoolFoldingEntry(&Instr);
|
| + Producers[Var->getIndex()] = BoolFoldingEntry<MachineTraits>(&Instr);
|
| }
|
| // Check each src variable against the map.
|
| for (SizeT I = 0; I < Instr.getSrcSize(); ++I) {
|
| @@ -379,7 +234,9 @@ void BoolFolding::init(CfgNode *Node) {
|
| }
|
| }
|
|
|
| -const Inst *BoolFolding::getProducerFor(const Operand *Opnd) const {
|
| +template <class MachineTraits>
|
| +const Inst *
|
| +BoolFolding<MachineTraits>::getProducerFor(const Operand *Opnd) const {
|
| auto *Var = llvm::dyn_cast<const Variable>(Opnd);
|
| if (Var == nullptr)
|
| return nullptr;
|
| @@ -390,7 +247,8 @@ const Inst *BoolFolding::getProducerFor(const Operand *Opnd) const {
|
| return Element->second.Instr;
|
| }
|
|
|
| -void BoolFolding::dump(const Cfg *Func) const {
|
| +template <class MachineTraits>
|
| +void BoolFolding<MachineTraits>::dump(const Cfg *Func) const {
|
| if (!ALLOW_DUMP || !Func->isVerbose(IceV_Folding))
|
| return;
|
| OstreamLocker L(Func->getContext());
|
| @@ -404,22 +262,26 @@ void BoolFolding::dump(const Cfg *Func) const {
|
| }
|
| }
|
|
|
| -void TargetX8632::initNodeForLowering(CfgNode *Node) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::initNodeForLowering(CfgNode *Node) {
|
| FoldingInfo.init(Node);
|
| FoldingInfo.dump(Func);
|
| }
|
|
|
| -TargetX8632::TargetX8632(Cfg *Func) : TargetLowering(Func) {
|
| - static_assert((X86InstructionSet::End - X86InstructionSet::Begin) ==
|
| - (TargetInstructionSet::X86InstructionSet_End -
|
| - TargetInstructionSet::X86InstructionSet_Begin),
|
| - "X86InstructionSet range different from TargetInstructionSet");
|
| +template <class Machine>
|
| +TargetX86Base<Machine>::TargetX86Base(Cfg *Func)
|
| + : Machine(Func) {
|
| + static_assert(
|
| + (Traits::InstructionSet::End - Traits::InstructionSet::Begin) ==
|
| + (TargetInstructionSet::X86InstructionSet_End -
|
| + TargetInstructionSet::X86InstructionSet_Begin),
|
| + "Traits::InstructionSet range different from TargetInstructionSet");
|
| if (Func->getContext()->getFlags().getTargetInstructionSet() !=
|
| TargetInstructionSet::BaseInstructionSet) {
|
| - InstructionSet = static_cast<X86InstructionSet>(
|
| + InstructionSet = static_cast<typename Traits::InstructionSet>(
|
| (Func->getContext()->getFlags().getTargetInstructionSet() -
|
| TargetInstructionSet::X86InstructionSet_Begin) +
|
| - X86InstructionSet::Begin);
|
| + Traits::InstructionSet::Begin);
|
| }
|
| // TODO: Don't initialize IntegerRegisters and friends every time.
|
| // Instead, initialize in some sort of static initializer for the
|
| @@ -456,7 +318,7 @@ TargetX8632::TargetX8632(Cfg *Func) : TargetLowering(Func) {
|
| TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
|
| }
|
|
|
| -void TargetX8632::translateO2() {
|
| +template <class Machine> void TargetX86Base<Machine>::translateO2() {
|
| TimerMarker T(TimerStack::TT_O2, Func);
|
|
|
| if (!Ctx->getFlags().getPhiEdgeSplit()) {
|
| @@ -568,7 +430,7 @@ void TargetX8632::translateO2() {
|
| }
|
| }
|
|
|
| -void TargetX8632::translateOm1() {
|
| +template <class Machine> void TargetX86Base<Machine>::translateOm1() {
|
| TimerMarker T(TimerStack::TT_Om1, Func);
|
|
|
| Func->placePhiLoads();
|
| @@ -605,8 +467,6 @@ void TargetX8632::translateOm1() {
|
| }
|
| }
|
|
|
| -namespace {
|
| -
|
| bool canRMW(const InstArithmetic *Arith) {
|
| Type Ty = Arith->getDest()->getType();
|
| // X86 vector instructions write to a register and have no RMW
|
| @@ -652,9 +512,7 @@ bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
|
| return false;
|
| }
|
|
|
| -} // end of anonymous namespace
|
| -
|
| -void TargetX8632::findRMW() {
|
| +template <class Machine> void TargetX86Base<Machine>::findRMW() {
|
| Func->dump("Before RMW");
|
| OstreamLocker L(Func->getContext());
|
| Ostream &Str = Func->getContext()->getStrDump();
|
| @@ -746,8 +604,6 @@ void TargetX8632::findRMW() {
|
| }
|
| }
|
|
|
| -namespace {
|
| -
|
| // Converts a ConstantInteger32 operand into its constant value, or
|
| // MemoryOrderInvalid if the operand is not a ConstantInteger32.
|
| uint64_t getConstantMemoryOrder(Operand *Opnd) {
|
| @@ -774,9 +630,7 @@ bool canFoldLoadIntoBinaryInst(Operand *LoadSrc, Variable *LoadDest,
|
| return false;
|
| }
|
|
|
| -} // end of anonymous namespace
|
| -
|
| -void TargetX8632::doLoadOpt() {
|
| +template <class Machine> void TargetX86Base<Machine>::doLoadOpt() {
|
| for (CfgNode *Node : Func->getNodes()) {
|
| Context.init(Node);
|
| while (!Context.atEnd()) {
|
| @@ -866,14 +720,16 @@ void TargetX8632::doLoadOpt() {
|
| Func->dump("After load optimization");
|
| }
|
|
|
| -bool TargetX8632::doBranchOpt(Inst *I, const CfgNode *NextNode) {
|
| +template <class Machine>
|
| +bool TargetX86Base<Machine>::doBranchOpt(Inst *I, const CfgNode *NextNode) {
|
| if (InstX8632Br *Br = llvm::dyn_cast<InstX8632Br>(I)) {
|
| return Br->optimizeBranch(NextNode);
|
| }
|
| return false;
|
| }
|
|
|
| -IceString TargetX8632::RegNames[] = {
|
| +template <class Machine>
|
| +IceString TargetX86Base<Machine>::RegNames[] = {
|
| #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
|
| frameptr, isI8, isInt, isFP) \
|
| name,
|
| @@ -881,7 +737,8 @@ IceString TargetX8632::RegNames[] = {
|
| #undef X
|
| };
|
|
|
| -Variable *TargetX8632::getPhysicalRegister(SizeT RegNum, Type Ty) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::getPhysicalRegister(SizeT RegNum, Type Ty) {
|
| if (Ty == IceType_void)
|
| Ty = IceType_i32;
|
| if (PhysicalRegisters[Ty].empty())
|
| @@ -902,7 +759,8 @@ Variable *TargetX8632::getPhysicalRegister(SizeT RegNum, Type Ty) {
|
| return Reg;
|
| }
|
|
|
| -IceString TargetX8632::getRegName(SizeT RegNum, Type Ty) const {
|
| +template <class Machine>
|
| +IceString TargetX86Base<Machine>::getRegName(SizeT RegNum, Type Ty) const {
|
| assert(RegNum < RegX8632::Reg_NUM);
|
| static IceString RegNames8[] = {
|
| #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
|
| @@ -929,7 +787,8 @@ IceString TargetX8632::getRegName(SizeT RegNum, Type Ty) const {
|
| }
|
| }
|
|
|
| -void TargetX8632::emitVariable(const Variable *Var) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emitVariable(const Variable *Var) const {
|
| Ostream &Str = Ctx->getStrEmit();
|
| if (Var->hasReg()) {
|
| Str << "%" << getRegName(Var->getRegNum(), Var->getType());
|
| @@ -947,7 +806,9 @@ void TargetX8632::emitVariable(const Variable *Var) const {
|
| Str << "(%" << getRegName(getFrameOrStackReg(), FrameSPTy) << ")";
|
| }
|
|
|
| -X8632::Address TargetX8632::stackVarToAsmOperand(const Variable *Var) const {
|
| +template <class Machine>
|
| +X8632::Address
|
| +TargetX86Base<Machine>::stackVarToAsmOperand(const Variable *Var) const {
|
| if (Var->hasReg())
|
| llvm_unreachable("Stack Variable has a register assigned");
|
| if (Var->getWeight().isInf()) {
|
| @@ -959,7 +820,7 @@ X8632::Address TargetX8632::stackVarToAsmOperand(const Variable *Var) const {
|
| return X8632::Address(RegX8632::getEncodedGPR(getFrameOrStackReg()), Offset);
|
| }
|
|
|
| -void TargetX8632::lowerArguments() {
|
| +template <class Machine> void TargetX86Base<Machine>::lowerArguments() {
|
| VarList &Args = Func->getArgs();
|
| // The first four arguments of vector type, regardless of their
|
| // position relative to the other arguments in the argument list, are
|
| @@ -969,8 +830,8 @@ void TargetX8632::lowerArguments() {
|
| Context.init(Func->getEntryNode());
|
| Context.setInsertPoint(Context.getCur());
|
|
|
| - for (SizeT I = 0, E = Args.size(); I < E && NumXmmArgs < X86_MAX_XMM_ARGS;
|
| - ++I) {
|
| + for (SizeT I = 0, E = Args.size();
|
| + I < E && NumXmmArgs < Traits::X86_MAX_XMM_ARGS; ++I) {
|
| Variable *Arg = Args[I];
|
| Type Ty = Arg->getType();
|
| if (!isVectorType(Ty))
|
| @@ -1001,9 +862,11 @@ void TargetX8632::lowerArguments() {
|
| // Lo first because of the little-endian architecture. Lastly, this
|
| // function generates an instruction to copy Arg into its assigned
|
| // register if applicable.
|
| -void TargetX8632::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
|
| - size_t BasicFrameOffset,
|
| - size_t &InArgsSizeBytes) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::finishArgumentLowering(Variable *Arg,
|
| + Variable *FramePtr,
|
| + size_t BasicFrameOffset,
|
| + size_t &InArgsSizeBytes) {
|
| Variable *Lo = Arg->getLo();
|
| Variable *Hi = Arg->getHi();
|
| Type Ty = Arg->getType();
|
| @@ -1015,7 +878,7 @@ void TargetX8632::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
|
| return;
|
| }
|
| if (isVectorType(Ty)) {
|
| - InArgsSizeBytes = applyStackAlignment(InArgsSizeBytes);
|
| + InArgsSizeBytes = Traits::applyStackAlignment(InArgsSizeBytes);
|
| }
|
| Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
|
| InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
|
| @@ -1036,9 +899,11 @@ void TargetX8632::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
|
| }
|
| }
|
|
|
| -Type TargetX8632::stackSlotType() { return IceType_i32; }
|
| +template <class Machine> Type TargetX86Base<Machine>::stackSlotType() {
|
| + return IceType_i32;
|
| +}
|
|
|
| -void TargetX8632::addProlog(CfgNode *Node) {
|
| +template <class Machine> void TargetX86Base<Machine>::addProlog(CfgNode *Node) {
|
| // Stack frame layout:
|
| //
|
| // +------------------------+
|
| @@ -1147,11 +1012,11 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
| // the region after the preserved registers and before the spill areas.
|
| // LocalsSlotsPaddingBytes is the amount of padding between the globals
|
| // and locals area if they are separate.
|
| - assert(SpillAreaAlignmentBytes <= X86_STACK_ALIGNMENT_BYTES);
|
| + assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES);
|
| assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
|
| uint32_t SpillAreaPaddingBytes = 0;
|
| uint32_t LocalsSlotsPaddingBytes = 0;
|
| - alignStackSpillAreas(X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
|
| + alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
|
| SpillAreaAlignmentBytes, GlobalsSize,
|
| LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
|
| &LocalsSlotsPaddingBytes);
|
| @@ -1161,8 +1026,10 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
|
|
| // Align esp if necessary.
|
| if (NeedsStackAlignment) {
|
| - uint32_t StackOffset = X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
|
| - uint32_t StackSize = applyStackAlignment(StackOffset + SpillAreaSizeBytes);
|
| + uint32_t StackOffset =
|
| + Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
|
| + uint32_t StackSize =
|
| + Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes);
|
| SpillAreaSizeBytes = StackSize - StackOffset;
|
| }
|
|
|
| @@ -1178,7 +1045,8 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
| // for those that were register-allocated. Args are pushed right to
|
| // left, so Arg[0] is closest to the stack/frame pointer.
|
| Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg());
|
| - size_t BasicFrameOffset = PreservedRegsSizeBytes + X86_RET_IP_SIZE_BYTES;
|
| + size_t BasicFrameOffset =
|
| + PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES;
|
| if (!IsEbpBasedFrame)
|
| BasicFrameOffset += SpillAreaSizeBytes;
|
|
|
| @@ -1187,7 +1055,7 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
| unsigned NumXmmArgs = 0;
|
| for (Variable *Arg : Args) {
|
| // Skip arguments passed in registers.
|
| - if (isVectorType(Arg->getType()) && NumXmmArgs < X86_MAX_XMM_ARGS) {
|
| + if (isVectorType(Arg->getType()) && NumXmmArgs < Traits::X86_MAX_XMM_ARGS) {
|
| ++NumXmmArgs;
|
| continue;
|
| }
|
| @@ -1215,7 +1083,7 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
| SpillAreaSizeBytes - LocalsSpillAreaSize -
|
| GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes;
|
| Str << " in-args = " << InArgsSizeBytes << " bytes\n"
|
| - << " return address = " << X86_RET_IP_SIZE_BYTES << " bytes\n"
|
| + << " return address = " << Traits::X86_RET_IP_SIZE_BYTES << " bytes\n"
|
| << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
|
| << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
|
| << " globals spill area = " << GlobalsSize << " bytes\n"
|
| @@ -1234,7 +1102,7 @@ void TargetX8632::addProlog(CfgNode *Node) {
|
| }
|
| }
|
|
|
| -void TargetX8632::addEpilog(CfgNode *Node) {
|
| +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) {
|
| @@ -1287,8 +1155,8 @@ void TargetX8632::addEpilog(CfgNode *Node) {
|
| // jmp *t
|
| // bundle_unlock
|
| // FakeUse <original_ret_operand>
|
| - const SizeT BundleSize = 1
|
| - << Func->getAssembler<>()->getBundleAlignLog2Bytes();
|
| + const SizeT BundleSize =
|
| + 1 << Func->template getAssembler<>()->getBundleAlignLog2Bytes();
|
| Variable *T_ecx = makeReg(IceType_i32, RegX8632::Reg_ecx);
|
| _pop(T_ecx);
|
| _bundle_lock();
|
| @@ -1302,7 +1170,7 @@ void TargetX8632::addEpilog(CfgNode *Node) {
|
| RI->setDeleted();
|
| }
|
|
|
| -void TargetX8632::split64(Variable *Var) {
|
| +template <class Machine> void TargetX86Base<Machine>::split64(Variable *Var) {
|
| switch (Var->getType()) {
|
| default:
|
| return;
|
| @@ -1333,7 +1201,8 @@ void TargetX8632::split64(Variable *Var) {
|
| }
|
| }
|
|
|
| -Operand *TargetX8632::loOperand(Operand *Operand) {
|
| +template <class Machine>
|
| +Operand *TargetX86Base<Machine>::loOperand(Operand *Operand) {
|
| assert(Operand->getType() == IceType_i64 ||
|
| Operand->getType() == IceType_f64);
|
| if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
|
| @@ -1360,7 +1229,8 @@ Operand *TargetX8632::loOperand(Operand *Operand) {
|
| return nullptr;
|
| }
|
|
|
| -Operand *TargetX8632::hiOperand(Operand *Operand) {
|
| +template <class Machine>
|
| +Operand *TargetX86Base<Machine>::hiOperand(Operand *Operand) {
|
| assert(Operand->getType() == IceType_i64 ||
|
| Operand->getType() == IceType_f64);
|
| if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
|
| @@ -1401,8 +1271,10 @@ Operand *TargetX8632::hiOperand(Operand *Operand) {
|
| return nullptr;
|
| }
|
|
|
| -llvm::SmallBitVector TargetX8632::getRegisterSet(RegSetMask Include,
|
| - RegSetMask Exclude) const {
|
| +template <class Machine>
|
| +llvm::SmallBitVector
|
| +TargetX86Base<Machine>::getRegisterSet(RegSetMask Include,
|
| + RegSetMask Exclude) const {
|
| llvm::SmallBitVector Registers(RegX8632::Reg_NUM);
|
|
|
| #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \
|
| @@ -1431,7 +1303,8 @@ llvm::SmallBitVector TargetX8632::getRegisterSet(RegSetMask Include,
|
| return Registers;
|
| }
|
|
|
| -void TargetX8632::lowerAlloca(const InstAlloca *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerAlloca(const InstAlloca *Inst) {
|
| IsEbpBasedFrame = true;
|
| // Conservatively require the stack to be aligned. Some stack
|
| // adjustment operations implemented below assume that the stack is
|
| @@ -1451,10 +1324,11 @@ void TargetX8632::lowerAlloca(const InstAlloca *Inst) {
|
|
|
| // LLVM enforces power of 2 alignment.
|
| assert(llvm::isPowerOf2_32(AlignmentParam));
|
| - assert(llvm::isPowerOf2_32(X86_STACK_ALIGNMENT_BYTES));
|
| + assert(llvm::isPowerOf2_32(Traits::X86_STACK_ALIGNMENT_BYTES));
|
|
|
| - uint32_t Alignment = std::max(AlignmentParam, X86_STACK_ALIGNMENT_BYTES);
|
| - if (Alignment > X86_STACK_ALIGNMENT_BYTES) {
|
| + uint32_t Alignment =
|
| + std::max(AlignmentParam, Traits::X86_STACK_ALIGNMENT_BYTES);
|
| + if (Alignment > Traits::X86_STACK_ALIGNMENT_BYTES) {
|
| _and(esp, Ctx->getConstantInt32(-Alignment));
|
| }
|
| if (const auto *ConstantTotalSize =
|
| @@ -1480,8 +1354,9 @@ void TargetX8632::lowerAlloca(const InstAlloca *Inst) {
|
| // to multiply by powers of 2. These can be combined such that
|
| // e.g. multiplying by 100 can be done as 2 lea-based multiplies by 5,
|
| // combined with left-shifting by 2.
|
| -bool TargetX8632::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| - int32_t Src1) {
|
| +template <class Machine>
|
| +bool TargetX86Base<Machine>::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| + int32_t Src1) {
|
| // Disable this optimization for Om1 and O0, just to keep things
|
| // simple there.
|
| if (Ctx->getFlags().getOptLevel() < Opt_1)
|
| @@ -1570,7 +1445,8 @@ bool TargetX8632::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| return true;
|
| }
|
|
|
| -void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerArithmetic(const InstArithmetic *Inst) {
|
| Variable *Dest = Inst->getDest();
|
| Operand *Src0 = legalize(Inst->getSrc(0));
|
| Operand *Src1 = legalize(Inst->getSrc(1));
|
| @@ -1873,7 +1749,7 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) {
|
| bool TypesAreValidForPmull =
|
| Dest->getType() == IceType_v4i32 || Dest->getType() == IceType_v8i16;
|
| bool InstructionSetIsValidForPmull =
|
| - Dest->getType() == IceType_v8i16 || InstructionSet >= SSE4_1;
|
| + Dest->getType() == IceType_v8i16 || InstructionSet >= Machine::SSE4_1;
|
| if (TypesAreValidForPmull && InstructionSetIsValidForPmull) {
|
| Variable *T = makeReg(Dest->getType());
|
| _movp(T, Src0);
|
| @@ -2067,7 +1943,7 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) {
|
| // add t,src
|
| // sar t,log
|
| // dest=t
|
| - uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
|
| + uint32_t TypeWidth = Traits::X86_CHAR_BIT * typeWidthInBytes(Ty);
|
| _mov(T, Src0);
|
| // If for some reason we are dividing by 1, just treat it
|
| // like an assignment.
|
| @@ -2136,7 +2012,7 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) {
|
| // sub t,src
|
| // neg t
|
| // dest=t
|
| - uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
|
| + uint32_t TypeWidth = Traits::X86_CHAR_BIT * typeWidthInBytes(Ty);
|
| // If for some reason we are dividing by 1, just assign 0.
|
| if (LogDiv == 0) {
|
| _mov(Dest, Ctx->getConstantZero(Ty));
|
| @@ -2204,7 +2080,8 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerAssign(const InstAssign *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerAssign(const InstAssign *Inst) {
|
| Variable *Dest = Inst->getDest();
|
| Operand *Src0 = Inst->getSrc(0);
|
| assert(Dest->getType() == Src0->getType());
|
| @@ -2249,7 +2126,8 @@ void TargetX8632::lowerAssign(const InstAssign *Inst) {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerBr(const InstBr *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerBr(const InstBr *Inst) {
|
| if (Inst->isUnconditional()) {
|
| _br(Inst->getTargetUnconditional());
|
| return;
|
| @@ -2270,7 +2148,7 @@ void TargetX8632::lowerBr(const InstBr *Inst) {
|
| Operand *Src1 = legalize(Producer->getSrc(1));
|
| Operand *Src0RM = legalizeSrc0ForCmp(Src0, Src1);
|
| _cmp(Src0RM, Src1);
|
| - _br(getIcmp32Mapping(Cmp->getCondition()), Inst->getTargetTrue(),
|
| + _br(Traits::getIcmp32Mapping(Cmp->getCondition()), Inst->getTargetTrue(),
|
| Inst->getTargetFalse());
|
| return;
|
| }
|
| @@ -2283,7 +2161,8 @@ void TargetX8632::lowerBr(const InstBr *Inst) {
|
| _br(CondX86::Br_ne, Inst->getTargetTrue(), Inst->getTargetFalse());
|
| }
|
|
|
| -void TargetX8632::lowerCall(const InstCall *Instr) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerCall(const InstCall *Instr) {
|
| // x86-32 calling convention:
|
| //
|
| // * At the point before the call, the stack must be aligned to 16
|
| @@ -2318,12 +2197,13 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
|
| Type Ty = Arg->getType();
|
| // The PNaCl ABI requires the width of arguments to be at least 32 bits.
|
| assert(typeWidthInBytes(Ty) >= 4);
|
| - if (isVectorType(Ty) && XmmArgs.size() < X86_MAX_XMM_ARGS) {
|
| + if (isVectorType(Ty) && XmmArgs.size() < Traits::X86_MAX_XMM_ARGS) {
|
| XmmArgs.push_back(Arg);
|
| } else {
|
| StackArgs.push_back(Arg);
|
| if (isVectorType(Arg->getType())) {
|
| - ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
|
| + ParameterAreaSizeBytes =
|
| + Traits::applyStackAlignment(ParameterAreaSizeBytes);
|
| }
|
| Variable *esp = Func->getTarget()->getPhysicalRegister(RegX8632::Reg_esp);
|
| Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
|
| @@ -2335,7 +2215,7 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
|
| // Adjust the parameter area so that the stack is aligned. It is
|
| // assumed that the stack is already aligned at the start of the
|
| // calling sequence.
|
| - ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
|
| + ParameterAreaSizeBytes = Traits::applyStackAlignment(ParameterAreaSizeBytes);
|
|
|
| // Subtract the appropriate amount for the argument area. This also
|
| // takes care of setting the stack adjustment during emission.
|
| @@ -2418,7 +2298,7 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
|
| _mov(CallTargetVar, CallTarget);
|
| _bundle_lock(InstBundleLock::Opt_AlignToEnd);
|
| const SizeT BundleSize =
|
| - 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes();
|
| + 1 << Func->template getAssembler<>()->getBundleAlignLog2Bytes();
|
| _and(CallTargetVar, Ctx->getConstantInt32(~(BundleSize - 1)));
|
| CallTarget = CallTargetVar;
|
| }
|
| @@ -2480,7 +2360,8 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerCast(const InstCast *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerCast(const InstCast *Inst) {
|
| // a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap)
|
| InstCast::OpKind CastKind = Inst->getCastKind();
|
| Variable *Dest = Inst->getDest();
|
| @@ -2510,7 +2391,8 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
|
| } else {
|
| // width = width(elty) - 1; dest = (src << width) >> width
|
| SizeT ShiftAmount =
|
| - X86_CHAR_BIT * typeWidthInBytes(typeElementType(DestTy)) - 1;
|
| + Traits::X86_CHAR_BIT * typeWidthInBytes(typeElementType(DestTy)) -
|
| + 1;
|
| Constant *ShiftConstant = Ctx->getConstantInt8(ShiftAmount);
|
| Variable *T = makeReg(DestTy);
|
| _movp(T, Src0RM);
|
| @@ -2545,7 +2427,8 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
|
| // shl t1, dst_bitwidth - 1
|
| // sar t1, dst_bitwidth - 1
|
| // dst = t1
|
| - size_t DestBits = X86_CHAR_BIT * typeWidthInBytes(Dest->getType());
|
| + size_t DestBits =
|
| + Traits::X86_CHAR_BIT * typeWidthInBytes(Dest->getType());
|
| Constant *ShiftAmount = Ctx->getConstantInt32(DestBits - 1);
|
| Variable *T = makeReg(Dest->getType());
|
| if (typeWidthInBytes(Dest->getType()) <=
|
| @@ -2950,7 +2833,9 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerExtractElement(const InstExtractElement *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerExtractElement(
|
| + const InstExtractElement *Inst) {
|
| Operand *SourceVectNotLegalized = Inst->getSrc(0);
|
| ConstantInteger32 *ElementIndex =
|
| llvm::dyn_cast<ConstantInteger32>(Inst->getSrc(1));
|
| @@ -2960,12 +2845,12 @@ void TargetX8632::lowerExtractElement(const InstExtractElement *Inst) {
|
| unsigned Index = ElementIndex->getValue();
|
| Type Ty = SourceVectNotLegalized->getType();
|
| Type ElementTy = typeElementType(Ty);
|
| - Type InVectorElementTy = getInVectorElementType(Ty);
|
| + Type InVectorElementTy = Traits::getInVectorElementType(Ty);
|
| Variable *ExtractedElementR = makeReg(InVectorElementTy);
|
|
|
| // TODO(wala): Determine the best lowering sequences for each type.
|
| - bool CanUsePextr =
|
| - Ty == IceType_v8i16 || Ty == IceType_v8i1 || InstructionSet >= SSE4_1;
|
| + bool CanUsePextr = Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
|
| + InstructionSet >= Machine::SSE4_1;
|
| if (CanUsePextr && Ty != IceType_v4f32) {
|
| // Use pextrb, pextrw, or pextrd.
|
| Constant *Mask = Ctx->getConstantInt32(Index);
|
| @@ -3026,7 +2911,8 @@ void TargetX8632::lowerExtractElement(const InstExtractElement *Inst) {
|
| _mov(Dest, ExtractedElementR);
|
| }
|
|
|
| -void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerFcmp(const InstFcmp *Inst) {
|
| Operand *Src0 = Inst->getSrc(0);
|
| Operand *Src1 = Inst->getSrc(1);
|
| Variable *Dest = Inst->getDest();
|
| @@ -3034,9 +2920,9 @@ void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
|
| if (isVectorType(Dest->getType())) {
|
| InstFcmp::FCond Condition = Inst->getCondition();
|
| size_t Index = static_cast<size_t>(Condition);
|
| - assert(Index < TableFcmpSize);
|
| + assert(Index < Traits::TableFcmpSize);
|
|
|
| - if (TableFcmp[Index].SwapVectorOperands) {
|
| + if (Traits::TableFcmp[Index].SwapVectorOperands) {
|
| Operand *T = Src0;
|
| Src0 = Src1;
|
| Src1 = T;
|
| @@ -3057,7 +2943,7 @@ void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
|
|
|
| switch (Condition) {
|
| default: {
|
| - CondX86::CmppsCond Predicate = TableFcmp[Index].Predicate;
|
| + CondX86::CmppsCond Predicate = Traits::TableFcmp[Index].Predicate;
|
| assert(Predicate != CondX86::Cmpps_Invalid);
|
| T = makeReg(Src0RM->getType());
|
| _movp(T, Src0RM);
|
| @@ -3106,11 +2992,11 @@ void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
|
| // setcc a, C1
|
| InstFcmp::FCond Condition = Inst->getCondition();
|
| size_t Index = static_cast<size_t>(Condition);
|
| - assert(Index < TableFcmpSize);
|
| - if (TableFcmp[Index].SwapScalarOperands)
|
| + assert(Index < Traits::TableFcmpSize);
|
| + if (Traits::TableFcmp[Index].SwapScalarOperands)
|
| std::swap(Src0, Src1);
|
| - bool HasC1 = (TableFcmp[Index].C1 != CondX86::Br_None);
|
| - bool HasC2 = (TableFcmp[Index].C2 != CondX86::Br_None);
|
| + bool HasC1 = (Traits::TableFcmp[Index].C1 != CondX86::Br_None);
|
| + bool HasC2 = (Traits::TableFcmp[Index].C2 != CondX86::Br_None);
|
| if (HasC1) {
|
| Src0 = legalize(Src0);
|
| Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
|
| @@ -3118,26 +3004,28 @@ void TargetX8632::lowerFcmp(const InstFcmp *Inst) {
|
| _mov(T, Src0);
|
| _ucomiss(T, Src1RM);
|
| if (!HasC2) {
|
| - assert(TableFcmp[Index].Default);
|
| - _setcc(Dest, TableFcmp[Index].C1);
|
| + assert(Traits::TableFcmp[Index].Default);
|
| + _setcc(Dest, Traits::TableFcmp[Index].C1);
|
| return;
|
| }
|
| }
|
| - Constant *Default = Ctx->getConstantInt32(TableFcmp[Index].Default);
|
| + Constant *Default = Ctx->getConstantInt32(Traits::TableFcmp[Index].Default);
|
| _mov(Dest, Default);
|
| if (HasC1) {
|
| InstX8632Label *Label = InstX8632Label::create(Func, this);
|
| - _br(TableFcmp[Index].C1, Label);
|
| + _br(Traits::TableFcmp[Index].C1, Label);
|
| if (HasC2) {
|
| - _br(TableFcmp[Index].C2, Label);
|
| + _br(Traits::TableFcmp[Index].C2, Label);
|
| }
|
| - Constant *NonDefault = Ctx->getConstantInt32(!TableFcmp[Index].Default);
|
| + Constant *NonDefault =
|
| + Ctx->getConstantInt32(!Traits::TableFcmp[Index].Default);
|
| _mov_nonkillable(Dest, NonDefault);
|
| Context.insert(Label);
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerIcmp(const InstIcmp *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerIcmp(const InstIcmp *Inst) {
|
| Operand *Src0 = legalize(Inst->getSrc(0));
|
| Operand *Src1 = legalize(Inst->getSrc(1));
|
| Variable *Dest = Inst->getDest();
|
| @@ -3255,7 +3143,7 @@ void TargetX8632::lowerIcmp(const InstIcmp *Inst) {
|
| if (Src0->getType() == IceType_i64) {
|
| InstIcmp::ICond Condition = Inst->getCondition();
|
| size_t Index = static_cast<size_t>(Condition);
|
| - assert(Index < TableIcmp64Size);
|
| + assert(Index < Traits::TableIcmp64Size);
|
| Operand *Src0LoRM = legalize(loOperand(Src0), Legal_Reg | Legal_Mem);
|
| Operand *Src0HiRM = legalize(hiOperand(Src0), Legal_Reg | Legal_Mem);
|
| Operand *Src1LoRI = legalize(loOperand(Src1), Legal_Reg | Legal_Imm);
|
| @@ -3266,12 +3154,12 @@ void TargetX8632::lowerIcmp(const InstIcmp *Inst) {
|
| InstX8632Label *LabelTrue = InstX8632Label::create(Func, this);
|
| _mov(Dest, One);
|
| _cmp(Src0HiRM, Src1HiRI);
|
| - if (TableIcmp64[Index].C1 != CondX86::Br_None)
|
| - _br(TableIcmp64[Index].C1, LabelTrue);
|
| - if (TableIcmp64[Index].C2 != CondX86::Br_None)
|
| - _br(TableIcmp64[Index].C2, LabelFalse);
|
| + if (Traits::TableIcmp64[Index].C1 != CondX86::Br_None)
|
| + _br(Traits::TableIcmp64[Index].C1, LabelTrue);
|
| + if (Traits::TableIcmp64[Index].C2 != CondX86::Br_None)
|
| + _br(Traits::TableIcmp64[Index].C2, LabelFalse);
|
| _cmp(Src0LoRM, Src1LoRI);
|
| - _br(TableIcmp64[Index].C3, LabelTrue);
|
| + _br(Traits::TableIcmp64[Index].C3, LabelTrue);
|
| Context.insert(LabelFalse);
|
| _mov_nonkillable(Dest, Zero);
|
| Context.insert(LabelTrue);
|
| @@ -3281,10 +3169,11 @@ void TargetX8632::lowerIcmp(const InstIcmp *Inst) {
|
| // cmp b, c
|
| Operand *Src0RM = legalizeSrc0ForCmp(Src0, Src1);
|
| _cmp(Src0RM, Src1);
|
| - _setcc(Dest, getIcmp32Mapping(Inst->getCondition()));
|
| + _setcc(Dest, Traits::getIcmp32Mapping(Inst->getCondition()));
|
| }
|
|
|
| -void TargetX8632::lowerInsertElement(const InstInsertElement *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerInsertElement(const InstInsertElement *Inst) {
|
| Operand *SourceVectNotLegalized = Inst->getSrc(0);
|
| Operand *ElementToInsertNotLegalized = Inst->getSrc(1);
|
| ConstantInteger32 *ElementIndex =
|
| @@ -3296,7 +3185,7 @@ void TargetX8632::lowerInsertElement(const InstInsertElement *Inst) {
|
|
|
| Type Ty = SourceVectNotLegalized->getType();
|
| Type ElementTy = typeElementType(Ty);
|
| - Type InVectorElementTy = getInVectorElementType(Ty);
|
| + Type InVectorElementTy = Traits::getInVectorElementType(Ty);
|
|
|
| if (ElementTy == IceType_i1) {
|
| // Expand the element to the appropriate size for it to be inserted
|
| @@ -3308,7 +3197,8 @@ void TargetX8632::lowerInsertElement(const InstInsertElement *Inst) {
|
| ElementToInsertNotLegalized = Expanded;
|
| }
|
|
|
| - if (Ty == IceType_v8i16 || Ty == IceType_v8i1 || InstructionSet >= SSE4_1) {
|
| + if (Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
|
| + InstructionSet >= Machine::SSE4_1) {
|
| // Use insertps, pinsrb, pinsrw, or pinsrd.
|
| Operand *ElementRM =
|
| legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
|
| @@ -3407,7 +3297,9 @@ void TargetX8632::lowerInsertElement(const InstInsertElement *Inst) {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerIntrinsicCall(
|
| + const InstIntrinsicCall *Instr) {
|
| switch (Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID) {
|
| case Intrinsics::AtomicCmpxchg: {
|
| if (!Intrinsics::isMemoryOrderValid(
|
| @@ -3510,11 +3402,10 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
|
| Func->setError("Unexpected memory ordering for AtomicRMW");
|
| return;
|
| }
|
| - lowerAtomicRMW(
|
| - Instr->getDest(),
|
| - static_cast<uint32_t>(
|
| - llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
|
| - Instr->getArg(1), Instr->getArg(2));
|
| + lowerAtomicRMW(Instr->getDest(),
|
| + static_cast<uint32_t>(llvm::cast<ConstantInteger32>(
|
| + Instr->getArg(0))->getValue()),
|
| + Instr->getArg(1), Instr->getArg(2));
|
| return;
|
| case Intrinsics::AtomicStore: {
|
| if (!Intrinsics::isMemoryOrderValid(
|
| @@ -3740,8 +3631,10 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
|
| return;
|
| }
|
|
|
| -void TargetX8632::lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr,
|
| - Operand *Expected, Operand *Desired) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerAtomicCmpxchg(Variable *DestPrev,
|
| + Operand *Ptr, Operand *Expected,
|
| + Operand *Desired) {
|
| if (Expected->getType() == IceType_i64) {
|
| // Reserve the pre-colored registers first, before adding any more
|
| // infinite-weight variables from formMemoryOperand's legalization.
|
| @@ -3771,9 +3664,11 @@ void TargetX8632::lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr,
|
| _mov(DestPrev, T_eax);
|
| }
|
|
|
| -bool TargetX8632::tryOptimizedCmpxchgCmpBr(Variable *Dest, Operand *PtrToMem,
|
| - Operand *Expected,
|
| - Operand *Desired) {
|
| +template <class Machine>
|
| +bool TargetX86Base<Machine>::tryOptimizedCmpxchgCmpBr(Variable *Dest,
|
| + Operand *PtrToMem,
|
| + Operand *Expected,
|
| + Operand *Desired) {
|
| if (Ctx->getFlags().getOptLevel() == Opt_m1)
|
| return false;
|
| // Peek ahead a few instructions and see how Dest is used.
|
| @@ -3844,8 +3739,9 @@ bool TargetX8632::tryOptimizedCmpxchgCmpBr(Variable *Dest, Operand *PtrToMem,
|
| return false;
|
| }
|
|
|
| -void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| - Operand *Ptr, Operand *Val) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| + Operand *Ptr, Operand *Val) {
|
| bool NeedsCmpxchg = false;
|
| LowerBinOp Op_Lo = nullptr;
|
| LowerBinOp Op_Hi = nullptr;
|
| @@ -3858,8 +3754,8 @@ void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| // All the fall-through paths must set this to true, but use this
|
| // for asserting.
|
| NeedsCmpxchg = true;
|
| - Op_Lo = &TargetX8632::_add;
|
| - Op_Hi = &TargetX8632::_adc;
|
| + Op_Lo = &TargetX86Base<Machine>::_add;
|
| + Op_Hi = &TargetX86Base<Machine>::_adc;
|
| break;
|
| }
|
| OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType());
|
| @@ -3873,8 +3769,8 @@ void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| case Intrinsics::AtomicSub: {
|
| if (Dest->getType() == IceType_i64) {
|
| NeedsCmpxchg = true;
|
| - Op_Lo = &TargetX8632::_sub;
|
| - Op_Hi = &TargetX8632::_sbb;
|
| + Op_Lo = &TargetX86Base<Machine>::_sub;
|
| + Op_Hi = &TargetX86Base<Machine>::_sbb;
|
| break;
|
| }
|
| OperandX8632Mem *Addr = formMemoryOperand(Ptr, Dest->getType());
|
| @@ -3893,18 +3789,18 @@ void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| // xadd is probably fine vs lock add for add, and xchg is fine
|
| // vs an atomic store.
|
| NeedsCmpxchg = true;
|
| - Op_Lo = &TargetX8632::_or;
|
| - Op_Hi = &TargetX8632::_or;
|
| + Op_Lo = &TargetX86Base<Machine>::_or;
|
| + Op_Hi = &TargetX86Base<Machine>::_or;
|
| break;
|
| case Intrinsics::AtomicAnd:
|
| NeedsCmpxchg = true;
|
| - Op_Lo = &TargetX8632::_and;
|
| - Op_Hi = &TargetX8632::_and;
|
| + Op_Lo = &TargetX86Base<Machine>::_and;
|
| + Op_Hi = &TargetX86Base<Machine>::_and;
|
| break;
|
| case Intrinsics::AtomicXor:
|
| NeedsCmpxchg = true;
|
| - Op_Lo = &TargetX8632::_xor;
|
| - Op_Hi = &TargetX8632::_xor;
|
| + Op_Lo = &TargetX86Base<Machine>::_xor;
|
| + Op_Hi = &TargetX86Base<Machine>::_xor;
|
| break;
|
| case Intrinsics::AtomicExchange:
|
| if (Dest->getType() == IceType_i64) {
|
| @@ -3928,9 +3824,12 @@ void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
|
| expandAtomicRMWAsCmpxchg(Op_Lo, Op_Hi, Dest, Ptr, Val);
|
| }
|
|
|
| -void TargetX8632::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, LowerBinOp Op_Hi,
|
| - Variable *Dest, Operand *Ptr,
|
| - Operand *Val) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
|
| + LowerBinOp Op_Hi,
|
| + Variable *Dest,
|
| + Operand *Ptr,
|
| + Operand *Val) {
|
| // Expand a more complex RMW operation as a cmpxchg loop:
|
| // For 64-bit:
|
| // mov eax, [ptr]
|
| @@ -4035,8 +3934,10 @@ void TargetX8632::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, LowerBinOp Op_Hi,
|
| //
|
| // We could do constant folding here, but that should have
|
| // been done by the front-end/middle-end optimizations.
|
| -void TargetX8632::lowerCountZeros(bool Cttz, Type Ty, Variable *Dest,
|
| - Operand *FirstVal, Operand *SecondVal) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerCountZeros(bool Cttz, Type Ty, Variable *Dest,
|
| + Operand *FirstVal,
|
| + Operand *SecondVal) {
|
| // TODO(jvoung): Determine if the user CPU supports LZCNT (BMI).
|
| // Then the instructions will handle the Val == 0 case much more simply
|
| // and won't require conversion from bit position to number of zeros.
|
| @@ -4107,8 +4008,6 @@ void TargetX8632::lowerCountZeros(bool Cttz, Type Ty, Variable *Dest,
|
| _mov(DestHi, Ctx->getConstantZero(IceType_i32));
|
| }
|
|
|
| -namespace {
|
| -
|
| bool isAdd(const Inst *Inst) {
|
| if (const InstArithmetic *Arith =
|
| llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) {
|
| @@ -4349,9 +4248,8 @@ void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base,
|
| }
|
| }
|
|
|
| -} // anonymous namespace
|
| -
|
| -void TargetX8632::lowerLoad(const InstLoad *Load) {
|
| +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
|
| @@ -4364,7 +4262,7 @@ void TargetX8632::lowerLoad(const InstLoad *Load) {
|
| lowerAssign(Assign);
|
| }
|
|
|
| -void TargetX8632::doAddressOptLoad() {
|
| +template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() {
|
| Inst *Inst = Context.getCur();
|
| Variable *Dest = Inst->getDest();
|
| Operand *Addr = Inst->getSrc(0);
|
| @@ -4388,18 +4286,21 @@ void TargetX8632::doAddressOptLoad() {
|
| }
|
| }
|
|
|
| -void TargetX8632::randomlyInsertNop(float Probability) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::randomlyInsertNop(float Probability) {
|
| RandomNumberGeneratorWrapper RNG(Ctx->getRNG());
|
| if (RNG.getTrueWithProbability(Probability)) {
|
| - _nop(RNG(X86_NUM_NOP_VARIANTS));
|
| + _nop(RNG(Traits::X86_NUM_NOP_VARIANTS));
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerPhi(const InstPhi * /*Inst*/) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerPhi(const InstPhi * /*Inst*/) {
|
| Func->setError("Phi found in regular instruction list");
|
| }
|
|
|
| -void TargetX8632::lowerRet(const InstRet *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerRet(const InstRet *Inst) {
|
| Variable *Reg = nullptr;
|
| if (Inst->hasRetValue()) {
|
| Operand *Src0 = legalize(Inst->getRetValue());
|
| @@ -4429,7 +4330,8 @@ void TargetX8632::lowerRet(const InstRet *Inst) {
|
| Context.insert(InstFakeUse::create(Func, esp));
|
| }
|
|
|
| -void TargetX8632::lowerSelect(const InstSelect *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerSelect(const InstSelect *Inst) {
|
| Variable *Dest = Inst->getDest();
|
| Type DestTy = Dest->getType();
|
| Operand *SrcT = Inst->getTrueOperand();
|
| @@ -4441,7 +4343,7 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) {
|
| Variable *T = makeReg(SrcTy);
|
| Operand *SrcTRM = legalize(SrcT, Legal_Reg | Legal_Mem);
|
| Operand *SrcFRM = legalize(SrcF, Legal_Reg | Legal_Mem);
|
| - if (InstructionSet >= SSE4_1) {
|
| + if (InstructionSet >= Machine::SSE4_1) {
|
| // TODO(wala): If the condition operand is a constant, use blendps
|
| // or pblendw.
|
| //
|
| @@ -4467,7 +4369,7 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) {
|
| }
|
| return;
|
| }
|
| - // Lower select without SSE4.1:
|
| + // Lower select without Machine::SSE4.1:
|
| // a=d?b:c ==>
|
| // if elementtype(d) != i1:
|
| // d=sext(d);
|
| @@ -4505,7 +4407,7 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) {
|
| break;
|
| case BoolFolding::PK_Icmp32: {
|
| auto *Cmp = llvm::dyn_cast<InstIcmp>(Producer);
|
| - Cond = getIcmp32Mapping(Cmp->getCondition());
|
| + Cond = Traits::getIcmp32Mapping(Cmp->getCondition());
|
| CmpOpnd1 = legalize(Producer->getSrc(1));
|
| CmpOpnd0 = legalizeSrc0ForCmp(Producer->getSrc(0), CmpOpnd1);
|
| } break;
|
| @@ -4569,7 +4471,8 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) {
|
| _mov(Dest, T);
|
| }
|
|
|
| -void TargetX8632::lowerStore(const InstStore *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
|
| Operand *Value = Inst->getData();
|
| Operand *Addr = Inst->getAddr();
|
| OperandX8632Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
|
| @@ -4589,7 +4492,7 @@ void TargetX8632::lowerStore(const InstStore *Inst) {
|
| }
|
| }
|
|
|
| -void TargetX8632::doAddressOptStore() {
|
| +template <class Machine> void TargetX86Base<Machine>::doAddressOptStore() {
|
| InstStore *Inst = llvm::cast<InstStore>(Context.getCur());
|
| Operand *Data = Inst->getData();
|
| Operand *Addr = Inst->getAddr();
|
| @@ -4616,7 +4519,8 @@ void TargetX8632::doAddressOptStore() {
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerSwitch(const InstSwitch *Inst) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) {
|
| // This implements the most naive possible lowering.
|
| // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
|
| Operand *Src0 = Inst->getComparison();
|
| @@ -4660,9 +4564,10 @@ void TargetX8632::lowerSwitch(const InstSwitch *Inst) {
|
| _br(Inst->getLabelDefault());
|
| }
|
|
|
| -void TargetX8632::scalarizeArithmetic(InstArithmetic::OpKind Kind,
|
| - Variable *Dest, Operand *Src0,
|
| - Operand *Src1) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::scalarizeArithmetic(InstArithmetic::OpKind Kind,
|
| + Variable *Dest, Operand *Src0,
|
| + Operand *Src1) {
|
| assert(isVectorType(Dest->getType()));
|
| Type Ty = Dest->getType();
|
| Type ElementTy = typeElementType(Ty);
|
| @@ -4699,7 +4604,8 @@ void TargetX8632::scalarizeArithmetic(InstArithmetic::OpKind Kind,
|
| // We can eliminate the sext operation by copying the result of pcmpeqd,
|
| // pcmpgtd, or cmpps (which produce sign extended results) to the result
|
| // of the sext operation.
|
| -void TargetX8632::eliminateNextVectorSextInstruction(
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::eliminateNextVectorSextInstruction(
|
| Variable *SignExtendedResult) {
|
| if (InstCast *NextCast =
|
| llvm::dyn_cast_or_null<InstCast>(Context.getNextInst())) {
|
| @@ -4713,9 +4619,14 @@ void TargetX8632::eliminateNextVectorSextInstruction(
|
| }
|
| }
|
|
|
| -void TargetX8632::lowerUnreachable(const InstUnreachable * /*Inst*/) { _ud2(); }
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerUnreachable(
|
| + const InstUnreachable * /*Inst*/) {
|
| + _ud2();
|
| +}
|
|
|
| -void TargetX8632::lowerRMW(const InstX8632FakeRMW *RMW) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerRMW(const InstX8632FakeRMW *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
|
| @@ -4789,7 +4700,8 @@ void TargetX8632::lowerRMW(const InstX8632FakeRMW *RMW) {
|
| llvm::report_fatal_error("Couldn't lower RMW instruction");
|
| }
|
|
|
| -void TargetX8632::lowerOther(const Inst *Instr) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerOther(const Inst *Instr) {
|
| if (const auto *RMW = llvm::dyn_cast<InstX8632FakeRMW>(Instr)) {
|
| lowerRMW(RMW);
|
| } else {
|
| @@ -4801,7 +4713,7 @@ void TargetX8632::lowerOther(const Inst *Instr) {
|
| // preserve integrity of liveness analysis. Undef values are also
|
| // turned into zeroes, since loOperand() and hiOperand() don't expect
|
| // Undef input.
|
| -void TargetX8632::prelowerPhis() {
|
| +template <class Machine> void TargetX86Base<Machine>::prelowerPhis() {
|
| // Pause constant blinding or pooling, blinding or pooling will be done later
|
| // during phi lowering assignments
|
| BoolFlagSaver B(RandomizationPoolingPaused, true);
|
| @@ -4832,8 +4744,6 @@ void TargetX8632::prelowerPhis() {
|
| }
|
| }
|
|
|
| -namespace {
|
| -
|
| bool isMemoryOperand(const Operand *Opnd) {
|
| if (const auto Var = llvm::dyn_cast<Variable>(Opnd))
|
| return !Var->hasReg();
|
| @@ -4848,12 +4758,11 @@ bool isMemoryOperand(const Operand *Opnd) {
|
| return true;
|
| }
|
|
|
| -} // end of anonymous namespace
|
| -
|
| // Lower the pre-ordered list of assignments into mov instructions.
|
| // Also has to do some ad-hoc register allocation as necessary.
|
| -void TargetX8632::lowerPhiAssignments(CfgNode *Node,
|
| - const AssignList &Assignments) {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::lowerPhiAssignments(
|
| + CfgNode *Node, const AssignList &Assignments) {
|
| // Check that this is a properly initialized shell of a node.
|
| assert(Node->getOutEdges().size() == 1);
|
| assert(Node->getInsts().empty());
|
| @@ -5004,7 +4913,8 @@ void TargetX8632::lowerPhiAssignments(CfgNode *Node,
|
| // TODO(wala): Add limited support for vector constants so that
|
| // complex initialization in registers is unnecessary.
|
|
|
| -Variable *TargetX8632::makeVectorOfZeros(Type Ty, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeVectorOfZeros(Type Ty, int32_t RegNum) {
|
| Variable *Reg = makeReg(Ty, RegNum);
|
| // Insert a FakeDef, since otherwise the live range of Reg might
|
| // be overestimated.
|
| @@ -5013,7 +4923,9 @@ Variable *TargetX8632::makeVectorOfZeros(Type Ty, int32_t RegNum) {
|
| return Reg;
|
| }
|
|
|
| -Variable *TargetX8632::makeVectorOfMinusOnes(Type Ty, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeVectorOfMinusOnes(Type Ty,
|
| + int32_t RegNum) {
|
| Variable *MinusOnes = makeReg(Ty, RegNum);
|
| // Insert a FakeDef so the live range of MinusOnes is not overestimated.
|
| Context.insert(InstFakeDef::create(Func, MinusOnes));
|
| @@ -5021,19 +4933,23 @@ Variable *TargetX8632::makeVectorOfMinusOnes(Type Ty, int32_t RegNum) {
|
| return MinusOnes;
|
| }
|
|
|
| -Variable *TargetX8632::makeVectorOfOnes(Type Ty, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeVectorOfOnes(Type Ty, int32_t RegNum) {
|
| Variable *Dest = makeVectorOfZeros(Ty, RegNum);
|
| Variable *MinusOne = makeVectorOfMinusOnes(Ty);
|
| _psub(Dest, MinusOne);
|
| return Dest;
|
| }
|
|
|
| -Variable *TargetX8632::makeVectorOfHighOrderBits(Type Ty, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeVectorOfHighOrderBits(Type Ty,
|
| + int32_t RegNum) {
|
| assert(Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v8i16 ||
|
| Ty == IceType_v16i8);
|
| if (Ty == IceType_v4f32 || Ty == IceType_v4i32 || Ty == IceType_v8i16) {
|
| Variable *Reg = makeVectorOfOnes(Ty, RegNum);
|
| - SizeT Shift = typeWidthInBytes(typeElementType(Ty)) * X86_CHAR_BIT - 1;
|
| + SizeT Shift =
|
| + typeWidthInBytes(typeElementType(Ty)) * Traits::X86_CHAR_BIT - 1;
|
| _psll(Reg, Ctx->getConstantInt8(Shift));
|
| return Reg;
|
| } else {
|
| @@ -5053,15 +4969,18 @@ Variable *TargetX8632::makeVectorOfHighOrderBits(Type Ty, int32_t RegNum) {
|
| // for f64. Construct it as vector of ones logically right shifted
|
| // one bit. TODO(stichnot): Fix the wala TODO above, to represent
|
| // vector constants in memory.
|
| -Variable *TargetX8632::makeVectorOfFabsMask(Type Ty, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeVectorOfFabsMask(Type Ty,
|
| + int32_t RegNum) {
|
| Variable *Reg = makeVectorOfMinusOnes(Ty, RegNum);
|
| _psrl(Reg, Ctx->getConstantInt8(1));
|
| return Reg;
|
| }
|
|
|
| -OperandX8632Mem *TargetX8632::getMemoryOperandForStackSlot(Type Ty,
|
| - Variable *Slot,
|
| - uint32_t Offset) {
|
| +template <class Machine>
|
| +OperandX8632Mem *
|
| +TargetX86Base<Machine>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
|
| + uint32_t Offset) {
|
| // Ensure that Loc is a stack slot.
|
| assert(Slot->getWeight().isZero());
|
| assert(Slot->getRegNum() == Variable::NoRegister);
|
| @@ -5078,7 +4997,8 @@ OperandX8632Mem *TargetX8632::getMemoryOperandForStackSlot(Type Ty,
|
|
|
| // Helper for legalize() to emit the right code to lower an operand to a
|
| // register of the appropriate type.
|
| -Variable *TargetX8632::copyToReg(Operand *Src, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::copyToReg(Operand *Src, int32_t RegNum) {
|
| Type Ty = Src->getType();
|
| Variable *Reg = makeReg(Ty, RegNum);
|
| if (isVectorType(Ty)) {
|
| @@ -5089,8 +5009,9 @@ Variable *TargetX8632::copyToReg(Operand *Src, int32_t RegNum) {
|
| return Reg;
|
| }
|
|
|
| -Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| - int32_t RegNum) {
|
| +template <class Machine>
|
| +Operand *TargetX86Base<Machine>::legalize(Operand *From, LegalMask Allowed,
|
| + int32_t RegNum) {
|
| Type Ty = From->getType();
|
| // Assert that a physical register is allowed. To date, all calls
|
| // to legalize() allow a physical register. If a physical register
|
| @@ -5203,7 +5124,8 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| }
|
|
|
| // Provide a trivial wrapper to legalize() for this common usage.
|
| -Variable *TargetX8632::legalizeToVar(Operand *From, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::legalizeToVar(Operand *From, int32_t RegNum) {
|
| return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
|
| }
|
|
|
| @@ -5213,7 +5135,9 @@ Variable *TargetX8632::legalizeToVar(Operand *From, int32_t RegNum) {
|
| // (Actually, either Src0 or Src1 can be chosen for the physical
|
| // register, but unfortunately we have to commit to one or the other
|
| // before register allocation.)
|
| -Operand *TargetX8632::legalizeSrc0ForCmp(Operand *Src0, Operand *Src1) {
|
| +template <class Machine>
|
| +Operand *TargetX86Base<Machine>::legalizeSrc0ForCmp(Operand *Src0,
|
| + Operand *Src1) {
|
| bool IsSrc1ImmOrReg = false;
|
| if (llvm::isa<Constant>(Src1)) {
|
| IsSrc1ImmOrReg = true;
|
| @@ -5224,8 +5148,10 @@ Operand *TargetX8632::legalizeSrc0ForCmp(Operand *Src0, Operand *Src1) {
|
| return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
|
| }
|
|
|
| -OperandX8632Mem *TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty,
|
| - bool DoLegalize) {
|
| +template <class Machine>
|
| +OperandX8632Mem *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
|
| @@ -5257,7 +5183,8 @@ OperandX8632Mem *TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty,
|
| DoLegalize ? legalize(Mem) : randomizeOrPoolImmediate(Mem));
|
| }
|
|
|
| -Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) {
|
| +template <class Machine>
|
| +Variable *TargetX86Base<Machine>::makeReg(Type Type, int32_t RegNum) {
|
| // There aren't any 64-bit integer registers for x86-32.
|
| assert(Type != IceType_i64);
|
| Variable *Reg = Func->makeVariable(Type);
|
| @@ -5268,13 +5195,14 @@ Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) {
|
| return Reg;
|
| }
|
|
|
| -void TargetX8632::postLower() {
|
| +template <class Machine> void TargetX86Base<Machine>::postLower() {
|
| if (Ctx->getFlags().getOptLevel() == Opt_m1)
|
| return;
|
| inferTwoAddress();
|
| }
|
|
|
| -void TargetX8632::makeRandomRegisterPermutation(
|
| +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
|
| @@ -5341,192 +5269,44 @@ void TargetX8632::makeRandomRegisterPermutation(
|
| }
|
| }
|
|
|
| -void TargetX8632::emit(const ConstantInteger32 *C) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emit(const ConstantInteger32 *C) const {
|
| if (!ALLOW_DUMP)
|
| return;
|
| Ostream &Str = Ctx->getStrEmit();
|
| Str << getConstantPrefix() << C->getValue();
|
| }
|
|
|
| -void TargetX8632::emit(const ConstantInteger64 *) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emit(const ConstantInteger64 *) const {
|
| llvm::report_fatal_error("Not expecting to emit 64-bit integers");
|
| }
|
|
|
| -void TargetX8632::emit(const ConstantFloat *C) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emit(const ConstantFloat *C) const {
|
| if (!ALLOW_DUMP)
|
| return;
|
| Ostream &Str = Ctx->getStrEmit();
|
| C->emitPoolLabel(Str);
|
| }
|
|
|
| -void TargetX8632::emit(const ConstantDouble *C) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emit(const ConstantDouble *C) const {
|
| if (!ALLOW_DUMP)
|
| return;
|
| Ostream &Str = Ctx->getStrEmit();
|
| C->emitPoolLabel(Str);
|
| }
|
|
|
| -void TargetX8632::emit(const ConstantUndef *) const {
|
| +template <class Machine>
|
| +void TargetX86Base<Machine>::emit(const ConstantUndef *) const {
|
| llvm::report_fatal_error("undef value encountered by emitter.");
|
| }
|
|
|
| -TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
|
| - : TargetDataLowering(Ctx) {}
|
| -
|
| -void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
|
| - const IceString &SectionSuffix) {
|
| - switch (Ctx->getFlags().getOutFileType()) {
|
| - case FT_Elf: {
|
| - ELFObjectWriter *Writer = Ctx->getObjectWriter();
|
| - Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix);
|
| - } break;
|
| - case FT_Asm:
|
| - case FT_Iasm: {
|
| - const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
|
| - OstreamLocker L(Ctx);
|
| - for (const VariableDeclaration *Var : Vars) {
|
| - if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
|
| - emitGlobal(*Var, SectionSuffix);
|
| - }
|
| - }
|
| - } break;
|
| - }
|
| -}
|
| -
|
| -template <typename T> struct PoolTypeConverter {};
|
| -
|
| -template <> struct PoolTypeConverter<float> {
|
| - typedef uint32_t PrimitiveIntType;
|
| - typedef ConstantFloat IceType;
|
| - static const Type Ty = IceType_f32;
|
| - static const char *TypeName;
|
| - static const char *AsmTag;
|
| - static const char *PrintfString;
|
| -};
|
| -const char *PoolTypeConverter<float>::TypeName = "float";
|
| -const char *PoolTypeConverter<float>::AsmTag = ".long";
|
| -const char *PoolTypeConverter<float>::PrintfString = "0x%x";
|
| -
|
| -template <> struct PoolTypeConverter<double> {
|
| - typedef uint64_t PrimitiveIntType;
|
| - typedef ConstantDouble IceType;
|
| - static const Type Ty = IceType_f64;
|
| - static const char *TypeName;
|
| - static const char *AsmTag;
|
| - static const char *PrintfString;
|
| -};
|
| -const char *PoolTypeConverter<double>::TypeName = "double";
|
| -const char *PoolTypeConverter<double>::AsmTag = ".quad";
|
| -const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
|
| -
|
| -// Add converter for int type constant pooling
|
| -template <> struct PoolTypeConverter<uint32_t> {
|
| - typedef uint32_t PrimitiveIntType;
|
| - typedef ConstantInteger32 IceType;
|
| - static const Type Ty = IceType_i32;
|
| - static const char *TypeName;
|
| - static const char *AsmTag;
|
| - static const char *PrintfString;
|
| -};
|
| -const char *PoolTypeConverter<uint32_t>::TypeName = "i32";
|
| -const char *PoolTypeConverter<uint32_t>::AsmTag = ".long";
|
| -const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x";
|
| -
|
| -// Add converter for int type constant pooling
|
| -template <> struct PoolTypeConverter<uint16_t> {
|
| - typedef uint32_t PrimitiveIntType;
|
| - typedef ConstantInteger32 IceType;
|
| - static const Type Ty = IceType_i16;
|
| - static const char *TypeName;
|
| - static const char *AsmTag;
|
| - static const char *PrintfString;
|
| -};
|
| -const char *PoolTypeConverter<uint16_t>::TypeName = "i16";
|
| -const char *PoolTypeConverter<uint16_t>::AsmTag = ".short";
|
| -const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x";
|
| -
|
| -// Add converter for int type constant pooling
|
| -template <> struct PoolTypeConverter<uint8_t> {
|
| - typedef uint32_t PrimitiveIntType;
|
| - typedef ConstantInteger32 IceType;
|
| - static const Type Ty = IceType_i8;
|
| - static const char *TypeName;
|
| - static const char *AsmTag;
|
| - static const char *PrintfString;
|
| -};
|
| -const char *PoolTypeConverter<uint8_t>::TypeName = "i8";
|
| -const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte";
|
| -const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x";
|
| -
|
| -template <typename T>
|
| -void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) {
|
| - if (!ALLOW_DUMP)
|
| - return;
|
| - Ostream &Str = Ctx->getStrEmit();
|
| - Type Ty = T::Ty;
|
| - SizeT Align = typeAlignInBytes(Ty);
|
| - ConstantList Pool = Ctx->getConstantPool(Ty);
|
| -
|
| - Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
|
| - << "\n";
|
| - Str << "\t.align\t" << Align << "\n";
|
| - for (Constant *C : Pool) {
|
| - if (!C->getShouldBePooled())
|
| - continue;
|
| - typename T::IceType *Const = llvm::cast<typename T::IceType>(C);
|
| - typename T::IceType::PrimType Value = Const->getValue();
|
| - // Use memcpy() to copy bits from Value into RawValue in a way
|
| - // that avoids breaking strict-aliasing rules.
|
| - typename T::PrimitiveIntType RawValue;
|
| - memcpy(&RawValue, &Value, sizeof(Value));
|
| - char buf[30];
|
| - int CharsPrinted =
|
| - snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
|
| - assert(CharsPrinted >= 0 &&
|
| - (size_t)CharsPrinted < llvm::array_lengthof(buf));
|
| - (void)CharsPrinted; // avoid warnings if asserts are disabled
|
| - Const->emitPoolLabel(Str);
|
| - Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " "
|
| - << Value << "\n";
|
| - }
|
| -}
|
| -
|
| -void TargetDataX8632::lowerConstants() {
|
| - if (Ctx->getFlags().getDisableTranslation())
|
| - return;
|
| - // No need to emit constants from the int pool since (for x86) they
|
| - // are embedded as immediates in the instructions, just emit float/double.
|
| - switch (Ctx->getFlags().getOutFileType()) {
|
| - case FT_Elf: {
|
| - ELFObjectWriter *Writer = Ctx->getObjectWriter();
|
| -
|
| - Writer->writeConstantPool<ConstantInteger32>(IceType_i8);
|
| - Writer->writeConstantPool<ConstantInteger32>(IceType_i16);
|
| - Writer->writeConstantPool<ConstantInteger32>(IceType_i32);
|
| -
|
| - Writer->writeConstantPool<ConstantFloat>(IceType_f32);
|
| - Writer->writeConstantPool<ConstantDouble>(IceType_f64);
|
| - } break;
|
| - case FT_Asm:
|
| - case FT_Iasm: {
|
| - OstreamLocker L(Ctx);
|
| -
|
| - emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx);
|
| - emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx);
|
| - emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx);
|
| -
|
| - emitConstantPool<PoolTypeConverter<float>>(Ctx);
|
| - emitConstantPool<PoolTypeConverter<double>>(Ctx);
|
| - } break;
|
| - }
|
| -}
|
| -
|
| -TargetHeaderX8632::TargetHeaderX8632(GlobalContext *Ctx)
|
| - : TargetHeaderLowering(Ctx) {}
|
| -
|
| // Randomize or pool an Immediate.
|
| -Operand *TargetX8632::randomizeOrPoolImmediate(Constant *Immediate,
|
| - int32_t RegNum) {
|
| +template <class Machine>
|
| +Operand *TargetX86Base<Machine>::randomizeOrPoolImmediate(Constant *Immediate,
|
| + int32_t RegNum) {
|
| assert(llvm::isa<ConstantInteger32>(Immediate) ||
|
| llvm::isa<ConstantRelocatable>(Immediate));
|
| if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
|
| @@ -5602,9 +5382,10 @@ Operand *TargetX8632::randomizeOrPoolImmediate(Constant *Immediate,
|
| return Immediate;
|
| }
|
|
|
| +template <class Machine>
|
| OperandX8632Mem *
|
| -TargetX8632::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
|
| - int32_t RegNum) {
|
| +TargetX86Base<Machine>::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
|
| + int32_t RegNum) {
|
| assert(MemOperand);
|
| if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
|
| RandomizationPoolingPaused == true) {
|
| @@ -5629,9 +5410,8 @@ TargetX8632::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
|
| // TO:
|
| // insert: lea offset+cookie[base], RegTemp
|
| // => -cookie[RegTemp, index, shift]
|
| - uint32_t Value =
|
| - llvm::dyn_cast<ConstantInteger32>(MemOperand->getOffset())
|
| - ->getValue();
|
| + uint32_t Value = llvm::dyn_cast<ConstantInteger32>(
|
| + MemOperand->getOffset())->getValue();
|
| uint32_t Cookie = Ctx->getRandomizationCookie();
|
| Constant *Mask1 = Ctx->getConstantInt(
|
| MemOperand->getOffset()->getType(), Cookie + Value);
|
| @@ -5717,4 +5497,7 @@ TargetX8632::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand,
|
| return MemOperand;
|
| }
|
|
|
| +} // end of namespace X86Internal
|
| } // end of namespace Ice
|
| +
|
| +#endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
|
|
|