diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 |
| commit | b915e9e0fc85ba6f398b3fab0db6a81a8913af94 (patch) | |
| tree | 98b8f811c7aff2547cab8642daf372d6c59502fb /include/llvm/CodeGen/SelectionDAGNodes.h | |
| parent | 6421cca32f69ac849537a3cff78c352195e99f1b (diff) | |
Notes
Diffstat (limited to 'include/llvm/CodeGen/SelectionDAGNodes.h')
| -rw-r--r-- | include/llvm/CodeGen/SelectionDAGNodes.h | 450 |
1 files changed, 299 insertions, 151 deletions
diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index cfcc4117f93b6..d4b7170eac3c5 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -19,23 +19,37 @@ #ifndef LLVM_CODEGEN_SELECTIONDAGNODES_H #define LLVM_CODEGEN_SELECTIONDAGNODES_H +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> #include <cassert> +#include <climits> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <iterator> +#include <string> +#include <tuple> namespace llvm { @@ -44,12 +58,9 @@ class GlobalValue; class MachineBasicBlock; class MachineConstantPoolValue; class SDNode; -class HandleSDNode; class Value; class MCSymbol; template <typename T> struct DenseMapInfo; -template <typename T> struct simplify_type; -template <typename T> struct ilist_traits; void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr, bool force = false); @@ -64,6 +75,7 @@ struct SDVTList { }; namespace ISD { + /// Node predicates /// If N is a BUILD_VECTOR node whose elements are all the same constant or @@ -89,7 +101,8 @@ namespace ISD { /// Return true if the node has at least one operand and all operands of the /// specified node are ISD::UNDEF. bool allOperandsUndef(const SDNode *N); -} // end llvm:ISD namespace + +} // end namespace ISD //===----------------------------------------------------------------------===// /// Unlike LLVM values, Selection DAG nodes may return multiple @@ -107,6 +120,7 @@ class SDValue { SDNode *Node; // The node defining the value we are using. unsigned ResNo; // Which return value of the node we are using. + public: SDValue() : Node(nullptr), ResNo(0) {} SDValue(SDNode *node, unsigned resno); @@ -188,29 +202,30 @@ public: inline bool hasOneUse() const; }; - template<> struct DenseMapInfo<SDValue> { static inline SDValue getEmptyKey() { SDValue V; V.ResNo = -1U; return V; } + static inline SDValue getTombstoneKey() { SDValue V; V.ResNo = -2U; return V; } + static unsigned getHashValue(const SDValue &Val) { return ((unsigned)((uintptr_t)Val.getNode() >> 4) ^ (unsigned)((uintptr_t)Val.getNode() >> 9)) + Val.getResNo(); } + static bool isEqual(const SDValue &LHS, const SDValue &RHS) { return LHS == RHS; } }; template <> struct isPodLike<SDValue> { static const bool value = true; }; - /// Allow casting operators to work directly on /// SDValues as if they were SDNode*'s. template<> struct simplify_type<SDValue> { @@ -244,7 +259,7 @@ class SDUse { void operator=(const SDUse &U) = delete; public: - SDUse() : Val(), User(nullptr), Prev(nullptr), Next(nullptr) {} + SDUse() : User(nullptr), Prev(nullptr), Next(nullptr) {} /// Normally SDUse will just implicitly convert to an SDValue that it holds. operator const SDValue&() const { return Val; } @@ -372,14 +387,6 @@ public: bool hasAllowReciprocal() const { return AllowReciprocal; } bool hasVectorReduction() const { return VectorReduction; } - /// Return a raw encoding of the flags. - /// This function should only be used to add data to the NodeID value. - unsigned getRawFlags() const { - return (NoUnsignedWrap << 0) | (NoSignedWrap << 1) | (Exact << 2) | - (UnsafeAlgebra << 3) | (NoNaNs << 4) | (NoInfs << 5) | - (NoSignedZeros << 6) | (AllowReciprocal << 7); - } - /// Clear any flags in this flag set that aren't also set in Flags. void intersectWith(const SDNodeFlags *Flags) { NoUnsignedWrap &= Flags->NoUnsignedWrap; @@ -400,15 +407,90 @@ private: /// The operation that this node performs. int16_t NodeType; - /// This tracks whether this node has one or more dbg_value - /// nodes corresponding to it. - uint16_t HasDebugValue : 1; - protected: - /// This member is defined by this class, but is not used for - /// anything. Subclasses can use it to hold whatever state they find useful. - /// This field is initialized to zero by the ctor. - uint16_t SubclassData : 15; + // We define a set of mini-helper classes to help us interpret the bits in our + // SubclassData. These are designed to fit within a uint16_t so they pack + // with NodeType. + + class SDNodeBitfields { + friend class SDNode; + friend class MemIntrinsicSDNode; + friend class MemSDNode; + + uint16_t HasDebugValue : 1; + uint16_t IsMemIntrinsic : 1; + }; + enum { NumSDNodeBits = 2 }; + + class ConstantSDNodeBitfields { + friend class ConstantSDNode; + + uint16_t : NumSDNodeBits; + + uint16_t IsOpaque : 1; + }; + + class MemSDNodeBitfields { + friend class MemSDNode; + friend class MemIntrinsicSDNode; + friend class AtomicSDNode; + + uint16_t : NumSDNodeBits; + + uint16_t IsVolatile : 1; + uint16_t IsNonTemporal : 1; + uint16_t IsDereferenceable : 1; + uint16_t IsInvariant : 1; + }; + enum { NumMemSDNodeBits = NumSDNodeBits + 4 }; + + class LSBaseSDNodeBitfields { + friend class LSBaseSDNode; + uint16_t : NumMemSDNodeBits; + + uint16_t AddressingMode : 3; // enum ISD::MemIndexedMode + }; + enum { NumLSBaseSDNodeBits = NumMemSDNodeBits + 3 }; + + class LoadSDNodeBitfields { + friend class LoadSDNode; + friend class MaskedLoadSDNode; + + uint16_t : NumLSBaseSDNodeBits; + + uint16_t ExtTy : 2; // enum ISD::LoadExtType + uint16_t IsExpanding : 1; + }; + + class StoreSDNodeBitfields { + friend class StoreSDNode; + friend class MaskedStoreSDNode; + + uint16_t : NumLSBaseSDNodeBits; + + uint16_t IsTruncating : 1; + uint16_t IsCompressing : 1; + }; + + union { + char RawSDNodeBits[sizeof(uint16_t)]; + SDNodeBitfields SDNodeBits; + ConstantSDNodeBitfields ConstantSDNodeBits; + MemSDNodeBitfields MemSDNodeBits; + LSBaseSDNodeBitfields LSBaseSDNodeBits; + LoadSDNodeBitfields LoadSDNodeBits; + StoreSDNodeBitfields StoreSDNodeBits; + }; + + // RawSDNodeBits must cover the entirety of the union. This means that all of + // the union's members must have size <= RawSDNodeBits. We write the RHS as + // "2" instead of sizeof(RawSDNodeBits) because MSVC can't handle the latter. + static_assert(sizeof(SDNodeBitfields) <= 2, "field too wide"); + static_assert(sizeof(ConstantSDNodeBitfields) <= 2, "field too wide"); + static_assert(sizeof(MemSDNodeBitfields) <= 2, "field too wide"); + static_assert(sizeof(LSBaseSDNodeBitfields) <= 2, "field too wide"); + static_assert(sizeof(LoadSDNodeBitfields) <= 4, "field too wide"); + static_assert(sizeof(StoreSDNodeBitfields) <= 2, "field too wide"); private: /// Unique id per SDNode in the DAG. @@ -441,7 +523,6 @@ private: static const EVT *getValueTypeList(EVT VT); friend class SelectionDAG; - friend struct ilist_traits<SDNode>; // TODO: unfriend HandleSDNode once we fix its operand handling. friend class HandleSDNode; @@ -481,7 +562,8 @@ public: /// proper classof relationship. bool isMemIntrinsic() const { return (NodeType == ISD::INTRINSIC_W_CHAIN || - NodeType == ISD::INTRINSIC_VOID) && ((SubclassData >> 13) & 1); + NodeType == ISD::INTRINSIC_VOID) && + SDNodeBits.IsMemIntrinsic; } /// Test if this node has a post-isel opcode, directly @@ -496,11 +578,8 @@ public: return ~NodeType; } - /// Get this bit. - bool getHasDebugValue() const { return HasDebugValue; } - - /// Set this bit. - void setHasDebugValue(bool b) { HasDebugValue = b; } + bool getHasDebugValue() const { return SDNodeBits.HasDebugValue; } + void setHasDebugValue(bool b) { SDNodeBits.HasDebugValue = b; } /// Return true if there are no uses of this node. bool use_empty() const { return UseList == nullptr; } @@ -538,9 +617,11 @@ public: class use_iterator : public std::iterator<std::forward_iterator_tag, SDUse, ptrdiff_t> { SDUse *Op; - explicit use_iterator(SDUse *op) : Op(op) { - } + friend class SDNode; + + explicit use_iterator(SDUse *op) : Op(op) {} + public: typedef std::iterator<std::forward_iterator_tag, SDUse, ptrdiff_t>::reference reference; @@ -668,6 +749,7 @@ public: } typedef SDUse* op_iterator; + op_iterator op_begin() const { return OperandList; } op_iterator op_end() const { return OperandList+NumOperands; } ArrayRef<SDUse> ops() const { return makeArrayRef(op_begin(), op_end()); } @@ -767,7 +849,6 @@ public: void printrWithDepth(raw_ostream &O, const SelectionDAG *G = nullptr, unsigned depth = 100) const; - /// Dump this node, for debugging. void dump() const; @@ -815,10 +896,10 @@ protected: /// SDNodes are created without any operands, and never own the operand /// storage. To add operands, see SelectionDAG::createOperands. SDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs) - : NodeType(Opc), HasDebugValue(false), SubclassData(0), NodeId(-1), - OperandList(nullptr), ValueList(VTs.VTs), UseList(nullptr), - NumOperands(0), NumValues(VTs.NumVTs), IROrder(Order), + : NodeType(Opc), NodeId(-1), OperandList(nullptr), ValueList(VTs.VTs), + UseList(nullptr), NumOperands(0), NumValues(VTs.NumVTs), IROrder(Order), debugLoc(std::move(dl)) { + memset(&RawSDNodeBits, 0, sizeof(RawSDNodeBits)); assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); assert(NumValues == VTs.NumVTs && "NumValues wasn't wide enough for its operands!"); @@ -851,16 +932,19 @@ public: if (I) DL = I->getDebugLoc(); } + unsigned getIROrder() const { return IROrder; } const DebugLoc &getDebugLoc() const { return DL; } }; - // Define inline functions from the SDValue class. inline SDValue::SDValue(SDNode *node, unsigned resno) : Node(node), ResNo(resno) { - assert((!Node || ResNo < Node->getNumValues()) && + // Explicitly check for !ResNo to avoid use-after-free, because there are + // callers that use SDValue(N, 0) with a deleted N to indicate successful + // combines. + assert((!Node || !ResNo || ResNo < Node->getNumValues()) && "Invalid result number for the given node!"); assert(ResNo < -2U && "Cannot use result numbers reserved for DenseMaps."); } @@ -868,48 +952,63 @@ inline SDValue::SDValue(SDNode *node, unsigned resno) inline unsigned SDValue::getOpcode() const { return Node->getOpcode(); } + inline EVT SDValue::getValueType() const { return Node->getValueType(ResNo); } + inline unsigned SDValue::getNumOperands() const { return Node->getNumOperands(); } + inline const SDValue &SDValue::getOperand(unsigned i) const { return Node->getOperand(i); } + inline uint64_t SDValue::getConstantOperandVal(unsigned i) const { return Node->getConstantOperandVal(i); } + inline bool SDValue::isTargetOpcode() const { return Node->isTargetOpcode(); } + inline bool SDValue::isTargetMemoryOpcode() const { return Node->isTargetMemoryOpcode(); } + inline bool SDValue::isMachineOpcode() const { return Node->isMachineOpcode(); } + inline unsigned SDValue::getMachineOpcode() const { return Node->getMachineOpcode(); } + inline bool SDValue::isUndef() const { return Node->isUndef(); } + inline bool SDValue::use_empty() const { return !Node->hasAnyUseOfValue(ResNo); } + inline bool SDValue::hasOneUse() const { return Node->hasNUsesOfValue(1, ResNo); } + inline const DebugLoc &SDValue::getDebugLoc() const { return Node->getDebugLoc(); } + inline void SDValue::dump() const { return Node->dump(); } + inline void SDValue::dumpr() const { return Node->dumpr(); } + // Define inline functions from the SDUse class. inline void SDUse::set(const SDValue &V) { @@ -956,9 +1055,11 @@ static bool isBinOpWithFlags(unsigned Opcode) { class BinaryWithFlagsSDNode : public SDNode { public: SDNodeFlags Flags; + BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, const SDNodeFlags &NodeFlags) : SDNode(Opc, Order, dl, VTs), Flags(NodeFlags) {} + static bool classof(const SDNode *N) { return isBinOpWithFlags(N->getOpcode()); } @@ -970,6 +1071,7 @@ public: /// the AllNodes list. class HandleSDNode : public SDNode { SDUse Op; + public: explicit HandleSDNode(SDValue X) : SDNode(ISD::HANDLENODE, 0, DebugLoc(), getSDVTList(MVT::Other)) { @@ -987,6 +1089,7 @@ public: OperandList = &Op; } ~HandleSDNode(); + const SDValue &getValue() const { return Op; } }; @@ -1032,25 +1135,27 @@ public: return MMO->getAlignment(); } - /// Return the SubclassData value, which contains an + /// Return the SubclassData value, without HasDebugValue. This contains an /// encoding of the volatile flag, as well as bits used by subclasses. This /// function should only be used to compute a FoldingSetNodeID value. + /// The HasDebugValue bit is masked out because CSE map needs to match + /// nodes with debug info with nodes without debug info. unsigned getRawSubclassData() const { - return SubclassData; + uint16_t Data; + union { + char RawSDNodeBits[sizeof(uint16_t)]; + SDNodeBitfields SDNodeBits; + }; + memcpy(&RawSDNodeBits, &this->RawSDNodeBits, sizeof(this->RawSDNodeBits)); + SDNodeBits.HasDebugValue = 0; + memcpy(&Data, &RawSDNodeBits, sizeof(RawSDNodeBits)); + return Data; } - // We access subclass data here so that we can check consistency - // with MachineMemOperand information. - bool isVolatile() const { return (SubclassData >> 5) & 1; } - bool isNonTemporal() const { return (SubclassData >> 6) & 1; } - bool isInvariant() const { return (SubclassData >> 7) & 1; } - - AtomicOrdering getOrdering() const { - return AtomicOrdering((SubclassData >> 8) & 15); - } - SynchronizationScope getSynchScope() const { - return SynchronizationScope((SubclassData >> 12) & 1); - } + bool isVolatile() const { return MemSDNodeBits.IsVolatile; } + bool isNonTemporal() const { return MemSDNodeBits.IsNonTemporal; } + bool isDereferenceable() const { return MemSDNodeBits.IsDereferenceable; } + bool isInvariant() const { return MemSDNodeBits.IsInvariant; } // Returns the offset from the location of the access. int64_t getSrcValueOffset() const { return MMO->getOffset(); } @@ -1061,6 +1166,14 @@ public: /// Returns the Ranges that describes the dereference. const MDNode *getRanges() const { return MMO->getRanges(); } + /// Return the synchronization scope for this memory operation. + SynchronizationScope getSynchScope() const { return MMO->getSynchScope(); } + + /// Return the atomic ordering requirements for this memory operation. For + /// cmpxchg atomic operations, return the atomic ordering requirements when + /// store occurs. + AtomicOrdering getOrdering() const { return MMO->getOrdering(); } + /// Return the type of the in-memory value. EVT getMemoryVT() const { return MemoryVT; } @@ -1123,57 +1236,27 @@ public: /// This is an SDNode representing atomic operations. class AtomicSDNode : public MemSDNode { - /// For cmpxchg instructions, the ordering requirements when a store does not - /// occur. - AtomicOrdering FailureOrdering; - - void InitAtomic(AtomicOrdering SuccessOrdering, - AtomicOrdering FailureOrdering, - SynchronizationScope SynchScope) { - // This must match encodeMemSDNodeFlags() in SelectionDAG.cpp. - assert((AtomicOrdering)((unsigned)SuccessOrdering & 15) == - SuccessOrdering && - "Ordering may not require more than 4 bits!"); - assert((AtomicOrdering)((unsigned)FailureOrdering & 15) == - FailureOrdering && - "Ordering may not require more than 4 bits!"); - assert((SynchScope & 1) == SynchScope && - "SynchScope may not require more than 1 bit!"); - SubclassData |= (unsigned)SuccessOrdering << 8; - SubclassData |= SynchScope << 12; - this->FailureOrdering = FailureOrdering; - assert(getSuccessOrdering() == SuccessOrdering && - "Ordering encoding error!"); - assert(getFailureOrdering() == FailureOrdering && - "Ordering encoding error!"); - assert(getSynchScope() == SynchScope && "Synch-scope encoding error!"); - } - public: AtomicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTL, - EVT MemVT, MachineMemOperand *MMO, - AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, - SynchronizationScope SynchScope) - : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { - InitAtomic(SuccessOrdering, FailureOrdering, SynchScope); - } + EVT MemVT, MachineMemOperand *MMO) + : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) {} const SDValue &getBasePtr() const { return getOperand(1); } const SDValue &getVal() const { return getOperand(2); } - AtomicOrdering getSuccessOrdering() const { - return getOrdering(); + /// Returns true if this SDNode represents cmpxchg atomic operation, false + /// otherwise. + bool isCompareAndSwap() const { + unsigned Op = getOpcode(); + return Op == ISD::ATOMIC_CMP_SWAP || + Op == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS; } - // Not quite enough room in SubclassData for everything, so failure gets its - // own field. + /// For cmpxchg atomic operations, return the atomic ordering requirements + /// when store does not occur. AtomicOrdering getFailureOrdering() const { - return FailureOrdering; - } - - bool isCompareAndSwap() const { - unsigned Op = getOpcode(); - return Op == ISD::ATOMIC_CMP_SWAP || Op == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS; + assert(isCompareAndSwap() && "Must be cmpxchg operation"); + return MMO->getFailureOrdering(); } // Methods to support isa and dyn_cast @@ -1205,7 +1288,7 @@ public: MemIntrinsicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO) : MemSDNode(Opc, Order, dl, VTs, MemoryVT, MMO) { - SubclassData |= 1u << 13; + SDNodeBits.IsMemIntrinsic = true; } // Methods to support isa and dyn_cast @@ -1230,8 +1313,10 @@ class ShuffleVectorSDNode : public SDNode { // The memory for Mask is owned by the SelectionDAG's OperandAllocator, and // is freed when the SelectionDAG object is destroyed. const int *Mask; + protected: friend class SelectionDAG; + ShuffleVectorSDNode(EVT VT, unsigned Order, const DebugLoc &dl, const int *M) : SDNode(ISD::VECTOR_SHUFFLE, Order, dl, getSDVTList(VT)), Mask(M) {} @@ -1240,12 +1325,14 @@ public: EVT VT = getValueType(0); return makeArrayRef(Mask, VT.getVectorNumElements()); } + int getMaskElt(unsigned Idx) const { assert(Idx < getValueType(0).getVectorNumElements() && "Idx out of range!"); return Mask[Idx]; } bool isSplat() const { return isSplatMask(Mask, getValueType(0)); } + int getSplatIndex() const { assert(isSplat() && "Cannot get splat index for non-splat!"); EVT VT = getValueType(0); @@ -1255,6 +1342,7 @@ public: } llvm_unreachable("Splat with all undef indices?"); } + static bool isSplatMask(const int *Mask, EVT VT); /// Change values in a shuffle permute mask assuming @@ -1279,16 +1367,18 @@ public: class ConstantSDNode : public SDNode { const ConstantInt *Value; + friend class SelectionDAG; + ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val, const DebugLoc &DL, EVT VT) : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DL, getSDVTList(VT)), Value(val) { - SubclassData |= (uint16_t)isOpaque; + ConstantSDNodeBits.IsOpaque = isOpaque; } -public: +public: const ConstantInt *getConstantIntValue() const { return Value; } const APInt &getAPIntValue() const { return Value->getValue(); } uint64_t getZExtValue() const { return Value->getZExtValue(); } @@ -1298,7 +1388,7 @@ public: bool isNullValue() const { return Value->isNullValue(); } bool isAllOnesValue() const { return Value->isAllOnesValue(); } - bool isOpaque() const { return SubclassData & 1; } + bool isOpaque() const { return ConstantSDNodeBits.IsOpaque; } static bool classof(const SDNode *N) { return N->getOpcode() == ISD::Constant || @@ -1308,7 +1398,9 @@ public: class ConstantFPSDNode : public SDNode { const ConstantFP *Value; + friend class SelectionDAG; + ConstantFPSDNode(bool isTarget, const ConstantFP *val, const DebugLoc &DL, EVT VT) : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, 0, DL, @@ -1316,7 +1408,6 @@ class ConstantFPSDNode : public SDNode { Value(val) {} public: - const APFloat& getValueAPF() const { return Value->getValueAPF(); } const ConstantFP *getConstantFPValue() const { return Value; } @@ -1359,16 +1450,26 @@ public: /// Returns true if \p V is a constant integer zero. bool isNullConstant(SDValue V); + /// Returns true if \p V is an FP constant with a value of positive zero. bool isNullFPConstant(SDValue V); + /// Returns true if \p V is an integer constant with all bits set. bool isAllOnesConstant(SDValue V); + /// Returns true if \p V is a constant integer one. bool isOneConstant(SDValue V); + /// Returns true if \p V is a bitwise not operation. Assumes that an all ones /// constant is canonicalized to be operand 1. bool isBitwiseNot(SDValue V); +/// Returns the SDNode if it is a constant splat BuildVector or constant int. +ConstantSDNode *isConstOrConstSplat(SDValue V); + +/// Returns the SDNode if it is a constant splat BuildVector or constant float. +ConstantFPSDNode *isConstOrConstSplatFP(SDValue V); + class GlobalAddressSDNode : public SDNode { const GlobalValue *TheGlobal; int64_t Offset; @@ -1379,7 +1480,6 @@ class GlobalAddressSDNode : public SDNode { unsigned char TargetFlags); public: - const GlobalValue *getGlobal() const { return TheGlobal; } int64_t getOffset() const { return Offset; } unsigned char getTargetFlags() const { return TargetFlags; } @@ -1396,13 +1496,15 @@ public: class FrameIndexSDNode : public SDNode { int FI; + friend class SelectionDAG; + FrameIndexSDNode(int fi, EVT VT, bool isTarg) : SDNode(isTarg ? ISD::TargetFrameIndex : ISD::FrameIndex, 0, DebugLoc(), getSDVTList(VT)), FI(fi) { } -public: +public: int getIndex() const { return FI; } static bool classof(const SDNode *N) { @@ -1414,13 +1516,15 @@ public: class JumpTableSDNode : public SDNode { int JTI; unsigned char TargetFlags; + friend class SelectionDAG; + JumpTableSDNode(int jti, EVT VT, bool isTarg, unsigned char TF) : SDNode(isTarg ? ISD::TargetJumpTable : ISD::JumpTable, 0, DebugLoc(), getSDVTList(VT)), JTI(jti), TargetFlags(TF) { } -public: +public: int getIndex() const { return JTI; } unsigned char getTargetFlags() const { return TargetFlags; } @@ -1438,7 +1542,9 @@ class ConstantPoolSDNode : public SDNode { int Offset; // It's a MachineConstantPoolValue if top bit is set. unsigned Alignment; // Minimum alignment requirement of CP (not log2 value). unsigned char TargetFlags; + friend class SelectionDAG; + ConstantPoolSDNode(bool isTarget, const Constant *c, EVT VT, int o, unsigned Align, unsigned char TF) : SDNode(isTarget ? ISD::TargetConstantPool : ISD::ConstantPool, 0, @@ -1447,6 +1553,7 @@ class ConstantPoolSDNode : public SDNode { assert(Offset >= 0 && "Offset is too large"); Val.ConstVal = c; } + ConstantPoolSDNode(bool isTarget, MachineConstantPoolValue *v, EVT VT, int o, unsigned Align, unsigned char TF) : SDNode(isTarget ? ISD::TargetConstantPool : ISD::ConstantPool, 0, @@ -1456,8 +1563,8 @@ class ConstantPoolSDNode : public SDNode { Val.MachineCPVal = v; Offset |= 1 << (sizeof(unsigned)*CHAR_BIT-1); } -public: +public: bool isMachineConstantPoolEntry() const { return Offset < 0; } @@ -1494,13 +1601,13 @@ class TargetIndexSDNode : public SDNode { unsigned char TargetFlags; int Index; int64_t Offset; + friend class SelectionDAG; -public: +public: TargetIndexSDNode(int Idx, EVT VT, int64_t Ofs, unsigned char TF) : SDNode(ISD::TargetIndex, 0, DebugLoc(), getSDVTList(VT)), TargetFlags(TF), Index(Idx), Offset(Ofs) {} -public: unsigned char getTargetFlags() const { return TargetFlags; } int getIndex() const { return Index; } @@ -1513,15 +1620,17 @@ public: class BasicBlockSDNode : public SDNode { MachineBasicBlock *MBB; + friend class SelectionDAG; + /// Debug info is meaningful and potentially useful here, but we create /// blocks out of order when they're jumped to, which makes it a bit /// harder. Let's see if we need it first. explicit BasicBlockSDNode(MachineBasicBlock *mbb) : SDNode(ISD::BasicBlock, 0, DebugLoc(), getSDVTList(MVT::Other)), MBB(mbb) {} -public: +public: MachineBasicBlock *getBasicBlock() const { return MBB; } static bool classof(const SDNode *N) { @@ -1533,6 +1642,7 @@ public: class BuildVectorSDNode : public SDNode { // These are constructed as SDNodes and then cast to BuildVectorSDNodes. explicit BuildVectorSDNode() = delete; + public: /// Check if this is a constant splat, and if so, find the /// smallest element size that splats the vector. If MinSplatBits is @@ -1591,7 +1701,9 @@ public: /// class SrcValueSDNode : public SDNode { const Value *V; + friend class SelectionDAG; + /// Create a SrcValue for a general value. explicit SrcValueSDNode(const Value *v) : SDNode(ISD::SRCVALUE, 0, DebugLoc(), getSDVTList(MVT::Other)), V(v) {} @@ -1607,12 +1719,14 @@ public: class MDNodeSDNode : public SDNode { const MDNode *MD; + friend class SelectionDAG; + explicit MDNodeSDNode(const MDNode *md) : SDNode(ISD::MDNODE_SDNODE, 0, DebugLoc(), getSDVTList(MVT::Other)), MD(md) {} -public: +public: const MDNode *getMD() const { return MD; } static bool classof(const SDNode *N) { @@ -1622,12 +1736,13 @@ public: class RegisterSDNode : public SDNode { unsigned Reg; + friend class SelectionDAG; + RegisterSDNode(unsigned reg, EVT VT) - : SDNode(ISD::Register, 0, DebugLoc(), getSDVTList(VT)), Reg(reg) { - } -public: + : SDNode(ISD::Register, 0, DebugLoc(), getSDVTList(VT)), Reg(reg) {} +public: unsigned getReg() const { return Reg; } static bool classof(const SDNode *N) { @@ -1638,12 +1753,14 @@ public: class RegisterMaskSDNode : public SDNode { // The memory for RegMask is not owned by the node. const uint32_t *RegMask; + friend class SelectionDAG; + RegisterMaskSDNode(const uint32_t *mask) : SDNode(ISD::RegisterMask, 0, DebugLoc(), getSDVTList(MVT::Untyped)), RegMask(mask) {} -public: +public: const uint32_t *getRegMask() const { return RegMask; } static bool classof(const SDNode *N) { @@ -1655,12 +1772,15 @@ class BlockAddressSDNode : public SDNode { const BlockAddress *BA; int64_t Offset; unsigned char TargetFlags; + friend class SelectionDAG; + BlockAddressSDNode(unsigned NodeTy, EVT VT, const BlockAddress *ba, int64_t o, unsigned char Flags) : SDNode(NodeTy, 0, DebugLoc(), getSDVTList(VT)), BA(ba), Offset(o), TargetFlags(Flags) { } + public: const BlockAddress *getBlockAddress() const { return BA; } int64_t getOffset() const { return Offset; } @@ -1674,7 +1794,9 @@ public: class EHLabelSDNode : public SDNode { MCSymbol *Label; + friend class SelectionDAG; + EHLabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) {} @@ -1691,12 +1813,12 @@ class ExternalSymbolSDNode : public SDNode { unsigned char TargetFlags; friend class SelectionDAG; + ExternalSymbolSDNode(bool isTarget, const char *Sym, unsigned char TF, EVT VT) : SDNode(isTarget ? ISD::TargetExternalSymbol : ISD::ExternalSymbol, - 0, DebugLoc(), getSDVTList(VT)), Symbol(Sym), TargetFlags(TF) { - } -public: + 0, DebugLoc(), getSDVTList(VT)), Symbol(Sym), TargetFlags(TF) {} +public: const char *getSymbol() const { return Symbol; } unsigned char getTargetFlags() const { return TargetFlags; } @@ -1723,13 +1845,14 @@ public: class CondCodeSDNode : public SDNode { ISD::CondCode Condition; + friend class SelectionDAG; + explicit CondCodeSDNode(ISD::CondCode Cond) : SDNode(ISD::CONDCODE, 0, DebugLoc(), getSDVTList(MVT::Other)), - Condition(Cond) { - } -public: + Condition(Cond) {} +public: ISD::CondCode get() const { return Condition; } static bool classof(const SDNode *N) { @@ -1741,7 +1864,9 @@ public: /// future and most targets don't support it. class CvtRndSatSDNode : public SDNode { ISD::CvtCode CvtCode; + friend class SelectionDAG; + explicit CvtRndSatSDNode(EVT VT, unsigned Order, const DebugLoc &dl, ISD::CvtCode Code) : SDNode(ISD::CONVERT_RNDSAT, Order, dl, getSDVTList(VT)), CvtCode(Code) { @@ -1759,13 +1884,14 @@ public: /// to parameterize some operations. class VTSDNode : public SDNode { EVT ValueType; + friend class SelectionDAG; + explicit VTSDNode(EVT VT) : SDNode(ISD::VALUETYPE, 0, DebugLoc(), getSDVTList(MVT::Other)), - ValueType(VT) { - } -public: + ValueType(VT) {} +public: EVT getVT() const { return ValueType; } static bool classof(const SDNode *N) { @@ -1780,8 +1906,8 @@ public: SDVTList VTs, ISD::MemIndexedMode AM, EVT MemVT, MachineMemOperand *MMO) : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { - SubclassData |= AM << 2; - assert(getAddressingMode() == AM && "MemIndexedMode encoding error!"); + LSBaseSDNodeBits.AddressingMode = AM; + assert(getAddressingMode() == AM && "Value truncated"); } const SDValue &getOffset() const { @@ -1791,7 +1917,7 @@ public: /// Return the addressing mode for this load or store: /// unindexed, pre-inc, pre-dec, post-inc, or post-dec. ISD::MemIndexedMode getAddressingMode() const { - return ISD::MemIndexedMode((SubclassData >> 2) & 7); + return static_cast<ISD::MemIndexedMode>(LSBaseSDNodeBits.AddressingMode); } /// Return true if this is a pre/post inc/dec load/store. @@ -1809,21 +1935,21 @@ public: /// This class is used to represent ISD::LOAD nodes. class LoadSDNode : public LSBaseSDNode { friend class SelectionDAG; + LoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::MemIndexedMode AM, ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) : LSBaseSDNode(ISD::LOAD, Order, dl, VTs, AM, MemVT, MMO) { - SubclassData |= (unsigned short)ETy; - assert(getExtensionType() == ETy && "LoadExtType encoding error!"); + LoadSDNodeBits.ExtTy = ETy; assert(readMem() && "Load MachineMemOperand is not a load!"); assert(!writeMem() && "Load MachineMemOperand is a store!"); } -public: +public: /// Return whether this is a plain node, /// or one of the varieties of value-extending loads. ISD::LoadExtType getExtensionType() const { - return ISD::LoadExtType(SubclassData & 3); + return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy); } const SDValue &getBasePtr() const { return getOperand(1); } @@ -1837,21 +1963,21 @@ public: /// This class is used to represent ISD::STORE nodes. class StoreSDNode : public LSBaseSDNode { friend class SelectionDAG; + StoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::MemIndexedMode AM, bool isTrunc, EVT MemVT, MachineMemOperand *MMO) : LSBaseSDNode(ISD::STORE, Order, dl, VTs, AM, MemVT, MMO) { - SubclassData |= (unsigned short)isTrunc; - assert(isTruncatingStore() == isTrunc && "isTrunc encoding error!"); + StoreSDNodeBits.IsTruncating = isTrunc; assert(!readMem() && "Store MachineMemOperand is a load!"); assert(writeMem() && "Store MachineMemOperand is not a store!"); } -public: +public: /// Return true if the op does a truncation before store. /// For integers this is the same as doing a TRUNCATE and storing the result. /// For floats, it is the same as doing an FP_ROUND and storing the result. - bool isTruncatingStore() const { return SubclassData & 1; } + bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } const SDValue &getValue() const { return getOperand(1); } const SDValue &getBasePtr() const { return getOperand(2); } @@ -1866,6 +1992,7 @@ public: class MaskedLoadStoreSDNode : public MemSDNode { public: friend class SelectionDAG; + MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) @@ -1889,34 +2016,48 @@ class MaskedLoadSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, - ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) + ISD::LoadExtType ETy, bool IsExpanding, EVT MemVT, + MachineMemOperand *MMO) : MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, MemVT, MMO) { - SubclassData |= (unsigned short)ETy; + LoadSDNodeBits.ExtTy = ETy; + LoadSDNodeBits.IsExpanding = IsExpanding; } ISD::LoadExtType getExtensionType() const { - return ISD::LoadExtType(SubclassData & 3); + return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy); } + const SDValue &getSrc0() const { return getOperand(3); } static bool classof(const SDNode *N) { return N->getOpcode() == ISD::MLOAD; } + + bool isExpandingLoad() const { return LoadSDNodeBits.IsExpanding; } }; /// This class is used to represent an MSTORE node class MaskedStoreSDNode : public MaskedLoadStoreSDNode { - public: friend class SelectionDAG; + MaskedStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, - bool isTrunc, EVT MemVT, MachineMemOperand *MMO) + bool isTrunc, bool isCompressing, EVT MemVT, + MachineMemOperand *MMO) : MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, MemVT, MMO) { - SubclassData |= (unsigned short)isTrunc; + StoreSDNodeBits.IsTruncating = isTrunc; + StoreSDNodeBits.IsCompressing = isCompressing; } + /// Return true if the op does a truncation before store. /// For integers this is the same as doing a TRUNCATE and storing the result. /// For floats, it is the same as doing an FP_ROUND and storing the result. - bool isTruncatingStore() const { return SubclassData & 1; } + bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } + + /// Returns true if the op does a compression to the vector before storing. + /// The node contiguously stores the active elements (integers or floats) + /// in src (those with their respective bit set in writemask k) to unaligned + /// memory at base_addr. + bool isCompressingStore() const { return StoreSDNodeBits.IsCompressing; } const SDValue &getValue() const { return getOperand(3); } @@ -1931,6 +2072,7 @@ public: class MaskedGatherScatterSDNode : public MemSDNode { public: friend class SelectionDAG; + MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) @@ -1956,6 +2098,7 @@ public: class MaskedGatherSDNode : public MaskedGatherScatterSDNode { public: friend class SelectionDAG; + MaskedGatherSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) : MaskedGatherScatterSDNode(ISD::MGATHER, Order, dl, VTs, MemVT, MMO) {} @@ -1968,9 +2111,9 @@ public: /// This class is used to represent an MSCATTER node /// class MaskedScatterSDNode : public MaskedGatherScatterSDNode { - public: friend class SelectionDAG; + MaskedScatterSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) : MaskedGatherScatterSDNode(ISD::MSCATTER, Order, dl, VTs, MemVT, MMO) {} @@ -1989,6 +2132,7 @@ public: private: friend class SelectionDAG; + MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, SDVTList VTs) : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} @@ -2021,6 +2165,7 @@ class SDNodeIterator : public std::iterator<std::forward_iterator_tag, unsigned Operand; SDNodeIterator(const SDNode *N, unsigned Op) : Node(N), Operand(Op) {} + public: bool operator==(const SDNodeIterator& x) const { return Operand == x.Operand; @@ -2055,13 +2200,14 @@ public: }; template <> struct GraphTraits<SDNode*> { - typedef SDNode NodeType; + typedef SDNode *NodeRef; typedef SDNodeIterator ChildIteratorType; - static inline NodeType *getEntryNode(SDNode *N) { return N; } - static inline ChildIteratorType child_begin(NodeType *N) { + + static NodeRef getEntryNode(SDNode *N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { return SDNodeIterator::begin(N); } - static inline ChildIteratorType child_end(NodeType *N) { + static ChildIteratorType child_end(NodeRef N) { return SDNodeIterator::end(N); } }; @@ -2078,6 +2224,7 @@ typedef AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode, typedef GlobalAddressSDNode MostAlignedSDNode; namespace ISD { + /// Returns true if the specified node is a non-extending and unindexed load. inline bool isNormalLoad(const SDNode *N) { const LoadSDNode *Ld = dyn_cast<LoadSDNode>(N); @@ -2138,8 +2285,9 @@ namespace ISD { return isa<StoreSDNode>(N) && cast<StoreSDNode>(N)->getAddressingMode() == ISD::UNINDEXED; } -} -} // end llvm namespace +} // end namespace ISD + +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_SELECTIONDAGNODES_H |
