diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1249,6 +1249,10 @@ ``dereferenceable()``). This attribute may only be applied to pointer typed parameters. +``maxobjsize()`` + This indicates that the parameter or return pointer is a pointer to an object + that has at most ``n`` bytes. + ``swiftself`` This indicates that the parameter is the self/context parameter. This is not a valid attribute for return values and can only be applied to one diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -650,6 +650,7 @@ ATTR_KIND_NULL_POINTER_IS_VALID = 67, ATTR_KIND_NOUNDEF = 68, ATTR_KIND_BYREF = 69, + ATTR_KIND_MAX_OBJ_SIZE = 70 }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Argument.h b/llvm/include/llvm/IR/Argument.h --- a/llvm/include/llvm/IR/Argument.h +++ b/llvm/include/llvm/IR/Argument.h @@ -54,6 +54,10 @@ /// addrspace(0). bool hasNonNullAttr() const; + /// If this argument has the maxobjsize attribute, return the number of bytes + /// known to be maximal for the pointee. Otherwise, 0 is returned. + uint64_t getMaxObjSizeBytes() const; + /// If this argument has the dereferenceable attribute, return the number of /// bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableBytes() const; diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -100,6 +100,7 @@ /// alignment set. static Attribute getWithAlignment(LLVMContext &Context, Align Alignment); static Attribute getWithStackAlignment(LLVMContext &Context, Align Alignment); + static Attribute getWithMaxObjSizeBytes(LLVMContext &Context, uint64_t Bytes); static Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes); static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context, @@ -184,6 +185,9 @@ /// alignment value. MaybeAlign getStackAlignment() const; + /// Returns the maximum number of bytes of the pointee. + uint64_t getMaxObjSizeBytes() const; + /// Returns the number of dereferenceable bytes from the /// dereferenceable attribute. uint64_t getDereferenceableBytes() const; @@ -312,6 +316,7 @@ MaybeAlign getAlignment() const; MaybeAlign getStackAlignment() const; + uint64_t getMaxObjSizeBytes() const; uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; Type *getByValType() const; @@ -527,6 +532,10 @@ auto Attrs = removeAttribute(C, ArgNo, Kind); return Attrs.addAttribute(C, ArgNo, Attr.getWithNewType(C, ReplacementTy)); } + /// \brief Add the maxobjsize attribute to the attribute set at the given + /// index. Returns a new list because attribute lists are immutable. + LLVM_NODISCARD AttributeList addMaxObjSizeAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; /// \brief Add the dereferenceable attribute to the attribute set at the given /// index. Returns a new list because attribute lists are immutable. @@ -663,6 +672,14 @@ /// Get the stack alignment. MaybeAlign getStackAlignment(unsigned Index) const; + /// Get the maximal number of bytes for the underlying object. + uint64_t getMaxObjSizeBytes(unsigned Index) const; + + /// Get the number of maxobjsize bytes (or 0 if unknown) of an arg. + uint64_t getParamMaxObjSizeBytes(unsigned ArgNo) const { + return getMaxObjSizeBytes(ArgNo + FirstArgIndex); + } + /// Get the number of dereferenceable bytes (or zero if unknown). uint64_t getDereferenceableBytes(unsigned Index) const; @@ -756,6 +773,7 @@ std::map> TargetDepAttrs; MaybeAlign Alignment; MaybeAlign StackAlignment; + uint64_t MaxObjSizeBytes = 0; uint64_t DerefBytes = 0; uint64_t DerefOrNullBytes = 0; uint64_t AllocSizeArgs = 0; @@ -837,6 +855,9 @@ /// Retrieve the stack alignment attribute, if it exists. MaybeAlign getStackAlignment() const { return StackAlignment; } + /// Retreive the number of bytes the underlying object can have. + uint64_t getMaxObjSizeBytes() const { return MaxObjSizeBytes; } + /// Retrieve the number of dereferenceable bytes, if the /// dereferenceable attribute exists (zero is returned otherwise). uint64_t getDereferenceableBytes() const { return DerefBytes; } @@ -885,6 +906,10 @@ return addStackAlignmentAttr(MaybeAlign(Align)); } + /// This turns the number of max object size bytes into the form used + /// internally in Attribute. + AttrBuilder &addMaxObjSizeAttr(uint64_t Bytes); + /// This turns the number of dereferenceable bytes into the form used /// internally in Attribute. AttrBuilder &addDereferenceableAttr(uint64_t Bytes); diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -51,6 +51,9 @@ /// Can only be moved to control-equivalent blocks. def Convergent : EnumAttr<"convergent">; +/// Pointee is known to have a maximal size. +def MaxObjSize : IntAttr<"maxobjsize">; + /// Pointer is known to be dereferenceable. def Dereferenceable : IntAttr<"dereferenceable">; diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -483,6 +483,12 @@ return AttributeSets.getParamByRefType(ArgNo); } + /// Extract the number of maxobjsize bytes for a parameter. + /// @param ArgNo Index of an argument, with 0 being the first function arg. + uint64_t getParamMaxObjSizeBytes(unsigned ArgNo) const { + return AttributeSets.getParamMaxObjSizeBytes(ArgNo); + } + /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). /// @param i AttributeList index, referring to a return value or argument. diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1640,6 +1640,12 @@ return Ty ? Ty : getArgOperand(ArgNo)->getType()->getPointerElementType(); } + /// Extract the number of maxobjsize bytes for a call or parameter + /// (0=unknown) + uint64_t getMaxObjSizeBytes(unsigned ArgNo) const { + return Attrs.getMaxObjSizeBytes(ArgNo); + } + /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -48,6 +48,7 @@ class raw_ostream; template class StringMapEntry; class StringRef; +class TargetLibraryInfo; class Twine; class Type; class User; @@ -670,6 +671,11 @@ static_cast(this)->stripInBoundsOffsets(Func)); } + /// Returns the number of bytes known to be the maximal extend for the + /// pointer value. + uint64_t getPointerMaxObjSizeBytes(const DataLayout &DL, + const TargetLibraryInfo *TLI) const; + /// Returns the number of bytes known to be dereferenceable for the /// pointer value. /// diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -1233,6 +1233,11 @@ /// Return the internal information cache. InformationCache &getInfoCache() { return InfoCache; } + /// Return the internal information cache. + TargetLibraryInfo *getTargetLibraryInfo(const Function &F) { + return InfoCache.getTargetLibraryInfoForFunction(F); + } + /// Return true if this is a module pass, false otherwise. bool isModulePass() const { return !Functions.empty() && diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -214,10 +214,11 @@ /// assuming the result is used in an aliasing query. static uint64_t getMaximalExtentFrom(const Value &V, const LocationSize &LocSize, - const DataLayout &DL) { + const DataLayout &DL, + const TargetLibraryInfo &TLI) { // This is an over-approximation of the number of bytes until the end of // the object. This approximation ignores the offset in \p V. - return V.getPointerMaxObjSizeBytes(DL); + return V.getPointerMaxObjSizeBytes(DL, &TLI); } /// Returns true if we can prove that the object specified by V has size Size. @@ -1782,8 +1783,8 @@ getMinimalExtentFrom(*V1, V1Size, DL, NullIsValidLocation); uint64_t V2MinSize = getMinimalExtentFrom(*V2, V2Size, DL, NullIsValidLocation); - uint64_t V1MaxSize = getMaximalExtentFrom(*V1, V1Size, DL); - uint64_t V2MaxSize = getMaximalExtentFrom(*V2, V2Size, DL); + uint64_t V1MaxSize = getMaximalExtentFrom(*V1, V1Size, DL, TLI); + uint64_t V2MaxSize = getMaximalExtentFrom(*V2, V2Size, DL, TLI); if (V1MaxSize < V2MinSize || V2MaxSize < V1MinSize || isObjectSmallerThan(O2, V1MinSize, DL, TLI, NullIsValidLocation) || diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -639,6 +639,7 @@ KEYWORD(inalloca); KEYWORD(cold); KEYWORD(convergent); + KEYWORD(maxobjsize); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); KEYWORD(inaccessiblememonly); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1376,6 +1376,7 @@ "invalid use of attribute on a function"); break; case lltok::kw_byval: + case lltok::kw_maxobjsize: case lltok::kw_dereferenceable: case lltok::kw_dereferenceable_or_null: case lltok::kw_inalloca: @@ -1676,6 +1677,13 @@ B.addPreallocatedAttr(Ty); continue; } + case lltok::kw_maxobjsize: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_maxobjsize, Bytes)) + return true; + B.addMaxObjSizeAttr(Bytes); + continue; + } case lltok::kw_dereferenceable: { uint64_t Bytes; if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes)) @@ -1776,6 +1784,13 @@ return true; continue; } + case lltok::kw_maxobjsize: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_maxobjsize, Bytes)) + return true; + B.addMaxObjSizeAttr(Bytes); + continue; + } case lltok::kw_dereferenceable: { uint64_t Bytes; if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes)) @@ -2192,7 +2207,8 @@ bool LLParser::ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes) { assert((AttrKind == lltok::kw_dereferenceable || - AttrKind == lltok::kw_dereferenceable_or_null) && + AttrKind == lltok::kw_dereferenceable_or_null || + AttrKind == lltok::kw_maxobjsize) && "contract!"); Bytes = 0; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -185,6 +185,7 @@ kw_inalloca, kw_cold, kw_convergent, + kw_maxobjsize, kw_dereferenceable, kw_dereferenceable_or_null, kw_inaccessiblememonly, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1451,6 +1451,8 @@ return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; + case bitc::ATTR_KIND_MAX_OBJ_SIZE: + return Attribute::MaxObjSize; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: @@ -1621,6 +1623,8 @@ B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); + else if (Kind == Attribute::MaxObjSize) + B.addMaxObjSizeAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -661,6 +661,8 @@ return bitc::ATTR_KIND_NON_LAZY_BIND; case Attribute::NonNull: return bitc::ATTR_KIND_NON_NULL; + case Attribute::MaxObjSize: + return bitc::ATTR_KIND_MAX_OBJ_SIZE; case Attribute::Dereferenceable: return bitc::ATTR_KIND_DEREFERENCEABLE; case Attribute::DereferenceableOrNull: diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -249,6 +249,7 @@ MaybeAlign getAlignment() const; MaybeAlign getStackAlignment() const; + uint64_t getMaxObjSizeBytes() const; uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; std::pair> getAllocSizeArgs() const; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -156,6 +156,12 @@ return get(Context, StackAlignment, A.value()); } +Attribute Attribute::getWithMaxObjSizeBytes(LLVMContext &Context, + uint64_t Bytes) { + assert(Bytes != uint64_t(0) && "Bytes must be != 0"); + return get(Context, MaxObjSize, Bytes); +} + Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes) { assert(Bytes && "Bytes must be non-zero."); @@ -218,6 +224,7 @@ bool Attribute::doesAttrKindHaveArgument(Attribute::AttrKind AttrKind) { return AttrKind == Attribute::Alignment || AttrKind == Attribute::StackAlignment || + AttrKind == Attribute::MaxObjSize || AttrKind == Attribute::Dereferenceable || AttrKind == Attribute::AllocSize || AttrKind == Attribute::DereferenceableOrNull; @@ -308,6 +315,13 @@ return MaybeAlign(pImpl->getValueAsInt()); } +uint64_t Attribute::getMaxObjSizeBytes() const { + assert(hasAttribute(Attribute::MaxObjSize) && + "Trying to get the maximal object size from " + "non-maxobjsize attribute!"); + return pImpl->getValueAsInt(); +} + uint64_t Attribute::getDereferenceableBytes() const { assert(hasAttribute(Attribute::Dereferenceable) && "Trying to get dereferenceable bytes from " @@ -507,6 +521,9 @@ if (hasAttribute(Attribute::StackAlignment)) return AttrWithBytesToString("alignstack"); + if (hasAttribute(Attribute::MaxObjSize)) + return AttrWithBytesToString("maxobjsize"); + if (hasAttribute(Attribute::Dereferenceable)) return AttrWithBytesToString("dereferenceable"); @@ -741,6 +758,10 @@ return SetNode ? SetNode->getStackAlignment() : None; } +uint64_t AttributeSet::getMaxObjSizeBytes() const { + return SetNode ? SetNode->getMaxObjSizeBytes() : ~uint64_t(0); +} + uint64_t AttributeSet::getDereferenceableBytes() const { return SetNode ? SetNode->getDereferenceableBytes() : 0; } @@ -874,6 +895,10 @@ assert(B.getStackAlignment() && "StackAlignment must be set"); Attr = Attribute::getWithStackAlignment(C, *B.getStackAlignment()); break; + case Attribute::MaxObjSize: + assert(B.getMaxObjSizeBytes() && "MaxObjSize must be set"); + Attr = Attribute::getWithMaxObjSizeBytes(C, B.getMaxObjSizeBytes()); + break; case Attribute::Dereferenceable: Attr = Attribute::getWithDereferenceableBytes( C, B.getDereferenceableBytes()); @@ -967,6 +992,12 @@ return nullptr; } +uint64_t AttributeSetNode::getMaxObjSizeBytes() const { + if (auto A = findEnumAttribute(Attribute::MaxObjSize)) + return A->getMaxObjSizeBytes(); + return ~uint64_t(0); +} + uint64_t AttributeSetNode::getDereferenceableBytes() const { if (auto A = findEnumAttribute(Attribute::Dereferenceable)) return A->getDereferenceableBytes(); @@ -1389,6 +1420,13 @@ return getImpl(C, AttrSets); } +AttributeList AttributeList::addMaxObjSizeAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const { + AttrBuilder B; + B.addMaxObjSizeAttr(Bytes); + return addAttributes(C, Index, B); +} + AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C, unsigned Index, uint64_t Bytes) const { @@ -1498,6 +1536,10 @@ return getAttributes(Index).getStackAlignment(); } +uint64_t AttributeList::getMaxObjSizeBytes(unsigned Index) const { + return getAttributes(Index).getMaxObjSizeBytes(); +} + uint64_t AttributeList::getDereferenceableBytes(unsigned Index) const { return getAttributes(Index).getDereferenceableBytes(); } @@ -1572,6 +1614,7 @@ TargetDepAttrs.clear(); Alignment.reset(); StackAlignment.reset(); + MaxObjSizeBytes = 0; DerefBytes = DerefOrNullBytes = 0; AllocSizeArgs = 0; ByValType = nullptr; @@ -1601,6 +1644,8 @@ ByRefType = Attr.getValueAsType(); else if (Kind == Attribute::Preallocated) PreallocatedType = Attr.getValueAsType(); + else if (Kind == Attribute::MaxObjSize) + MaxObjSizeBytes = Attr.getMaxObjSizeBytes(); else if (Kind == Attribute::Dereferenceable) DerefBytes = Attr.getDereferenceableBytes(); else if (Kind == Attribute::DereferenceableOrNull) @@ -1631,6 +1676,8 @@ ByRefType = nullptr; else if (Val == Attribute::Preallocated) PreallocatedType = nullptr; + else if (Val == Attribute::MaxObjSize) + MaxObjSizeBytes = 0; else if (Val == Attribute::Dereferenceable) DerefBytes = 0; else if (Val == Attribute::DereferenceableOrNull) @@ -1680,6 +1727,15 @@ return *this; } +AttrBuilder &AttrBuilder::addMaxObjSizeAttr(uint64_t Bytes) { + if (Bytes == 0U) + return *this; + + Attrs[Attribute::MaxObjSize] = true; + MaxObjSizeBytes = Bytes; + return *this; +} + AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) { if (Bytes == 0) return *this; @@ -1745,6 +1801,9 @@ if (!StackAlignment) StackAlignment = B.StackAlignment; + if (MaxObjSizeBytes == 0) + MaxObjSizeBytes = B.MaxObjSizeBytes; + if (!DerefBytes) DerefBytes = B.DerefBytes; @@ -1782,6 +1841,9 @@ if (B.StackAlignment) StackAlignment.reset(); + if (B.MaxObjSizeBytes == 0) + MaxObjSizeBytes = 0; + if (B.DerefBytes) DerefBytes = 0; @@ -1864,7 +1926,8 @@ return Alignment == B.Alignment && StackAlignment == B.StackAlignment && DerefBytes == B.DerefBytes && ByValType == B.ByValType && StructRetType == B.StructRetType && ByRefType == B.ByRefType && - PreallocatedType == B.PreallocatedType; + PreallocatedType == B.PreallocatedType && + MaxObjSizeBytes == B.MaxObjSizeBytes; } //===----------------------------------------------------------------------===// @@ -1887,6 +1950,7 @@ .addAttribute(Attribute::NoCapture) .addAttribute(Attribute::NonNull) .addAlignmentAttr(1) // the int here is ignored + .addMaxObjSizeAttr(1) // the int here is ignored .addDereferenceableAttr(1) // the int here is ignored .addDereferenceableOrNullAttr(1) // the int here is ignored .addAttribute(Attribute::ReadNone) diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -208,6 +208,11 @@ return getParent()->getParamByRefType(getArgNo()); } +uint64_t Argument::getMaxObjSizeBytes() const { + assert(getType()->isPointerTy() && "Only pointers have maxobjsize bytes"); + return getParent()->getParamMaxObjSizeBytes(getArgNo()); +} + uint64_t Argument::getDereferenceableBytes() const { assert(getType()->isPointerTy() && "Only pointers have dereferenceable bytes"); diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -704,6 +705,28 @@ return stripPointerCastsAndOffsets(this, Func); } +uint64_t Value::getPointerMaxObjSizeBytes(const DataLayout &DL, + const TargetLibraryInfo *TLI) const { + assert(getType()->isPointerTy() && "must be pointer"); + + uint64_t MaxObjSizeBytes = ~0U; + if (const Argument *A = dyn_cast(this)) { + MaxObjSizeBytes = A->getMaxObjSizeBytes(); + if ((A->hasByValAttr() || A->hasStructRetAttr())) { + Type *PT = cast(A->getType())->getElementType(); + if (PT->isSized()) + MaxObjSizeBytes = + std::min(MaxObjSizeBytes, uint64_t(DL.getTypeStoreSize(PT))); + } + } else if (const auto *Call = dyn_cast(this)) { + MaxObjSizeBytes = Call->getMaxObjSizeBytes(AttributeList::ReturnIndex); + } else if (dyn_cast(this) || dyn_cast(this)) { + if (!getObjectSize(this, MaxObjSizeBytes, DL, TLI)) + MaxObjSizeBytes = ~0U; + } + return MaxObjSizeBytes; +} + uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, bool &CanBeNull) const { assert(getType()->isPointerTy() && "must be pointer"); diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Instructions.h" #include "llvm/Transforms/IPO/Attributor.h" @@ -3741,10 +3742,14 @@ bool Stripped) -> bool { const auto &AA = A.getAAFor(*this, IRPosition::value(V)); uint64_t MaxObjSize = 0; + Function *F = getAnchorScope(); + TargetLibraryInfo *TLI = nullptr; + if (F) + TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); if (!Stripped && this == &AA) { if (AA.getState().FixedSizeState.getAssumed()) { - MaxObjSize = V.getPointerMaxObjSizeBytes(DL); + MaxObjSize = V.getPointerMaxObjSizeBytes(DL, TLI); T.MaxObjSizeState.takeAssumedMaximum( std::min(~uint64_t(0), MaxObjSize)); T.MaxObjSizeState.indicateOptimisticFixpoint(); @@ -3809,8 +3814,13 @@ /// See AbstractAttribute::initialize(...). virtual void initialize(Attributor &A) override { if (hasAttr(Attribute::ByVal)) { + Function *F = getAnchorScope(); + TargetLibraryInfo *TLI = nullptr; + if (F) + TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); getState().MaxObjSizeState.takeKnownMinimum( - getAssociatedValue().getPointerMaxObjSizeBytes(A.getDataLayout())); + getAssociatedValue().getPointerMaxObjSizeBytes(A.getDataLayout(), + TLI)); getState().indicatePessimisticFixpoint(); return; } diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -862,6 +862,7 @@ case Attribute::Builtin: case Attribute::ByVal: case Attribute::Convergent: + case Attribute::MaxObjSize: case Attribute::Dereferenceable: case Attribute::DereferenceableOrNull: case Attribute::InAlloca: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -398,6 +398,12 @@ ret void } +; CHECK: define maxobjsize(8) i32* @f68(i32* maxobjsize(4) %0) +define maxobjsize(8) i32* @f68(i32* maxobjsize(4)) +{ + ret i32* %0; +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll @@ -11,7 +11,7 @@ define i32 @bar() { ; CHECK-LABEL: define {{[^@]+}}@bar() { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo(i32* noundef nonnull align 4 dereferenceable(4) maxobjsize(4) @g) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo(i32* noundef nonnull align 4 dereferenceable(4) @g) ; CHECK-NEXT: ret i32 [[CALL]] ; entry: diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll @@ -11,7 +11,7 @@ ; ; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind willreturn ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@add -; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__TUNIT_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__TUNIT_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__TUNIT_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -22,7 +22,7 @@ ; ; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@add -; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__TUNIT_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__TUNIT_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__TUNIT_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -33,7 +33,7 @@ ; ; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@add -; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__CGSCC_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__CGSCC_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__CGSCC_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -44,7 +44,7 @@ ; ; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@add -; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__CGSCC_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__CGSCC_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__CGSCC_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -68,7 +68,7 @@ ; IS__TUNIT_OPM-SAME: () [[ATTR1:#.*]] { ; IS__TUNIT_OPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__TUNIT_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__TUNIT_OPM-NEXT: ret void ; ; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn @@ -76,7 +76,7 @@ ; IS__TUNIT_NPM-SAME: () [[ATTR1:#.*]] { ; IS__TUNIT_NPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__TUNIT_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__TUNIT_NPM-NEXT: ret void ; ; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -84,7 +84,7 @@ ; IS__CGSCC_OPM-SAME: () [[ATTR1:#.*]] { ; IS__CGSCC_OPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__CGSCC_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__CGSCC_OPM-NEXT: ret void ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -92,7 +92,7 @@ ; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] { ; IS__CGSCC_NPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__CGSCC_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret(i32) align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__CGSCC_NPM-NEXT: ret void ; %r = alloca i32 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll @@ -37,7 +37,7 @@ ; IS__TUNIT____-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8 ; IS__TUNIT____-NEXT: [[THREAD:%.*]] = alloca i64, align 8 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @foo, i8* noalias nocapture nofree readnone align 536870912 undef) -; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) maxobjsize(8) "no-capture-maybe-returned" undef) +; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" undef) ; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @baz, i8* noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) maxobjsize(1) [[ALLOC1]]) ; IS__TUNIT____-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @buz, i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" [[ALLOC2]]) ; IS__TUNIT____-NEXT: ret i32 0 @@ -48,7 +48,7 @@ ; IS__CGSCC____-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8 ; IS__CGSCC____-NEXT: [[THREAD:%.*]] = alloca i64, align 8 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @foo, i8* noalias nocapture nofree noundef readnone align 536870912 null) -; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @bar, i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(8) maxobjsize(8) bitcast (i8** @GlobalVPtr to i8*)) +; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @bar, i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*)) ; IS__CGSCC____-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @baz, i8* noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) maxobjsize(1) [[ALLOC1]]) ; IS__CGSCC____-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* noundef nonnull align 8 dereferenceable(8) maxobjsize(8) [[THREAD]], %union.pthread_attr_t* noalias nocapture noundef align 536870912 null, i8* (i8*)* noundef nonnull @buz, i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" [[ALLOC2]]) ; IS__CGSCC____-NEXT: ret i32 0 @@ -86,13 +86,13 @@ define internal i8* @bar(i8* %arg) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@bar -; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) maxobjsize(8) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR0]] { +; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR0]] { ; IS__TUNIT____-NEXT: entry: ; IS__TUNIT____-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*) ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@bar -; IS__CGSCC____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) maxobjsize(8) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR0]] { +; IS__CGSCC____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR0]] { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*) ; diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll --- a/llvm/test/Transforms/Attributor/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll @@ -153,7 +153,7 @@ define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@f1 -; IS__TUNIT____-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] { +; IS__TUNIT____-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] { ; IS__TUNIT____-NEXT: br label [[TMP3:%.*]] ; IS__TUNIT____: 2: ; IS__TUNIT____-NEXT: unreachable @@ -162,7 +162,7 @@ ; ; IS__CGSCC_OPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f1 -; IS__CGSCC_OPM-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR2:#.*]] { +; IS__CGSCC_OPM-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR2:#.*]] { ; IS__CGSCC_OPM-NEXT: br label [[TMP3:%.*]] ; IS__CGSCC_OPM: 2: ; IS__CGSCC_OPM-NEXT: unreachable @@ -230,7 +230,7 @@ ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test7 ; IS__TUNIT____-SAME: () [[ATTR0]] { -; IS__TUNIT____-NEXT: [[C:%.*]] = tail call i8* @f1(i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" @a1) [[ATTR9:#.*]] +; IS__TUNIT____-NEXT: [[C:%.*]] = tail call i8* @f1(i8* noalias nofree noundef nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1) [[ATTR9:#.*]] ; IS__TUNIT____-NEXT: ret i8* [[C]] ; ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn @@ -247,7 +247,7 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 { ; IS__CGSCC_OPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f1b -; IS__CGSCC_OPM-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) maxobjsize(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR2]] { +; IS__CGSCC_OPM-SAME: (i8* noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR2]] { ; IS__CGSCC_OPM-NEXT: br label [[TMP3:%.*]] ; IS__CGSCC_OPM: 2: ; IS__CGSCC_OPM-NEXT: unreachable diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -473,13 +473,13 @@ ; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn writeonly ; IS__TUNIT____-LABEL: define {{[^@]+}}@writeonly_global_via_arg ; IS__TUNIT____-SAME: () [[ATTR6]] { -; IS__TUNIT____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) @G) [[ATTR6]] +; IS__TUNIT____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) [[ATTR6]] ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global_via_arg ; IS__CGSCC____-SAME: () [[ATTR6]] { -; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) @G) [[ATTR10]] +; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) [[ATTR10]] ; IS__CGSCC____-NEXT: ret void ; call void @write_global_via_arg(i32* @G) diff --git a/llvm/test/Transforms/Attributor/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll --- a/llvm/test/Transforms/Attributor/nosync.ll +++ b/llvm/test/Transforms/Attributor/nosync.ll @@ -463,7 +463,7 @@ ; CHECK: Function Attrs: nounwind ; CHECK-LABEL: define {{[^@]+}}@i_totally_sync ; CHECK-SAME: () [[ATTR14:#.*]] { -; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) maxobjsize(4) bitcast (i32* @a to i8*)) +; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*)) ; CHECK-NEXT: ret void ; tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*)) diff --git a/llvm/test/Transforms/InstCombine/pr46680.ll b/llvm/test/Transforms/InstCombine/pr46680.ll --- a/llvm/test/Transforms/InstCombine/pr46680.ll +++ b/llvm/test/Transforms/InstCombine/pr46680.ll @@ -24,11 +24,17 @@ ; CHECK-NEXT: br label [[BB22:%.*]] ; CHECK: bb13: ; CHECK-NEXT: [[I14:%.*]] = load i16, i16* [[ARG]], align 2 -; CHECK-NEXT: [[I19:%.*]] = trunc i16 [[I14]] to i8 -; CHECK-NEXT: store i8 [[I19]], i8* @c, align 1 +; CHECK-NEXT: [[I15:%.*]] = trunc i16 [[I14]] to i8 +; CHECK-NEXT: store i8 [[I15]], i8* @c, align 1 ; CHECK-NEXT: br label [[BB22]] ; CHECK: bb22: -; CHECK-NEXT: [[STOREMERGE_IN:%.*]] = phi i16 [ [[I5]], [[BB4]] ], [ [[I14]], [[BB13]] ] +; CHECK-NEXT: [[STOREMERGE2_IN:%.*]] = load i16, i16* [[ARG]], align 2 +; CHECK-NEXT: [[STOREMERGE2:%.*]] = trunc i16 [[STOREMERGE2_IN]] to i8 +; CHECK-NEXT: store i8 [[STOREMERGE2]], i8* @c, align 1 +; CHECK-NEXT: [[STOREMERGE1_IN:%.*]] = load i16, i16* [[ARG]], align 2 +; CHECK-NEXT: [[STOREMERGE1:%.*]] = trunc i16 [[STOREMERGE1_IN]] to i8 +; CHECK-NEXT: store i8 [[STOREMERGE1]], i8* @c, align 1 +; CHECK-NEXT: [[STOREMERGE_IN:%.*]] = load i16, i16* [[ARG]], align 2 ; CHECK-NEXT: [[STOREMERGE:%.*]] = trunc i16 [[STOREMERGE_IN]] to i8 ; CHECK-NEXT: store i8 [[STOREMERGE]], i8* @c, align 1 ; CHECK-NEXT: br label [[BB23:%.*]] diff --git a/llvm/test/Transforms/OpenMP/parallel_region_merging.ll b/llvm/test/Transforms/OpenMP/parallel_region_merging.ll --- a/llvm/test/Transforms/OpenMP/parallel_region_merging.ll +++ b/llvm/test/Transforms/OpenMP/parallel_region_merging.ll @@ -19,7 +19,6 @@ ; a = 3; ; } ; } -; ; Merge all parallel regions. define dso_local void @merge_all() local_unnamed_addr { %1 = alloca i32, align 4 @@ -59,7 +58,6 @@ ; a = 4; ; } ; } -; ; Does not merge parallel regions, in-between store ; instruction is unsafe to execute in parallel. define dso_local void @merge_none() local_unnamed_addr { @@ -100,7 +98,6 @@ ; a = 5; ; } ; } -; ; Do not merge first parallel region, due to the ; unsafe store, but merge the two next parallel ; regions. @@ -141,7 +138,6 @@ ; #pragma omp cancel parallel ; } ; } -; ; #pragma omp parallel ; { ; if (cancel2) { @@ -149,7 +145,6 @@ ; } ; } ; } -; ; Merge correctly cancellable regions. define dso_local void @merge_cancellable_regions(i32 %0, i32 %1) local_unnamed_addr { %3 = alloca i32, align 4 @@ -229,10 +224,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_all..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_all..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_all..omp_par.1(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_all..omp_par.1(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -243,13 +238,13 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_all..omp_par.1 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1:#.*]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1:#.*]] { ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_all..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -258,20 +253,20 @@ ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]]) ; CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 1, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par.2 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par.2 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_none..omp_par.2 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 4, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_none..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -280,7 +275,7 @@ ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]]) ; CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 1, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_some..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_some..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: br label [[OMP_PARALLEL:%.*]] @@ -308,10 +303,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_some..omp_par.3(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_some..omp_par.3(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_some..omp_par.4(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_some..omp_par.4(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -322,19 +317,19 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par.4 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 5, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par.3 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 4, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -372,10 +367,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_cancellable_regions..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_cancellable_regions..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_cancellable_regions..omp_par.5(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP1]]) +; CHECK-NEXT: call void @merge_cancellable_regions..omp_par.5(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP1]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -386,7 +381,7 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_cancellable_regions..omp_par.5 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP2:%.*]]) { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) { ; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 0 ; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP7:%.*]] @@ -399,7 +394,7 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_cancellable_regions..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP2:%.*]]) { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) { ; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 0 ; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP7:%.*]] diff --git a/llvm/test/Transforms/OpenMP/parallel_region_merging_legacy_pm.ll b/llvm/test/Transforms/OpenMP/parallel_region_merging_legacy_pm.ll --- a/llvm/test/Transforms/OpenMP/parallel_region_merging_legacy_pm.ll +++ b/llvm/test/Transforms/OpenMP/parallel_region_merging_legacy_pm.ll @@ -19,7 +19,6 @@ ; a = 3; ; } ; } -; ; Merge all parallel regions. define dso_local void @merge_all() local_unnamed_addr { %1 = alloca i32, align 4 @@ -59,7 +58,6 @@ ; a = 4; ; } ; } -; ; Does not merge parallel regions, in-between store ; instruction is unsafe to execute in parallel. define dso_local void @merge_none() local_unnamed_addr { @@ -100,7 +98,6 @@ ; a = 5; ; } ; } -; ; Do not merge first parallel region, due to the ; unsafe store, but merge the two next parallel ; regions. @@ -141,7 +138,6 @@ ; #pragma omp cancel parallel ; } ; } -; ; #pragma omp parallel ; { ; if (cancel2) { @@ -149,7 +145,6 @@ ; } ; } ; } -; ; Merge correctly cancellable regions. define dso_local void @merge_cancellable_regions(i32 %0, i32 %1) local_unnamed_addr { %3 = alloca i32, align 4 @@ -229,10 +224,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_all..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_all..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_all..omp_par.1(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_all..omp_par.1(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -243,13 +238,13 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_all..omp_par.1 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1:#.*]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1:#.*]] { ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_all..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -258,20 +253,20 @@ ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]]) ; CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 1, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par.2 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_none..omp_par.2 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_none..omp_par.2 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 4, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_none..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -280,7 +275,7 @@ ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]]) ; CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 1, i32* [[TMP2]], align 4 -; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_some..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2]]) +; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) maxobjsize(24) [[GLOB1]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @merge_some..omp_par to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2]]) ; CHECK-NEXT: store i32 3, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: br label [[OMP_PARALLEL:%.*]] @@ -308,10 +303,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_some..omp_par.3(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_some..omp_par.3(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_some..omp_par.4(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_some..omp_par.4(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -322,19 +317,19 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par.4 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 5, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par.3 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 4, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_some..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP2:%.*]]) [[ATTR1]] { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) [[ATTR1]] { ; CHECK-NEXT: store i32 2, i32* [[TMP2]], align 4 ; CHECK-NEXT: ret void ; @@ -372,10 +367,10 @@ ; CHECK: omp.par.region: ; CHECK-NEXT: br label [[OMP_PAR_MERGED:%.*]] ; CHECK: omp.par.merged: -; CHECK-NEXT: call void @merge_cancellable_regions..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP0]]) +; CHECK-NEXT: call void @merge_cancellable_regions..omp_par(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP0]]) ; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* [[GLOB1]]) ; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* [[GLOB2]], i32 [[OMP_GLOBAL_THREAD_NUM]]) -; CHECK-NEXT: call void @merge_cancellable_regions..omp_par.5(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP1]]) +; CHECK-NEXT: call void @merge_cancellable_regions..omp_par.5(i32* [[TID_ADDR]], i32* [[ZERO_ADDR]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP1]]) ; CHECK-NEXT: br label [[DOTSPLIT:%.*]] ; CHECK: .split: ; CHECK-NEXT: br label [[OMP_PAR_REGION_SPLIT:%.*]] @@ -386,7 +381,7 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_cancellable_regions..omp_par.5 -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP2:%.*]]) { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) { ; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 0 ; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP7:%.*]] @@ -399,7 +394,7 @@ ; ; ; CHECK-LABEL: define {{[^@]+}}@merge_cancellable_regions..omp_par -; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP2:%.*]]) { +; CHECK-SAME: (i32* noalias nocapture nofree readnone [[TMP0:%.*]], i32* noalias nocapture nofree readnone [[TMP1:%.*]], i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) maxobjsize(4) [[TMP2:%.*]]) { ; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[TMP2]], align 4 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 0 ; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP7:%.*]]