Index: include/llvm/IR/IntrinsicInst.h =================================================================== --- include/llvm/IR/IntrinsicInst.h +++ include/llvm/IR/IntrinsicInst.h @@ -213,12 +213,13 @@ } }; - /// This class represents atomic memcpy intrinsic - /// TODO: Integrate this class into MemIntrinsic hierarchy; for now this is - /// C&P of all methods from that hierarchy - class ElementUnorderedAtomicMemCpyInst : public IntrinsicInst { + /// Common base class for all memory intrinsics. Simply provides + /// common methods. + /// Written as CRTP to avoid a common base class amongst the + /// three atomicity hierarchies. + template class MemIntrinsicBase : public IntrinsicInst { private: - enum { ARG_DEST = 0, ARG_SOURCE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE = 3 }; + enum { ARG_DEST = 0, ARG_LENGTH = 2 }; public: Value *getRawDest() const { @@ -227,51 +228,21 @@ const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST); } Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); } - /// Return the arguments to the instruction. - Value *getRawSource() const { - return const_cast(getArgOperand(ARG_SOURCE)); - } - const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); } - Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); } - Value *getLength() const { return const_cast(getArgOperand(ARG_LENGTH)); } const Use &getLengthUse() const { return getArgOperandUse(ARG_LENGTH); } Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); } - bool isVolatile() const { return false; } - - Value *getRawElementSizeInBytes() const { - return const_cast(getArgOperand(ARG_ELEMENTSIZE)); - } - - ConstantInt *getElementSizeInBytesCst() const { - return cast(getRawElementSizeInBytes()); - } - - uint32_t getElementSizeInBytes() const { - return getElementSizeInBytesCst()->getZExtValue(); - } - /// This is just like getRawDest, but it strips off any cast - /// instructions that feed it, giving the original input. The returned - /// value is guaranteed to be a pointer. + /// instructions (including addrspacecast) that feed it, giving the + /// original input. The returned value is guaranteed to be a pointer. Value *getDest() const { return getRawDest()->stripPointerCasts(); } - /// This is just like getRawSource, but it strips off any cast - /// instructions that feed it, giving the original input. The returned - /// value is guaranteed to be a pointer. - Value *getSource() const { return getRawSource()->stripPointerCasts(); } - unsigned getDestAddressSpace() const { return cast(getRawDest()->getType())->getAddressSpace(); } - unsigned getSourceAddressSpace() const { - return cast(getRawSource()->getType())->getAddressSpace(); - } - /// Set the specified arguments of the instruction. void setDest(Value *Ptr) { assert(getRawDest()->getType() == Ptr->getType() && @@ -279,58 +250,20 @@ setArgOperand(ARG_DEST, Ptr); } - void setSource(Value *Ptr) { - assert(getRawSource()->getType() == Ptr->getType() && - "setSource called with pointer of wrong type!"); - setArgOperand(ARG_SOURCE, Ptr); - } - void setLength(Value *L) { assert(getLength()->getType() == L->getType() && "setLength called with value of wrong type!"); setArgOperand(ARG_LENGTH, L); } - - void setElementSizeInBytes(Constant *V) { - assert(V->getType() == Type::getInt8Ty(getContext()) && - "setElementSizeInBytes called with value of wrong type!"); - setArgOperand(ARG_ELEMENTSIZE, V); - } - - static bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::memcpy_element_unordered_atomic; - } - static bool classof(const Value *V) { - return isa(V) && classof(cast(V)); - } }; - class ElementUnorderedAtomicMemMoveInst : public IntrinsicInst { + // The common base class for the atomic memset/memmove/memcpy intrinsics + // i.e. llvm.element.unordered.atomic.memset/memcpy/memmove + class AtomicMemIntrinsic : public MemIntrinsicBase { private: - enum { ARG_DEST = 0, ARG_SOURCE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE = 3 }; + enum { ARG_ELEMENTSIZE = 3 }; public: - Value *getRawDest() const { - return const_cast(getArgOperand(ARG_DEST)); - } - const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST); } - Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); } - - /// Return the arguments to the instruction. - Value *getRawSource() const { - return const_cast(getArgOperand(ARG_SOURCE)); - } - const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); } - Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); } - - Value *getLength() const { - return const_cast(getArgOperand(ARG_LENGTH)); - } - const Use &getLengthUse() const { return getArgOperandUse(ARG_LENGTH); } - Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); } - - bool isVolatile() const { return false; } - Value *getRawElementSizeInBytes() const { return const_cast(getArgOperand(ARG_ELEMENTSIZE)); } @@ -343,150 +276,129 @@ return getElementSizeInBytesCst()->getZExtValue(); } - /// This is just like getRawDest, but it strips off any cast - /// instructions that feed it, giving the original input. The returned - /// value is guaranteed to be a pointer. - Value *getDest() const { return getRawDest()->stripPointerCasts(); } - - /// This is just like getRawSource, but it strips off any cast - /// instructions that feed it, giving the original input. The returned - /// value is guaranteed to be a pointer. - Value *getSource() const { return getRawSource()->stripPointerCasts(); } - - unsigned getDestAddressSpace() const { - return cast(getRawDest()->getType())->getAddressSpace(); - } - - unsigned getSourceAddressSpace() const { - return cast(getRawSource()->getType())->getAddressSpace(); - } - - /// Set the specified arguments of the instruction. - void setDest(Value *Ptr) { - assert(getRawDest()->getType() == Ptr->getType() && - "setDest called with pointer of wrong type!"); - setArgOperand(ARG_DEST, Ptr); - } - - void setSource(Value *Ptr) { - assert(getRawSource()->getType() == Ptr->getType() && - "setSource called with pointer of wrong type!"); - setArgOperand(ARG_SOURCE, Ptr); - } - - void setLength(Value *L) { - assert(getLength()->getType() == L->getType() && - "setLength called with value of wrong type!"); - setArgOperand(ARG_LENGTH, L); - } - void setElementSizeInBytes(Constant *V) { assert(V->getType() == Type::getInt8Ty(getContext()) && "setElementSizeInBytes called with value of wrong type!"); setArgOperand(ARG_ELEMENTSIZE, V); } - static inline bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::memmove_element_unordered_atomic; + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + case Intrinsic::memset_element_unordered_atomic: + return true; + default: + return false; + } } - static inline bool classof(const Value *V) { + static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; /// This class represents atomic memset intrinsic - /// TODO: Integrate this class into MemIntrinsic hierarchy; for now this is - /// C&P of all methods from that hierarchy - class ElementUnorderedAtomicMemSetInst : public IntrinsicInst { + // i.e. llvm.element.unordered.atomic.memset + class AtomicMemSetInst : public AtomicMemIntrinsic { private: - enum { ARG_DEST = 0, ARG_VALUE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE = 3 }; + enum { ARG_VALUE = 1 }; public: - Value *getRawDest() const { - return const_cast(getArgOperand(ARG_DEST)); + Value *getValue() const { + return const_cast(getArgOperand(ARG_VALUE)); } - const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST); } - Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); } - - Value *getValue() const { return const_cast(getArgOperand(ARG_VALUE)); } const Use &getValueUse() const { return getArgOperandUse(ARG_VALUE); } Use &getValueUse() { return getArgOperandUse(ARG_VALUE); } - Value *getLength() const { - return const_cast(getArgOperand(ARG_LENGTH)); + void setValue(Value *Val) { + assert(getValue()->getType() == Val->getType() && + "setValue called with value of wrong type!"); + setArgOperand(ARG_VALUE, Val); } - const Use &getLengthUse() const { return getArgOperandUse(ARG_LENGTH); } - Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); } - - bool isVolatile() const { return false; } - Value *getRawElementSizeInBytes() const { - return const_cast(getArgOperand(ARG_ELEMENTSIZE)); + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::memset_element_unordered_atomic; } - - ConstantInt *getElementSizeInBytesCst() const { - return cast(getRawElementSizeInBytes()); + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); } + }; - uint32_t getElementSizeInBytes() const { - return getElementSizeInBytesCst()->getZExtValue(); + // This class wraps the atomic memcpy/memmove intrinsics + // i.e. llvm.element.unordered.atomic.memcpy/memmove + class AtomicMemTransferInst : public AtomicMemIntrinsic { + private: + enum { ARG_SOURCE = 1 }; + + public: + /// Return the arguments to the instruction. + Value *getRawSource() const { + return const_cast(getArgOperand(ARG_SOURCE)); } + const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); } + Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); } - /// This is just like getRawDest, but it strips off any cast + /// This is just like getRawSource, but it strips off any cast /// instructions that feed it, giving the original input. The returned /// value is guaranteed to be a pointer. - Value *getDest() const { return getRawDest()->stripPointerCasts(); } + Value *getSource() const { return getRawSource()->stripPointerCasts(); } - unsigned getDestAddressSpace() const { - return cast(getRawDest()->getType())->getAddressSpace(); + unsigned getSourceAddressSpace() const { + return cast(getRawSource()->getType())->getAddressSpace(); } - /// Set the specified arguments of the instruction. - void setDest(Value *Ptr) { - assert(getRawDest()->getType() == Ptr->getType() && - "setDest called with pointer of wrong type!"); - setArgOperand(ARG_DEST, Ptr); + void setSource(Value *Ptr) { + assert(getRawSource()->getType() == Ptr->getType() && + "setSource called with pointer of wrong type!"); + setArgOperand(ARG_SOURCE, Ptr); } - void setValue(Value *Val) { - assert(getValue()->getType() == Val->getType() && - "setValue called with value of wrong type!"); - setArgOperand(ARG_VALUE, Val); + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + return true; + default: + return false; + } } - - void setLength(Value *L) { - assert(getLength()->getType() == L->getType() && - "setLength called with value of wrong type!"); - setArgOperand(ARG_LENGTH, L); + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); } + }; - void setElementSizeInBytes(Constant *V) { - assert(V->getType() == Type::getInt8Ty(getContext()) && - "setElementSizeInBytes called with value of wrong type!"); - setArgOperand(ARG_ELEMENTSIZE, V); + /// This class represents the atomic memcpy intrinsic + /// i.e. llvm.element.unordered.atomic.memcpy + class AtomicMemCpyInst : public AtomicMemTransferInst { + public: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::memcpy_element_unordered_atomic; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); } + }; - static inline bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::memset_element_unordered_atomic; + /// This class represents the atomic memmove intrinsic + /// i.e. llvm.element.unordered.atomic.memmove + class AtomicMemMoveInst : public AtomicMemTransferInst { + public: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::memmove_element_unordered_atomic; } - static inline bool classof(const Value *V) { + static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; /// This is the common base class for memset/memcpy/memmove. - class MemIntrinsic : public IntrinsicInst { - public: - Value *getRawDest() const { return const_cast(getArgOperand(0)); } - const Use &getRawDestUse() const { return getArgOperandUse(0); } - Use &getRawDestUse() { return getArgOperandUse(0); } - - Value *getLength() const { return const_cast(getArgOperand(2)); } - const Use &getLengthUse() const { return getArgOperandUse(2); } - Use &getLengthUse() { return getArgOperandUse(2); } + class MemIntrinsic : public MemIntrinsicBase { + private: + enum { ARG_ALIGN = 3, ARG_VOLATILE = 4 }; + public: ConstantInt *getAlignmentCst() const { - return cast(const_cast(getArgOperand(3))); + return cast(const_cast(getArgOperand(ARG_ALIGN))); } unsigned getAlignment() const { @@ -494,45 +406,20 @@ } ConstantInt *getVolatileCst() const { - return cast(const_cast(getArgOperand(4))); + return cast( + const_cast(getArgOperand(ARG_VOLATILE))); } bool isVolatile() const { return !getVolatileCst()->isZero(); } - unsigned getDestAddressSpace() const { - return cast(getRawDest()->getType())->getAddressSpace(); - } - - /// This is just like getRawDest, but it strips off any cast - /// instructions that feed it, giving the original input. The returned - /// value is guaranteed to be a pointer. - Value *getDest() const { return getRawDest()->stripPointerCasts(); } + void setAlignment(Constant *A) { setArgOperand(ARG_ALIGN, A); } - /// Set the specified arguments of the instruction. - void setDest(Value *Ptr) { - assert(getRawDest()->getType() == Ptr->getType() && - "setDest called with pointer of wrong type!"); - setArgOperand(0, Ptr); - } - - void setLength(Value *L) { - assert(getLength()->getType() == L->getType() && - "setLength called with value of wrong type!"); - setArgOperand(2, L); - } - - void setAlignment(Constant* A) { - setArgOperand(3, A); - } - - void setVolatile(Constant* V) { - setArgOperand(4, V); - } + void setVolatile(Constant *V) { setArgOperand(ARG_VOLATILE, V); } Type *getAlignmentType() const { - return getArgOperand(3)->getType(); + return getArgOperand(ARG_ALIGN)->getType(); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -630,6 +517,155 @@ } }; + // The common base class for any memset/memmove/memcpy intrinsics; + // whether they be atomic or non-atomic. + // i.e. llvm.element.unordered.atomic.memset/memcpy/memmove + // and llvm.memset/memcpy/memmove + class AnyMemIntrinsic : public MemIntrinsicBase { + public: + bool isVolatile() const { + // Only the non-atomic intrinsics can be volatile + if (auto *MI = dyn_cast(this)) + return MI->isVolatile(); + return false; + } + + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memmove: + case Intrinsic::memset: + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + case Intrinsic::memset_element_unordered_atomic: + return true; + default: + return false; + } + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + }; + + /// This class represents any memset intrinsic + // i.e. llvm.element.unordered.atomic.memset + // and llvm.memset + class AnyMemSetInst : public AnyMemIntrinsic { + private: + enum { ARG_VALUE = 1 }; + + public: + Value *getValue() const { + return const_cast(getArgOperand(ARG_VALUE)); + } + const Use &getValueUse() const { return getArgOperandUse(ARG_VALUE); } + Use &getValueUse() { return getArgOperandUse(ARG_VALUE); } + + void setValue(Value *Val) { + assert(getValue()->getType() == Val->getType() && + "setValue called with value of wrong type!"); + setArgOperand(ARG_VALUE, Val); + } + + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memset: + case Intrinsic::memset_element_unordered_atomic: + return true; + default: + return false; + } + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + }; + + // This class wraps any memcpy/memmove intrinsics + // i.e. llvm.element.unordered.atomic.memcpy/memmove + // and llvm.memcpy/memmove + class AnyMemTransferInst : public AnyMemIntrinsic { + private: + enum { ARG_SOURCE = 1 }; + + public: + /// Return the arguments to the instruction. + Value *getRawSource() const { + return const_cast(getArgOperand(ARG_SOURCE)); + } + const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); } + Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); } + + /// This is just like getRawSource, but it strips off any cast + /// instructions that feed it, giving the original input. The returned + /// value is guaranteed to be a pointer. + Value *getSource() const { return getRawSource()->stripPointerCasts(); } + + unsigned getSourceAddressSpace() const { + return cast(getRawSource()->getType())->getAddressSpace(); + } + + void setSource(Value *Ptr) { + assert(getRawSource()->getType() == Ptr->getType() && + "setSource called with pointer of wrong type!"); + setArgOperand(ARG_SOURCE, Ptr); + } + + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memmove: + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + return true; + default: + return false; + } + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + }; + + /// This class represents any memcpy intrinsic + /// i.e. llvm.element.unordered.atomic.memcpy + /// and llvm.memcpy + class AnyMemCpyInst : public AnyMemTransferInst { + public: + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memcpy_element_unordered_atomic: + return true; + default: + return false; + } + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + }; + + /// This class represents any memmove intrinsic + /// i.e. llvm.element.unordered.atomic.memmove + /// and llvm.memmove + class AnyMemMoveInst : public AnyMemTransferInst { + public: + static bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::memmove: + case Intrinsic::memmove_element_unordered_atomic: + return true; + default: + return false; + } + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + }; + /// This represents the llvm.va_start intrinsic. class VAStartInst : public IntrinsicInst { public: Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5044,8 +5044,7 @@ return nullptr; } case Intrinsic::memcpy_element_unordered_atomic: { - const ElementUnorderedAtomicMemCpyInst &MI = - cast(I); + const AtomicMemCpyInst &MI = cast(I); SDValue Dst = getValue(MI.getRawDest()); SDValue Src = getValue(MI.getRawSource()); SDValue Length = getValue(MI.getLength()); @@ -5083,7 +5082,7 @@ return nullptr; } case Intrinsic::memmove_element_unordered_atomic: { - auto &MI = cast(I); + auto &MI = cast(I); SDValue Dst = getValue(MI.getRawDest()); SDValue Src = getValue(MI.getRawSource()); SDValue Length = getValue(MI.getLength()); @@ -5121,7 +5120,7 @@ return nullptr; } case Intrinsic::memset_element_unordered_atomic: { - auto &MI = cast(I); + auto &MI = cast(I); SDValue Dst = getValue(MI.getRawDest()); SDValue Val = getValue(MI.getValue()); SDValue Length = getValue(MI.getLength()); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -4029,9 +4029,7 @@ break; } case Intrinsic::memcpy_element_unordered_atomic: { - const ElementUnorderedAtomicMemCpyInst *MI = - cast(CS.getInstruction()); - ; + const AtomicMemCpyInst *MI = cast(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast(MI->getRawElementSizeInBytes()); @@ -4066,7 +4064,7 @@ break; } case Intrinsic::memmove_element_unordered_atomic: { - auto *MI = cast(CS.getInstruction()); + auto *MI = cast(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast(MI->getRawElementSizeInBytes()); @@ -4101,7 +4099,7 @@ break; } case Intrinsic::memset_element_unordered_atomic: { - auto *MI = cast(CS.getInstruction()); + auto *MI = cast(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast(MI->getRawElementSizeInBytes()); Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -106,8 +106,8 @@ return ConstantVector::get(BoolVec); } -Instruction *InstCombiner::SimplifyElementUnorderedAtomicMemCpy( - ElementUnorderedAtomicMemCpyInst *AMI) { +Instruction * +InstCombiner::SimplifyElementUnorderedAtomicMemCpy(AtomicMemCpyInst *AMI) { // Try to unfold this intrinsic into sequence of explicit atomic loads and // stores. // First check that number of elements is compile time constant. @@ -1877,7 +1877,7 @@ if (Changed) return II; } - if (auto *AMI = dyn_cast(II)) { + if (auto *AMI = dyn_cast(II)) { if (Constant *C = dyn_cast(AMI->getLength())) if (C->isNullValue()) return eraseInstFromFunction(*AMI); Index: lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- lib/Transforms/InstCombine/InstCombineInternal.h +++ lib/Transforms/InstCombine/InstCombineInternal.h @@ -789,8 +789,7 @@ Instruction *MatchBSwap(BinaryOperator &I); bool SimplifyStoreAtEndOfBlock(StoreInst &SI); - Instruction * - SimplifyElementUnorderedAtomicMemCpy(ElementUnorderedAtomicMemCpyInst *AMI); + Instruction *SimplifyElementUnorderedAtomicMemCpy(AtomicMemCpyInst *AMI); Instruction *SimplifyMemTransfer(MemIntrinsic *MI); Instruction *SimplifyMemSet(MemSetInst *MI);