diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1135,15 +1135,22 @@ the behavior is undefined. ``dereferenceable()`` - This indicates that the parameter or return pointer is dereferenceable. This - attribute may only be applied to pointer typed parameters. A pointer that - is dereferenceable can be loaded from speculatively without a risk of - trapping. The number of bytes known to be dereferenceable must be provided - in parentheses. It is legal for the number of bytes to be less than the - size of the pointee type. The ``nonnull`` attribute does not imply - dereferenceability (consider a pointer to one element past the end of an - array), however ``dereferenceable()`` does imply ``nonnull`` in - ``addrspace(0)`` (which is the default address space). + This indicates that the annotated value, e.g., a parameter or return + value, is dereferenceable *at its definition*, which would be the beginning + of the function entry or the call site for annotated parameters and return + values respectively. This attribute may only be applied to values with + pointer type. A pointer that is known to be dereferenceable can be loaded + from speculatively without a risk of trapping. The number of bytes known to + be dereferenceable must be provided in parentheses. It is legal for the + number of bytes to be less than the size of the pointee type. If, at + runtime, the annotated pointer is not dereferenceable, the behavior is + undefined. The ``nonnull`` attribute does not imply dereferenceability + (consider a pointer to one element past the end of an array), however + ``dereferenceable()`` does imply ``nonnull`` in ``addrspace(0)`` (which + is the default address space). The dereferenceability property provided + through this argument is tied to the definition because it can be lost, + e.g., via a call to ``free``. Use ``dereferenceable_globally()`` for + pointer values that cannot be deallocated. ``dereferenceable_or_null()`` This indicates that the parameter or return value isn't both @@ -1154,9 +1161,24 @@ a pointer is exactly one of ``dereferenceable()`` or ``null``, and in other address spaces ``dereferenceable_or_null()`` implies that a pointer is at least one of ``dereferenceable()`` - or ``null`` (i.e. it may be both ``null`` and - ``dereferenceable()``). This attribute may only be applied to - pointer typed parameters. + or ``null`` (i.e. it may be both ``null`` and ``dereferenceable()``). + This attribute may only be applied to pointer typed parameters. + +``dereferenceable_globally()`` + This indicates that the annotated pointer value has the + ``dereferenceable()`` property *at any program point*, starting from the + definition of the value to the termination of the program. Thus, unlike + pointer values annotated with ``dereferenceable()``, + ``dereferenceable_globally()`` pointer values can never lose the + ``dereferenceable()`` property. + +``dereferenceable_or_null_globally()`` + This indicates that the annotated pointer value has the + ``dereferenceable_or_null()`` property *at any program point*, starting + from the definition of the value to the termination of the program. Thus, + unlike pointer values annotated with ``dereferenceable_or_null()``, + ``dereferenceable_or_null_globally()`` pointer values can never lose the + ``dereferenceable_or_null()`` property. ``swiftself`` This indicates that the parameter is the self/context parameter. This is not @@ -8492,7 +8514,7 @@ :: - = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !align !] + = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !dereferenceable_globally !][, !dereferenceable_or_null_globally !][, !align !] = load atomic [volatile] , * [syncscope("")] , align [, !invariant.group !] ! = !{ i32 1 } ! = !{i64 } @@ -8566,24 +8588,30 @@ This is analogous to the ``nonnull`` attribute on parameters and return values. This metadata can only be applied to loads of a pointer type. -The optional ``!dereferenceable`` metadata must reference a single metadata +The optional ``!dereferenceable`` and ``!dereferenceable_globally`` metadata +must reference a single metadata name ```` corresponding to a +metadata node with one ``i64`` entry. The existence of the ``!dereferenceable`` +or ``!dereferenceable_globally`` metadata on the instruction tells the +optimizer that the value loaded is known to be dereferenceable at its +definition, in the case of ``!dereferenceable``, or globally, in the case of +``!dereferenceable_globally``. The number of bytes known to be dereferenceable +is specified by the integer value in the metadata node. This is analogous to +the ''dereferenceable'' and ''dereferenceable_globally'' attribute on +parameters and return values. This metadata can only be applied to loads of a +pointer type. + +The optional ``!dereferenceable_or_null`` and +``!dereferenceable_or_null_globally`` metadata must reference a single metadata name ```` corresponding to a metadata node with one ``i64`` -entry. The existence of the ``!dereferenceable`` metadata on the instruction -tells the optimizer that the value loaded is known to be dereferenceable. -The number of bytes known to be dereferenceable is specified by the integer -value in the metadata node. This is analogous to the ''dereferenceable'' -attribute on parameters and return values. This metadata can only be applied -to loads of a pointer type. - -The optional ``!dereferenceable_or_null`` metadata must reference a single -metadata name ```` corresponding to a metadata node with one -``i64`` entry. The existence of the ``!dereferenceable_or_null`` metadata on the -instruction tells the optimizer that the value loaded is known to be either -dereferenceable or null. -The number of bytes known to be dereferenceable is specified by the integer -value in the metadata node. This is analogous to the ''dereferenceable_or_null'' -attribute on parameters and return values. This metadata can only be applied -to loads of a pointer type. +entry. The existence of the ``!dereferenceable_or_null`` or +``!dereferenceable_or_null_globally`` metadata on the instruction tells the +optimizer that the value loaded is known to be either dereferenceable or null +at its definition, in the case of ``!dereferenceable``, or globally, in the +case of ``!dereferenceable_globally``. The number of bytes known to be +dereferenceable is specified by the integer value in the metadata node. This is +analogous to the ''dereferenceable_or_null'' and +''dereferenceable_or_null_globally'' attribute on parameters and return values. +This metadata can only be applied to loads of a pointer type. The optional ``!align`` metadata must reference a single metadata name ```` corresponding to a metadata node with one ``i64`` entry. 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 @@ -629,6 +629,8 @@ ATTR_KIND_SPECULATIVE_LOAD_HARDENING = 59, ATTR_KIND_IMMARG = 60, ATTR_KIND_WILLRETURN = 61, + ATTR_KIND_DEREFERENCEABLE_GLOBALLY = 62, + ATTR_KIND_DEREFERENCEABLE_OR_NULL_GLOBALLY = 63, }; 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 @@ -62,6 +62,15 @@ /// number of bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableOrNullBytes() const; + /// If this argument has the dereferenceable_globally attribute, return the + /// number of bytes known to be dereferenceable. Otherwise, zero is returned. + uint64_t getDereferenceableGloballyBytes() const; + + /// If this argument has the dereferenceable_or_null_globally attribute, + /// return the number of bytes known to be dereferenceable. Otherwise, zero is + /// returned. + uint64_t getDereferenceableOrNullGloballyBytes() const; + /// Return true if this argument has the byval attribute. bool hasByValAttr() 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,11 @@ uint64_t Bytes); static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context, uint64_t Bytes); + static Attribute getWithDereferenceableGloballyBytes(LLVMContext &Context, + uint64_t Bytes); + static Attribute + getWithDereferenceableOrNullGloballyBytes(LLVMContext &Context, + uint64_t Bytes); static Attribute getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, const Optional &NumElemsArg); @@ -164,6 +169,14 @@ /// dereferenceable_or_null attribute. uint64_t getDereferenceableOrNullBytes() const; + /// Returns the number of globally dereferenceable bytes from the + /// dereferenceable_globally attribute. + uint64_t getDereferenceableGloballyBytes() const; + + /// Returns the number of globally dereferenceable_or_null bytes from the + /// dereferenceable_or_null_globally attribute. + uint64_t getDereferenceableOrNullGloballyBytes() const; + /// Returns the argument numbers for the allocsize attribute (or pair(0, 0) /// if not known). std::pair> getAllocSizeArgs() const; @@ -288,6 +301,8 @@ unsigned getStackAlignment() const; uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; + uint64_t getDereferenceableGloballyBytes() const; + uint64_t getDereferenceableOrNullGloballyBytes() const; Type *getByValType() const; std::pair> getAllocSizeArgs() const; std::string getAsString(bool InAttrGrp = false) const; @@ -511,6 +526,32 @@ return addDereferenceableOrNullAttr(C, ArgNo + FirstArgIndex, Bytes); } + /// Add the dereferenceable_globally attribute to the attribute set at the + /// given index. Returns a new list because attribute lists are immutable. + LLVM_NODISCARD AttributeList addDereferenceableGloballyAttr( + LLVMContext &C, unsigned Index, uint64_t Bytes) const; + + /// Add the dereferenceable_globally attribute to the attribute set at the + /// given arg index. Returns a new list because attribute lists are immutable. + LLVM_NODISCARD AttributeList addDereferenceableGloballyParamAttr( + LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const { + return addDereferenceableGloballyAttr(C, ArgNo + FirstArgIndex, Bytes); + } + + /// Add the dereferenceable_or_null_globally attribute to the attribute set at + /// the given index. Returns a new list because attribute lists are immutable. + LLVM_NODISCARD AttributeList addDereferenceableOrNullGloballyAttr( + LLVMContext &C, unsigned Index, uint64_t Bytes) const; + + /// Add the dereferenceable_or_null_globally attribute to the attribute set at + /// the given arg index. Returns a new list because attribute lists are + /// immutable. + LLVM_NODISCARD AttributeList addDereferenceableOrNullGloballyParamAttr( + LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const { + return addDereferenceableOrNullGloballyAttr(C, ArgNo + FirstArgIndex, + Bytes); + } + /// Add the allocsize attribute to the attribute set at the given index. /// Returns a new list because attribute lists are immutable. LLVM_NODISCARD AttributeList @@ -633,6 +674,25 @@ return getDereferenceableOrNullBytes(ArgNo + FirstArgIndex); } + /// Get the number of globally dereferenceable bytes (or zero if unknown). + uint64_t getDereferenceableGloballyBytes(unsigned Index) const; + + /// Get the number of globally dereferenceable bytes (or zero if unknown) of + /// an arg. + uint64_t getParamDereferenceableGloballyBytes(unsigned ArgNo) const { + return getDereferenceableGloballyBytes(ArgNo + FirstArgIndex); + } + + /// Get the number of globally dereferenceable_or_null bytes (or zero if + /// unknown). + uint64_t getDereferenceableOrNullGloballyBytes(unsigned Index) const; + + /// Get the number of globally dereferenceable_or_null bytes (or zero if + /// unknown) of an arg. + uint64_t getParamDereferenceableOrNullGloballyBytes(unsigned ArgNo) const { + return getDereferenceableOrNullGloballyBytes(ArgNo + FirstArgIndex); + } + /// Get the allocsize argument numbers (or pair(0, 0) if unknown). std::pair> getAllocSizeArgs(unsigned Index) const; @@ -709,6 +769,8 @@ uint64_t StackAlignment = 0; uint64_t DerefBytes = 0; uint64_t DerefOrNullBytes = 0; + uint64_t DerefGloballyBytes = 0; + uint64_t DerefOrNullGloballyBytes = 0; uint64_t AllocSizeArgs = 0; Type *ByValType = nullptr; @@ -786,6 +848,19 @@ /// dereferenceable_or_null attribute exists (zero is returned otherwise). uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; } + /// Retrieve the number of globally dereferenceable bytes, if the + /// dereferenceable_globally attribute exists (zero is returned otherwise). + uint64_t getDereferenceableGloballyBytes() const { + return DerefGloballyBytes; + } + + /// Retrieve the number of globally dereferenceable_or_null bytes, if the + /// dereferenceable_or_null_globally attribute exists (zero is returned + /// otherwise). + uint64_t getDereferenceableOrNullGloballyBytes() const { + return DerefOrNullGloballyBytes; + } + /// Retrieve the byval type. Type *getByValType() const { return ByValType; } @@ -809,6 +884,14 @@ /// form used internally in Attribute. AttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes); + /// This turns the number of globally dereferenceable_globally bytes into the + /// form used internally in Attribute. + AttrBuilder &addDereferenceableGloballyAttr(uint64_t Bytes); + + /// This turns the number of dereferenceable_or_null_globally bytes into the + /// form used internally in Attribute. + AttrBuilder &addDereferenceableOrNullGloballyAttr(uint64_t Bytes); + /// This turns one (or two) ints into the form used internally in Attribute. AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg, const Optional &NumElemsArg); 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 @@ -45,6 +45,12 @@ /// Pointer is either null or dereferenceable. def DereferenceableOrNull : EnumAttr<"dereferenceable_or_null">; +/// Pointer is known to be dereferenceable_globally. +def DereferenceableGlobally : EnumAttr<"dereferenceable_globally">; + +/// Pointer is either null or dereferenceable_globally. +def DereferenceableOrNullGlobally : EnumAttr<"dereferenceable_or_null_globally">; + /// Function may only access memory that is inaccessible from IR. def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly">; diff --git a/llvm/include/llvm/IR/CallSite.h b/llvm/include/llvm/IR/CallSite.h --- a/llvm/include/llvm/IR/CallSite.h +++ b/llvm/include/llvm/IR/CallSite.h @@ -432,6 +432,18 @@ CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i)); } + /// Extract the number of globally dereferenceable bytes for a call or + /// parameter (0=unknown). + uint64_t getDereferenceableGloballyBytes(unsigned i) const { + CALLSITE_DELEGATE_GETTER(getDereferenceableGloballyBytes(i)); + } + + /// Extract the number of globally dereferenceable_or_null bytes for a call or + /// parameter (0=unknown). + uint64_t getDereferenceableOrNullGloballyBytes(unsigned i) const { + CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullGloballyBytes(i)); + } + /// Determine if the return value is marked with NoAlias attribute. bool returnDoesNotAlias() const { CALLSITE_DELEGATE_GETTER(returnDoesNotAlias()); 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 @@ -431,6 +431,22 @@ /// attributes for the given arg. void addDereferenceableOrNullParamAttr(unsigned ArgNo, uint64_t Bytes); + /// adds the dereferenceable_globally attribute to the list of attributes. + void addDereferenceableGloballyAttr(unsigned i, uint64_t Bytes); + + /// adds the dereferenceable_globally attribute to the list of attributes for + /// the given arg. + void addDereferenceableGloballyParamAttr(unsigned ArgNo, uint64_t Bytes); + + /// adds the dereferenceable_or_null_globally attribute to the list of + /// attributes. + void addDereferenceableOrNullGloballyAttr(unsigned i, uint64_t Bytes); + + /// adds the dereferenceable_or_null_globally attribute to the list of + /// attributes for the given arg. + void addDereferenceableOrNullGloballyParamAttr(unsigned ArgNo, + uint64_t Bytes); + /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned ArgNo) const { return AttributeSets.getParamAlignment(ArgNo); @@ -469,6 +485,33 @@ return AttributeSets.getParamDereferenceableOrNullBytes(ArgNo); } + /// Extract the number of globally dereferenceable bytes for a call or + /// parameter (0=unknown). + /// @param i AttributeList index, referring to a return value or argument. + uint64_t getDereferenceableGloballyBytes(unsigned i) const { + return AttributeSets.getDereferenceableGloballyBytes(i); + } + + /// Extract the number of globally dereferenceable bytes for a parameter. + /// @param ArgNo Index of an argument, with 0 being the first function arg. + uint64_t getParamDereferenceableGloballyBytes(unsigned ArgNo) const { + return AttributeSets.getParamDereferenceableGloballyBytes(ArgNo); + } + + /// Extract the number of globally dereferenceable_or_null bytes for a call or + /// parameter (0=unknown). + /// @param i AttributeList index, referring to a return value or argument. + uint64_t getDereferenceableOrNullGloballyBytes(unsigned i) const { + return AttributeSets.getDereferenceableOrNullGloballyBytes(i); + } + + /// Extract the number of globally dereferenceable_or_null bytes for a + /// parameter. + /// @param ArgNo AttributeList ArgNo, referring to an argument. + uint64_t getParamDereferenceableOrNullGloballyBytes(unsigned ArgNo) const { + return AttributeSets.getParamDereferenceableOrNullGloballyBytes(ArgNo); + } + /// Determine if the function does not access memory. bool doesNotAccessMemory() const { return hasFnAttribute(Attribute::ReadNone); 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 @@ -1454,6 +1454,21 @@ setAttributes(PAL); } + /// adds the dereferenceable_globally attribute to the list of attributes. + void addDereferenceableGloballyAttr(unsigned i, uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = PAL.addDereferenceableGloballyAttr(getContext(), i, Bytes); + setAttributes(PAL); + } + + /// adds the dereferenceable_or_null_globally attribute to the list of + /// attributes. + void addDereferenceableOrNullGloballyAttr(unsigned i, uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = PAL.addDereferenceableOrNullGloballyAttr(getContext(), i, Bytes); + setAttributes(PAL); + } + /// Determine whether the return value has the given attribute. bool hasRetAttr(Attribute::AttrKind Kind) const; @@ -1592,6 +1607,18 @@ return Attrs.getDereferenceableOrNullBytes(i); } + /// Extract the number of globally dereferenceable bytes for a call or + /// parameter (0=unknown). + uint64_t getDereferenceableGloballyBytes(unsigned i) const { + return Attrs.getDereferenceableGloballyBytes(i); + } + + /// Extract the number of globally dereferenceable_or_null bytes for a call or + /// parameter (0=unknown). + uint64_t getDereferenceableOrNullGloballyBytes(unsigned i) const { + return Attrs.getDereferenceableOrNullGloballyBytes(i); + } + /// Return true if the return value is known to be not null. /// This may be because it has the nonnull attribute, or because at least /// one byte is dereferenceable and the pointer is in addrspace(0). diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -99,6 +99,9 @@ MD_irr_loop = 24, // "irr_loop" MD_access_group = 25, // "llvm.access.group" MD_callback = 26, // "callback" + MD_dereferenceable_globally = 27, // "dereferenceable_globally" + MD_dereferenceable_or_null_globally = + 28, // "dereferenceable_or_null_globally" }; /// Known operand bundle tag IDs, which always have the same value. All 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 @@ -638,6 +638,8 @@ KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(dereferenceable_globally); + KEYWORD(dereferenceable_or_null_globally); KEYWORD(inaccessiblememonly); KEYWORD(inaccessiblemem_or_argmemonly); KEYWORD(inlinehint); 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 @@ -1332,6 +1332,8 @@ case lltok::kw_byval: case lltok::kw_dereferenceable: case lltok::kw_dereferenceable_or_null: + case lltok::kw_dereferenceable_globally: + case lltok::kw_dereferenceable_or_null_globally: case lltok::kw_inalloca: case lltok::kw_nest: case lltok::kw_noalias: @@ -1626,6 +1628,22 @@ B.addDereferenceableOrNullAttr(Bytes); continue; } + case lltok::kw_dereferenceable_globally: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_globally, + Bytes)) + return true; + B.addDereferenceableGloballyAttr(Bytes); + continue; + } + case lltok::kw_dereferenceable_or_null_globally: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes( + lltok::kw_dereferenceable_or_null_globally, Bytes)) + return true; + B.addDereferenceableOrNullGloballyAttr(Bytes); + continue; + } case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; @@ -1714,6 +1732,20 @@ B.addDereferenceableOrNullAttr(Bytes); continue; } + case lltok::kw_dereferenceable_globally: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_globally, Bytes)) + return true; + B.addDereferenceableGloballyAttr(Bytes); + continue; + } + case lltok::kw_dereferenceable_or_null_globally: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null_globally, Bytes)) + return true; + B.addDereferenceableOrNullGloballyAttr(Bytes); + continue; + } case lltok::kw_align: { unsigned Alignment; if (ParseOptionalAlignment(Alignment)) @@ -2078,11 +2110,14 @@ /// ::= /* empty */ /// ::= AttrKind '(' 4 ')' /// -/// where AttrKind is either 'dereferenceable' or 'dereferenceable_or_null'. +/// where AttrKind is either 'dereferenceable', 'dereferenceable_or_null', +/// 'dereferenceable_globally', or 'dereferenceable_or_null_globally'. 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_dereferenceable_globally || + AttrKind == lltok::kw_dereferenceable_or_null_globally) && "contract!"); Bytes = 0; @@ -3372,7 +3407,7 @@ ID.Kind = ValID::t_Constant; return false; } - + // Unary Operators. case lltok::kw_fneg: { unsigned Opc = Lex.getUIntVal(); @@ -3382,7 +3417,7 @@ ParseGlobalTypeAndValue(Val) || ParseToken(lltok::rparen, "expected ')' in unary constantexpr")) return true; - + // Check that the type is valid for the operator. switch (Opc) { case Instruction::FNeg: @@ -4718,7 +4753,7 @@ OPTIONAL(declaration, MDField, ); \ OPTIONAL(name, MDStringField, ); \ OPTIONAL(file, MDField, ); \ - OPTIONAL(line, LineField, ); + OPTIONAL(line, LineField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS 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 @@ -182,6 +182,8 @@ kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_dereferenceable_globally, + kw_dereferenceable_or_null_globally, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, kw_inlinehint, 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 @@ -1284,6 +1284,14 @@ llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; + case Attribute::DereferenceableGlobally: + llvm_unreachable( + "dereferenceable_globally attribute not supported in raw format"); + break; + case Attribute::DereferenceableOrNullGlobally: + llvm_unreachable("dereferenceable_or_null_globally attribute not supported " + "in raw format"); + break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; @@ -1301,6 +1309,8 @@ I = Attribute::AttrKind(I + 1)) { if (I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || + I == Attribute::DereferenceableGlobally || + I == Attribute::DereferenceableOrNullGlobally || I == Attribute::ArgMemOnly || I == Attribute::AllocSize) continue; @@ -1455,6 +1465,10 @@ return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; + case bitc::ATTR_KIND_DEREFERENCEABLE_GLOBALLY: + return Attribute::DereferenceableGlobally; + case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL_GLOBALLY: + return Attribute::DereferenceableOrNullGlobally; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: @@ -1611,6 +1625,10 @@ B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); + else if (Kind == Attribute::DereferenceableGlobally) + B.addDereferenceableGloballyAttr(Record[++i]); + else if (Kind == Attribute::DereferenceableOrNullGlobally) + B.addDereferenceableOrNullGloballyAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else if (Record[i] == 3 || Record[i] == 4) { // String attribute 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 @@ -653,6 +653,10 @@ return bitc::ATTR_KIND_DEREFERENCEABLE; case Attribute::DereferenceableOrNull: return bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL; + case Attribute::DereferenceableGlobally: + return bitc::ATTR_KIND_DEREFERENCEABLE_GLOBALLY; + case Attribute::DereferenceableOrNullGlobally: + return bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL_GLOBALLY; case Attribute::NoRedZone: return bitc::ATTR_KIND_NO_RED_ZONE; case Attribute::NoReturn: 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 @@ -137,6 +137,8 @@ assert((Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || Kind == Attribute::Dereferenceable || Kind == Attribute::DereferenceableOrNull || + Kind == Attribute::DereferenceableGlobally || + Kind == Attribute::DereferenceableOrNullGlobally || Kind == Attribute::AllocSize) && "Wrong kind for int attribute!"); } @@ -212,6 +214,8 @@ unsigned getStackAlignment() const; uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; + uint64_t getDereferenceableGloballyBytes() const; + uint64_t getDereferenceableOrNullGloballyBytes() const; std::pair> getAllocSizeArgs() const; std::string getAsString(bool InAttrGrp) const; Type *getByValType() 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 @@ -167,6 +167,19 @@ return get(Context, DereferenceableOrNull, Bytes); } +Attribute Attribute::getWithDereferenceableGloballyBytes(LLVMContext &Context, + uint64_t Bytes) { + assert(Bytes && "Bytes must be non-zero."); + return get(Context, DereferenceableGlobally, Bytes); +} + +Attribute +Attribute::getWithDereferenceableOrNullGloballyBytes(LLVMContext &Context, + uint64_t Bytes) { + assert(Bytes && "Bytes must be non-zero."); + return get(Context, DereferenceableOrNullGlobally, Bytes); +} + Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { return get(Context, ByVal, Ty); } @@ -270,6 +283,20 @@ return pImpl->getValueAsInt(); } +uint64_t Attribute::getDereferenceableGloballyBytes() const { + assert(hasAttribute(Attribute::DereferenceableGlobally) && + "Trying to get dereferenceable bytes from " + "non-dereferenceable attribute!"); + return pImpl->getValueAsInt(); +} + +uint64_t Attribute::getDereferenceableOrNullGloballyBytes() const { + assert(hasAttribute(Attribute::DereferenceableOrNullGlobally) && + "Trying to get dereferenceable bytes from " + "non-dereferenceable attribute!"); + return pImpl->getValueAsInt(); +} + std::pair> Attribute::getAllocSizeArgs() const { assert(hasAttribute(Attribute::AllocSize) && "Trying to get allocsize args from non-allocsize attribute"); @@ -439,6 +466,12 @@ if (hasAttribute(Attribute::DereferenceableOrNull)) return AttrWithBytesToString("dereferenceable_or_null"); + if (hasAttribute(Attribute::DereferenceableGlobally)) + return AttrWithBytesToString("dereferenceable_globally"); + + if (hasAttribute(Attribute::DereferenceableOrNullGlobally)) + return AttrWithBytesToString("dereferenceable_or_null_globally"); + if (hasAttribute(Attribute::AllocSize)) { unsigned ElemSize; Optional NumElems; @@ -680,6 +713,14 @@ return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0; } +uint64_t AttributeSet::getDereferenceableGloballyBytes() const { + return SetNode ? SetNode->getDereferenceableGloballyBytes() : 0; +} + +uint64_t AttributeSet::getDereferenceableOrNullGloballyBytes() const { + return SetNode ? SetNode->getDereferenceableOrNullGloballyBytes() : 0; +} + Type *AttributeSet::getByValType() const { return SetNode ? SetNode->getByValType() : nullptr; } @@ -784,6 +825,14 @@ Attr = Attribute::getWithDereferenceableOrNullBytes( C, B.getDereferenceableOrNullBytes()); break; + case Attribute::DereferenceableGlobally: + Attr = Attribute::getWithDereferenceableGloballyBytes( + C, B.getDereferenceableGloballyBytes()); + break; + case Attribute::DereferenceableOrNullGlobally: + Attr = Attribute::getWithDereferenceableOrNullGloballyBytes( + C, B.getDereferenceableOrNullGloballyBytes()); + break; case Attribute::AllocSize: { auto A = B.getAllocSizeArgs(); Attr = Attribute::getWithAllocSizeArgs(C, A.first, A.second); @@ -860,6 +909,20 @@ return 0; } +uint64_t AttributeSetNode::getDereferenceableGloballyBytes() const { + for (const auto I : *this) + if (I.hasAttribute(Attribute::DereferenceableGlobally)) + return I.getDereferenceableGloballyBytes(); + return 0; +} + +uint64_t AttributeSetNode::getDereferenceableOrNullGloballyBytes() const { + for (const auto I : *this) + if (I.hasAttribute(Attribute::DereferenceableOrNullGlobally)) + return I.getDereferenceableOrNullGloballyBytes(); + return 0; +} + std::pair> AttributeSetNode::getAllocSizeArgs() const { for (const auto I : *this) @@ -1259,6 +1322,21 @@ return addAttributes(C, Index, B); } +AttributeList +AttributeList::addDereferenceableGloballyAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const { + AttrBuilder B; + B.addDereferenceableGloballyAttr(Bytes); + return addAttributes(C, Index, B); +} + +AttributeList AttributeList::addDereferenceableOrNullGloballyAttr( + LLVMContext &C, unsigned Index, uint64_t Bytes) const { + AttrBuilder B; + B.addDereferenceableOrNullGloballyAttr(Bytes); + return addAttributes(C, Index, B); +} + AttributeList AttributeList::addAllocSizeAttr(LLVMContext &C, unsigned Index, unsigned ElemSizeArg, @@ -1361,6 +1439,14 @@ return getAttributes(Index).getDereferenceableOrNullBytes(); } +uint64_t AttributeList::getDereferenceableGloballyBytes(unsigned Index) const { + return getAttributes(Index).getDereferenceableGloballyBytes(); +} + +uint64_t AttributeList::getDereferenceableOrNullGloballyBytes(unsigned Index) const { + return getAttributes(Index).getDereferenceableOrNullGloballyBytes(); +} + std::pair> AttributeList::getAllocSizeArgs(unsigned Index) const { return getAttributes(Index).getAllocSizeArgs(); @@ -1433,7 +1519,10 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment && - Val != Attribute::Dereferenceable && Val != Attribute::AllocSize && + Val != Attribute::AllocSize && Val != Attribute::Dereferenceable && + Val != Attribute::DereferenceableOrNull && + Val != Attribute::DereferenceableGlobally && + Val != Attribute::DereferenceableOrNullGlobally && "Adding integer attribute without adding a value!"); Attrs[Val] = true; return *this; @@ -1458,6 +1547,10 @@ DerefBytes = Attr.getDereferenceableBytes(); else if (Kind == Attribute::DereferenceableOrNull) DerefOrNullBytes = Attr.getDereferenceableOrNullBytes(); + else if (Kind == Attribute::DereferenceableGlobally) + DerefGloballyBytes = Attr.getDereferenceableGloballyBytes(); + else if (Kind == Attribute::DereferenceableOrNullGlobally) + DerefOrNullGloballyBytes = Attr.getDereferenceableOrNullGloballyBytes(); else if (Kind == Attribute::AllocSize) AllocSizeArgs = Attr.getValueAsInt(); return *this; @@ -1482,6 +1575,10 @@ DerefBytes = 0; else if (Val == Attribute::DereferenceableOrNull) DerefOrNullBytes = 0; + else if (Val == Attribute::DereferenceableGlobally) + DerefGloballyBytes = 0; + else if (Val == Attribute::DereferenceableOrNullGlobally) + DerefOrNullGloballyBytes = 0; else if (Val == Attribute::AllocSize) AllocSizeArgs = 0; @@ -1544,6 +1641,23 @@ return *this; } +AttrBuilder &AttrBuilder::addDereferenceableGloballyAttr(uint64_t Bytes) { + if (Bytes == 0) return *this; + + Attrs[Attribute::DereferenceableGlobally] = true; + DerefGloballyBytes = Bytes; + return *this; +} + +AttrBuilder &AttrBuilder::addDereferenceableOrNullGloballyAttr(uint64_t Bytes) { + if (Bytes == 0) + return *this; + + Attrs[Attribute::DereferenceableOrNullGlobally] = true; + DerefOrNullGloballyBytes = Bytes; + return *this; +} + AttrBuilder &AttrBuilder::addAllocSizeAttr(unsigned ElemSize, const Optional &NumElems) { return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems)); @@ -1698,6 +1812,8 @@ .addAttribute(Attribute::NonNull) .addDereferenceableAttr(1) // the int here is ignored .addDereferenceableOrNullAttr(1) // the int here is ignored + .addDereferenceableGloballyAttr(1) // the int here is ignored + .addDereferenceableOrNullGloballyAttr(1) // the int here is ignored .addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::StructRet) 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 @@ -130,6 +130,18 @@ return getParent()->getParamDereferenceableOrNullBytes(getArgNo()); } +uint64_t Argument::getDereferenceableGloballyBytes() const { + assert(getType()->isPointerTy() && + "Only pointers have dereferenceable bytes"); + return getParent()->getParamDereferenceableGloballyBytes(getArgNo()); +} + +uint64_t Argument::getDereferenceableOrNullGloballyBytes() const { + assert(getType()->isPointerTy() && + "Only pointers have dereferenceable bytes"); + return getParent()->getParamDereferenceableOrNullGloballyBytes(getArgNo()); +} + bool Argument::hasNestAttr() const { if (!getType()->isPointerTy()) return false; return hasAttribute(Attribute::Nest); @@ -474,6 +486,32 @@ setAttributes(PAL); } +void Function::addDereferenceableGloballyAttr(unsigned i, uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = PAL.addDereferenceableGloballyAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + +void Function::addDereferenceableGloballyParamAttr(unsigned ArgNo, uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = PAL.addDereferenceableGloballyParamAttr(getContext(), ArgNo, Bytes); + setAttributes(PAL); +} + +void Function::addDereferenceableOrNullGloballyAttr(unsigned i, uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = PAL.addDereferenceableOrNullGloballyAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + +void Function::addDereferenceableOrNullGloballyParamAttr(unsigned ArgNo, + uint64_t Bytes) { + AttributeList PAL = getAttributes(); + PAL = + PAL.addDereferenceableOrNullGloballyParamAttr(getContext(), ArgNo, Bytes); + setAttributes(PAL); +} + const std::string &Function::getGC() const { assert(hasGC() && "Function has no collector"); return getContext().getGC(*this); diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -63,6 +63,8 @@ {MD_irr_loop, "irr_loop"}, {MD_access_group, "llvm.access.group"}, {MD_callback, "callback"}, + {MD_dereferenceable_globally, "dereferenceable_globally"}, + {MD_dereferenceable_or_null_globally, "dereferenceable_or_null_globally"}, }; for (auto &MDKind : MDKinds) { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3100,7 +3100,7 @@ /// visitUnaryOperator - Check the argument to the unary operator. /// void Verifier::visitUnaryOperator(UnaryOperator &U) { - Assert(U.getType() == U.getOperand(0)->getType(), + Assert(U.getType() == U.getOperand(0)->getType(), "Unary operators must have same type for" "operands and result!", &U); @@ -3971,16 +3971,25 @@ } void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) { - Assert(I.getType()->isPointerTy(), "dereferenceable, dereferenceable_or_null " - "apply only to pointer types", &I); + Assert(I.getType()->isPointerTy(), + "dereferenceable, dereferenceable_or_null, dereferenceable_globally, " + "and dereferenceable_or_null_globally apply only to pointer types", + &I); Assert(isa(I), - "dereferenceable, dereferenceable_or_null apply only to load" - " instructions, use attributes for calls or invokes", &I); - Assert(MD->getNumOperands() == 1, "dereferenceable, dereferenceable_or_null " - "take one operand!", &I); + "dereferenceable, dereferenceable_or_null, dereferenceable_globally, " + "and dereferenceable_or_null_globally apply only to load " + "instructions, use attributes for calls or invokes", + &I); + Assert(MD->getNumOperands() == 1, + "dereferenceable, dereferenceable_or_null, dereferenceable_globally, " + "and dereferenceable_or_null_globally take one operand!", + &I); ConstantInt *CI = mdconst::dyn_extract(MD->getOperand(0)); - Assert(CI && CI->getType()->isIntegerTy(64), "dereferenceable, " - "dereferenceable_or_null metadata value must be an i64!", &I); + Assert(CI && CI->getType()->isIntegerTy(64), + "dereferenceable, " + "dereferenceable_or_null, dereferenceable_globally, and " + "dereferenceable_or_null_globally metadata value must be an i64!", + &I); } /// verifyInstruction - Verify that an instruction is well formed. @@ -4115,11 +4124,12 @@ &I); } - if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable)) - visitDereferenceableMetadata(I, MD); - - if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable_or_null)) - visitDereferenceableMetadata(I, MD); + for (auto ID : {LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_dereferenceable_globally, + LLVMContext::MD_dereferenceable_or_null_globally}) + if (MDNode *MD = I.getMetadata(ID)) + visitDereferenceableMetadata(I, MD); if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa)) TBAAVerifyHelper.visitTBAAMetadata(I, TBAA); @@ -4755,7 +4765,7 @@ "Intrinsic first argument's type must be smaller than result type", &FPI); } - } + } break; default: @@ -5018,7 +5028,7 @@ bool runOnFunction(Function &F) override { if (!V->verify(F) && FatalErrors) { - errs() << "in function " << F.getName() << '\n'; + errs() << "in function " << F.getName() << '\n'; report_fatal_error("Broken function found, compilation aborted!"); } return false; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -500,6 +500,8 @@ case LLVMContext::MD_align: case LLVMContext::MD_dereferenceable: case LLVMContext::MD_dereferenceable_or_null: + case LLVMContext::MD_dereferenceable_globally: + case LLVMContext::MD_dereferenceable_or_null_globally: // These only directly apply if the new type is also a pointer. if (NewTy->isPointerTy()) NewLoad->setMetadata(ID, N); @@ -559,6 +561,8 @@ case LLVMContext::MD_align: case LLVMContext::MD_dereferenceable: case LLVMContext::MD_dereferenceable_or_null: + case LLVMContext::MD_dereferenceable_globally: + case LLVMContext::MD_dereferenceable_or_null_globally: // These don't apply for stores. break; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -608,6 +608,8 @@ LLVMContext::MD_align, LLVMContext::MD_dereferenceable, LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_dereferenceable_globally, + LLVMContext::MD_dereferenceable_or_null_globally, LLVMContext::MD_access_group, }; 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 @@ -778,6 +778,8 @@ case Attribute::Convergent: case Attribute::Dereferenceable: case Attribute::DereferenceableOrNull: + case Attribute::DereferenceableGlobally: + case Attribute::DereferenceableOrNullGlobally: case Attribute::InAlloca: case Attribute::InReg: case Attribute::InaccessibleMemOnly: diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2360,6 +2360,8 @@ break; case LLVMContext::MD_dereferenceable: case LLVMContext::MD_dereferenceable_or_null: + case LLVMContext::MD_dereferenceable_globally: + case LLVMContext::MD_dereferenceable_or_null_globally: K->setMetadata(Kind, MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD)); break; @@ -2385,6 +2387,8 @@ LLVMContext::MD_invariant_group, LLVMContext::MD_align, LLVMContext::MD_dereferenceable, LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_dereferenceable_globally, + LLVMContext::MD_dereferenceable_or_null_globally, LLVMContext::MD_access_group}; combineMetadata(K, J, KnownIDs, KDominatesJ); } diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1312,6 +1312,8 @@ LLVMContext::MD_align, LLVMContext::MD_dereferenceable, LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_dereferenceable_globally, + LLVMContext::MD_dereferenceable_or_null_globally, LLVMContext::MD_mem_parallel_loop_access, LLVMContext::MD_access_group}; combineMetadata(I1, I2, KnownIDs, true); 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 @@ -357,6 +357,21 @@ ret void } +; CHECK: define dereferenceable_globally(2) i8* @f61(i8* dereferenceable_globally(1) %a) { +define dereferenceable_globally(2) i8* @f61(i8* dereferenceable_globally(1) %a) { + ret i8* %a +} + +; CHECK: define dereferenceable_globally(18446744073709551606) i8* @f62(i8* dereferenceable_globally(18446744073709551615) %a) { +define dereferenceable_globally(18446744073709551606) i8* @f62(i8* dereferenceable_globally(18446744073709551615) %a) { + ret i8* %a +} + +; CHECK: define dereferenceable_or_null_globally(8) i8* @f63(i8* dereferenceable_or_null_globally(8) %foo) +define dereferenceable_or_null_globally(8) i8* @f63(i8* dereferenceable_or_null_globally(8) %foo) { + ret i8* %foo +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } diff --git a/llvm/test/Verifier/dereferenceable-globally-md.ll b/llvm/test/Verifier/dereferenceable-globally-md.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/dereferenceable-globally-md.ll @@ -0,0 +1,86 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +declare i8* @foo() + +define void @f1() { +entry: + call i8* @foo(), !dereferenceable_globally !{i64 2} + ret void +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally apply only to load instructions, use attributes for calls or invokes +; CHECK-NEXT: call i8* @foo() + +define void @f2() { +entry: + call i8* @foo(), !dereferenceable_or_null_globally !{i64 2} + ret void +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally apply only to load instructions, use attributes for calls or invokes +; CHECK-NEXT: call i8* @foo() + +define i8 @f3(i8* %x) { +entry: + %y = load i8, i8* %x, !dereferenceable_globally !{i64 2} + ret i8 %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally apply only to pointer types +; CHECK-NEXT: load i8, i8* %x + +define i8 @f4(i8* %x) { +entry: + %y = load i8, i8* %x, !dereferenceable_or_null_globally !{i64 2} + ret i8 %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally apply only to pointer types +; CHECK-NEXT: load i8, i8* %x + +define i8* @f5(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_globally !{} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally take one operand +; CHECK-NEXT: load i8*, i8** %x + + +define i8* @f6(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_or_null_globally !{} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally take one operand +; CHECK-NEXT: load i8*, i8** %x + +define i8* @f7(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_globally !{!"str"} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally metadata value must be an i64! +; CHECK-NEXT: load i8*, i8** %x + + +define i8* @f8(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_or_null_globally !{!"str"} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally metadata value must be an i64! +; CHECK-NEXT: load i8*, i8** %x + +define i8* @f9(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_globally !{i32 2} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally metadata value must be an i64! +; CHECK-NEXT: load i8*, i8** %x + + +define i8* @f10(i8** %x) { +entry: + %y = load i8*, i8** %x, !dereferenceable_or_null_globally !{i32 2} + ret i8* %y +} +; CHECK: dereferenceable_globally, dereferenceable_or_null_globally metadata value must be an i64! +; CHECK-NEXT: load i8*, i8** %x