1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[IR] Introduce a dereferenceable_or_null(N) attribute.

Summary:
If a pointer is marked as dereferenceable_or_null(N), LLVM assumes it
is either `null` or `dereferenceable(N)` or both.  This change only
introduces the attribute and adds a token test case for the `llvm-as`
/ `llvm-dis`.  It does not hook up other parts of the optimizer to
actually exploit the attribute -- those changes will come later.

For pointers in address space 0, `dereferenceable(N)` is now exactly
equivalent to `dereferenceable_or_null(N)` && `nonnull`.  For other
address spaces, `dereferenceable(N)` is potentially weaker than
`dereferenceable_or_null(N)` && `nonnull` (since we could have a null
`dereferenceable(N)` pointer).

The motivating case for this change is Java (and other managed
languages), where pointers are either `null` or dereferenceable up to
some usually known-at-compile-time constant offset.

Reviewers: rafael, hfinkel

Reviewed By: hfinkel

Subscribers: nicholas, llvm-commits

Differential Revision: http://reviews.llvm.org/D8650

llvm-svn: 235132
This commit is contained in:
Sanjoy Das 2015-04-16 20:29:50 +00:00
parent a233dc55a3
commit 2d08e46e8b
17 changed files with 181 additions and 31 deletions

View File

@ -1012,6 +1012,19 @@ Currently, only the following parameter attributes are defined:
array), however ``dereferenceable(<n>)`` does imply ``nonnull`` in array), however ``dereferenceable(<n>)`` does imply ``nonnull`` in
``addrspace(0)`` (which is the default address space). ``addrspace(0)`` (which is the default address space).
``dereferenceable_or_null(<n>)``
This indicates that the parameter or return value isn't both
non-null and non-dereferenceable (up to ``<n>`` bytes) at the same
time. All non-null pointers tagged with
``dereferenceable_or_null(<n>)`` are ``dereferenceable(<n>)``.
For address space 0 ``dereferenceable_or_null(<n>)`` implies that
a pointer is exactly one of ``dereferenceable(<n>)`` or ``null``,
and in other address spaces ``dereferenceable_or_null(<n>)``
implies that a pointer is at least one of ``dereferenceable(<n>)``
or ``null`` (i.e. it may be both ``null`` and
``dereferenceable(<n>)``). This attribute may only be applied to
pointer typed parameters.
.. _gc: .. _gc:
Garbage Collector Strategy Names Garbage Collector Strategy Names

View File

@ -169,6 +169,7 @@ typedef enum {
LLVMNonNullAttribute = 1ULL << 37, LLVMNonNullAttribute = 1ULL << 37,
LLVMJumpTableAttribute = 1ULL << 38, LLVMJumpTableAttribute = 1ULL << 38,
LLVMDereferenceableAttribute = 1ULL << 39, LLVMDereferenceableAttribute = 1ULL << 39,
LLVMDereferenceableOrNullAttribute = 1ULL << 40,
*/ */
} LLVMAttribute; } LLVMAttribute;

View File

@ -397,7 +397,8 @@ namespace bitc {
ATTR_KIND_IN_ALLOCA = 38, ATTR_KIND_IN_ALLOCA = 38,
ATTR_KIND_NON_NULL = 39, ATTR_KIND_NON_NULL = 39,
ATTR_KIND_JUMP_TABLE = 40, ATTR_KIND_JUMP_TABLE = 40,
ATTR_KIND_DEREFERENCEABLE = 41 ATTR_KIND_DEREFERENCEABLE = 41,
ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42
}; };
enum ComdatSelectionKindCodes { enum ComdatSelectionKindCodes {

View File

@ -89,6 +89,7 @@ public:
///< often, so lazy binding isn't worthwhile ///< often, so lazy binding isn't worthwhile
NonNull, ///< Pointer is known to be not null NonNull, ///< Pointer is known to be not null
Dereferenceable, ///< Pointer is known to be dereferenceable Dereferenceable, ///< Pointer is known to be dereferenceable
DereferenceableOrNull, ///< Pointer is either null or dereferenceable
NoRedZone, ///< Disable redzone NoRedZone, ///< Disable redzone
NoReturn, ///< Mark the function as not returning NoReturn, ///< Mark the function as not returning
NoUnwind, ///< Function doesn't unwind stack NoUnwind, ///< Function doesn't unwind stack
@ -136,6 +137,8 @@ public:
static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align); static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align);
static Attribute getWithDereferenceableBytes(LLVMContext &Context, static Attribute getWithDereferenceableBytes(LLVMContext &Context,
uint64_t Bytes); uint64_t Bytes);
static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context,
uint64_t Bytes);
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Attribute Accessors // Attribute Accessors
@ -185,6 +188,10 @@ public:
/// dereferenceable attribute (or zero if unknown). /// dereferenceable attribute (or zero if unknown).
uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableBytes() const;
/// \brief Returns the number of dereferenceable_or_null bytes from the
/// dereferenceable_or_null attribute (or zero if unknown).
uint64_t getDereferenceableOrNullBytes() const;
/// \brief The Attribute is converted to a string of equivalent mnemonic. This /// \brief The Attribute is converted to a string of equivalent mnemonic. This
/// is, presumably, for writing out the mnemonics for the assembly writer. /// is, presumably, for writing out the mnemonics for the assembly writer.
std::string getAsString(bool InAttrGrp = false) const; std::string getAsString(bool InAttrGrp = false) const;
@ -287,6 +294,12 @@ public:
AttributeSet addDereferenceableAttr(LLVMContext &C, unsigned Index, AttributeSet addDereferenceableAttr(LLVMContext &C, unsigned Index,
uint64_t Bytes) const; uint64_t Bytes) const;
/// \brief Add the dereferenceable_or_null attribute to the attribute set at
/// the given index. Since attribute sets are immutable, this returns a new
/// set.
AttributeSet addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index,
uint64_t Bytes) const;
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// AttributeSet Accessors // AttributeSet Accessors
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
@ -331,6 +344,10 @@ public:
/// \brief Get the number of dereferenceable bytes (or zero if unknown). /// \brief Get the number of dereferenceable bytes (or zero if unknown).
uint64_t getDereferenceableBytes(unsigned Index) const; uint64_t getDereferenceableBytes(unsigned Index) const;
/// \brief Get the number of dereferenceable_or_null bytes (or zero if
/// unknown).
uint64_t getDereferenceableOrNullBytes(unsigned Index) const;
/// \brief Return the attributes at the index as a string. /// \brief Return the attributes at the index as a string.
std::string getAsString(unsigned Index, bool InAttrGrp = false) const; std::string getAsString(unsigned Index, bool InAttrGrp = false) const;
@ -411,6 +428,7 @@ class AttrBuilder {
uint64_t Alignment; uint64_t Alignment;
uint64_t StackAlignment; uint64_t StackAlignment;
uint64_t DerefBytes; uint64_t DerefBytes;
uint64_t DerefOrNullBytes;
public: public:
AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {} AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {}
explicit AttrBuilder(uint64_t Val) explicit AttrBuilder(uint64_t Val)
@ -476,6 +494,10 @@ public:
/// attribute exists (zero is returned otherwise). /// attribute exists (zero is returned otherwise).
uint64_t getDereferenceableBytes() const { return DerefBytes; } uint64_t getDereferenceableBytes() const { return DerefBytes; }
/// \brief Retrieve the number of dereferenceable_or_null bytes, if the
/// dereferenceable_or_null attribute exists (zero is returned otherwise).
uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; }
/// \brief This turns an int alignment (which must be a power of 2) into the /// \brief This turns an int alignment (which must be a power of 2) into the
/// form used internally in Attribute. /// form used internally in Attribute.
AttrBuilder &addAlignmentAttr(unsigned Align); AttrBuilder &addAlignmentAttr(unsigned Align);
@ -488,6 +510,10 @@ public:
/// internally in Attribute. /// internally in Attribute.
AttrBuilder &addDereferenceableAttr(uint64_t Bytes); AttrBuilder &addDereferenceableAttr(uint64_t Bytes);
/// \brief This turns the number of dereferenceable_or_null bytes into the
/// form used internally in Attribute.
AttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes);
/// \brief Return true if the builder contains no target-independent /// \brief Return true if the builder contains no target-independent
/// attributes. /// attributes.
bool empty() const { return Attrs.none(); } bool empty() const { return Attrs.none(); }

View File

@ -223,6 +223,10 @@ public:
/// @brief adds the dereferenceable attribute to the list of attributes. /// @brief adds the dereferenceable attribute to the list of attributes.
void addDereferenceableAttr(unsigned i, uint64_t Bytes); void addDereferenceableAttr(unsigned i, uint64_t Bytes);
/// @brief adds the dereferenceable_or_null attribute to the list of
/// attributes.
void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes);
/// @brief Extract the alignment for a call or parameter (0=unknown). /// @brief Extract the alignment for a call or parameter (0=unknown).
unsigned getParamAlignment(unsigned i) const { unsigned getParamAlignment(unsigned i) const {
return AttributeSets.getParamAlignment(i); return AttributeSets.getParamAlignment(i);

View File

@ -1412,6 +1412,10 @@ public:
/// \brief adds the dereferenceable attribute to the list of attributes. /// \brief adds the dereferenceable attribute to the list of attributes.
void addDereferenceableAttr(unsigned i, uint64_t Bytes); void addDereferenceableAttr(unsigned i, uint64_t Bytes);
/// \brief adds the dereferenceable_or_null attribute to the list of
/// attributes.
void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes);
/// \brief Determine whether this call has the given attribute. /// \brief Determine whether this call has the given attribute.
bool hasFnAttr(Attribute::AttrKind A) const { bool hasFnAttr(Attribute::AttrKind A) const {
assert(A != Attribute::NoBuiltin && assert(A != Attribute::NoBuiltin &&
@ -3104,6 +3108,10 @@ public:
/// \brief adds the dereferenceable attribute to the list of attributes. /// \brief adds the dereferenceable attribute to the list of attributes.
void addDereferenceableAttr(unsigned i, uint64_t Bytes); void addDereferenceableAttr(unsigned i, uint64_t Bytes);
/// \brief adds the dereferenceable_or_null attribute to the list of
/// attributes.
void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes);
/// \brief Determine whether this call has the given attribute. /// \brief Determine whether this call has the given attribute.
bool hasFnAttr(Attribute::AttrKind A) const { bool hasFnAttr(Attribute::AttrKind A) const {
assert(A != Attribute::NoBuiltin && assert(A != Attribute::NoBuiltin &&

View File

@ -598,6 +598,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(inalloca); KEYWORD(inalloca);
KEYWORD(cold); KEYWORD(cold);
KEYWORD(dereferenceable); KEYWORD(dereferenceable);
KEYWORD(dereferenceable_or_null);
KEYWORD(inlinehint); KEYWORD(inlinehint);
KEYWORD(inreg); KEYWORD(inreg);
KEYWORD(jumptable); KEYWORD(jumptable);

View File

@ -976,6 +976,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
break; break;
case lltok::kw_byval: case lltok::kw_byval:
case lltok::kw_dereferenceable: case lltok::kw_dereferenceable:
case lltok::kw_dereferenceable_or_null:
case lltok::kw_inalloca: case lltok::kw_inalloca:
case lltok::kw_nest: case lltok::kw_nest:
case lltok::kw_noalias: case lltok::kw_noalias:
@ -1220,11 +1221,18 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break; case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
case lltok::kw_dereferenceable: { case lltok::kw_dereferenceable: {
uint64_t Bytes; uint64_t Bytes;
if (ParseOptionalDereferenceableBytes(Bytes)) if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
return true; return true;
B.addDereferenceableAttr(Bytes); B.addDereferenceableAttr(Bytes);
continue; continue;
} }
case lltok::kw_dereferenceable_or_null: {
uint64_t Bytes;
if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
return true;
B.addDereferenceableOrNullAttr(Bytes);
continue;
}
case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break;
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
@ -1284,11 +1292,18 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
return HaveError; return HaveError;
case lltok::kw_dereferenceable: { case lltok::kw_dereferenceable: {
uint64_t Bytes; uint64_t Bytes;
if (ParseOptionalDereferenceableBytes(Bytes)) if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
return true; return true;
B.addDereferenceableAttr(Bytes); B.addDereferenceableAttr(Bytes);
continue; continue;
} }
case lltok::kw_dereferenceable_or_null: {
uint64_t Bytes;
if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
return true;
B.addDereferenceableOrNullAttr(Bytes);
continue;
}
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break; case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
@ -1516,12 +1531,19 @@ bool LLParser::ParseOptionalAlignment(unsigned &Alignment) {
return false; return false;
} }
/// ParseOptionalDereferenceableBytes /// ParseOptionalDerefAttrBytes
/// ::= /* empty */ /// ::= /* empty */
/// ::= 'dereferenceable' '(' 4 ')' /// ::= AttrKind '(' 4 ')'
bool LLParser::ParseOptionalDereferenceableBytes(uint64_t &Bytes) { ///
/// where AttrKind is either 'dereferenceable' or 'dereferenceable_or_null'.
bool LLParser::ParseOptionalDerefAttrBytes(lltok::Kind AttrKind,
uint64_t &Bytes) {
assert((AttrKind == lltok::kw_dereferenceable ||
AttrKind == lltok::kw_dereferenceable_or_null) &&
"contract!");
Bytes = 0; Bytes = 0;
if (!EatIfPresent(lltok::kw_dereferenceable)) if (!EatIfPresent(AttrKind))
return false; return false;
LocTy ParenLoc = Lex.getLoc(); LocTy ParenLoc = Lex.getLoc();
if (!EatIfPresent(lltok::lparen)) if (!EatIfPresent(lltok::lparen))

View File

@ -223,7 +223,7 @@ namespace llvm {
bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass); bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass);
bool ParseOptionalCallingConv(unsigned &CC); bool ParseOptionalCallingConv(unsigned &CC);
bool ParseOptionalAlignment(unsigned &Alignment); bool ParseOptionalAlignment(unsigned &Alignment);
bool ParseOptionalDereferenceableBytes(uint64_t &Bytes); bool ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope,
AtomicOrdering &Ordering); AtomicOrdering &Ordering);
bool ParseOrdering(AtomicOrdering &Ordering); bool ParseOrdering(AtomicOrdering &Ordering);

View File

@ -106,6 +106,7 @@ namespace lltok {
kw_inalloca, kw_inalloca,
kw_cold, kw_cold,
kw_dereferenceable, kw_dereferenceable,
kw_dereferenceable_or_null,
kw_inlinehint, kw_inlinehint,
kw_inreg, kw_inreg,
kw_jumptable, kw_jumptable,

View File

@ -1098,6 +1098,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
return Attribute::NonNull; return Attribute::NonNull;
case bitc::ATTR_KIND_DEREFERENCEABLE: case bitc::ATTR_KIND_DEREFERENCEABLE:
return Attribute::Dereferenceable; return Attribute::Dereferenceable;
case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL:
return Attribute::DereferenceableOrNull;
case bitc::ATTR_KIND_NO_RED_ZONE: case bitc::ATTR_KIND_NO_RED_ZONE:
return Attribute::NoRedZone; return Attribute::NoRedZone;
case bitc::ATTR_KIND_NO_RETURN: case bitc::ATTR_KIND_NO_RETURN:
@ -1214,6 +1216,8 @@ std::error_code BitcodeReader::ParseAttributeGroupBlock() {
B.addStackAlignmentAttr(Record[++i]); B.addStackAlignmentAttr(Record[++i]);
else if (Kind == Attribute::Dereferenceable) else if (Kind == Attribute::Dereferenceable)
B.addDereferenceableAttr(Record[++i]); B.addDereferenceableAttr(Record[++i]);
else if (Kind == Attribute::DereferenceableOrNull)
B.addDereferenceableOrNullAttr(Record[++i]);
} else { // String attribute } else { // String attribute
assert((Record[i] == 3 || Record[i] == 4) && assert((Record[i] == 3 || Record[i] == 4) &&
"Invalid attribute group entry"); "Invalid attribute group entry");

View File

@ -200,6 +200,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NON_NULL; return bitc::ATTR_KIND_NON_NULL;
case Attribute::Dereferenceable: case Attribute::Dereferenceable:
return bitc::ATTR_KIND_DEREFERENCEABLE; return bitc::ATTR_KIND_DEREFERENCEABLE;
case Attribute::DereferenceableOrNull:
return bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL;
case Attribute::NoRedZone: case Attribute::NoRedZone:
return bitc::ATTR_KIND_NO_RED_ZONE; return bitc::ATTR_KIND_NO_RED_ZONE;
case Attribute::NoReturn: case Attribute::NoReturn:

View File

@ -115,9 +115,9 @@ class IntAttributeImpl : public EnumAttributeImpl {
public: public:
IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val) IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val)
: EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) {
assert( assert((Kind == Attribute::Alignment || Kind == Attribute::StackAlignment ||
(Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || Kind == Attribute::Dereferenceable ||
Kind == Attribute::Dereferenceable) && Kind == Attribute::DereferenceableOrNull) &&
"Wrong kind for int attribute!"); "Wrong kind for int attribute!");
} }

View File

@ -94,6 +94,12 @@ Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
return get(Context, Dereferenceable, Bytes); return get(Context, Dereferenceable, Bytes);
} }
Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,
uint64_t Bytes) {
assert(Bytes && "Bytes must be non-zero.");
return get(Context, DereferenceableOrNull, Bytes);
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Attribute Accessor Methods // Attribute Accessor Methods
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -170,6 +176,13 @@ uint64_t Attribute::getDereferenceableBytes() const {
return pImpl->getValueAsInt(); return pImpl->getValueAsInt();
} }
uint64_t Attribute::getDereferenceableOrNullBytes() const {
assert(hasAttribute(Attribute::DereferenceableOrNull) &&
"Trying to get dereferenceable bytes from "
"non-dereferenceable attribute!");
return pImpl->getValueAsInt();
}
std::string Attribute::getAsString(bool InAttrGrp) const { std::string Attribute::getAsString(bool InAttrGrp) const {
if (!pImpl) return ""; if (!pImpl) return "";
@ -263,9 +276,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return Result; return Result;
} }
if (hasAttribute(Attribute::StackAlignment)) { auto AttrWithBytesToString = [&](const char *Name) {
std::string Result; std::string Result;
Result += "alignstack"; Result += Name;
if (InAttrGrp) { if (InAttrGrp) {
Result += "="; Result += "=";
Result += utostr(getValueAsInt()); Result += utostr(getValueAsInt());
@ -275,21 +288,16 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
Result += ")"; Result += ")";
} }
return Result; return Result;
} };
if (hasAttribute(Attribute::Dereferenceable)) { if (hasAttribute(Attribute::StackAlignment))
std::string Result; return AttrWithBytesToString("alignstack");
Result += "dereferenceable";
if (InAttrGrp) { if (hasAttribute(Attribute::Dereferenceable))
Result += "="; return AttrWithBytesToString("dereferenceable");
Result += utostr(getValueAsInt());
} else { if (hasAttribute(Attribute::DereferenceableOrNull))
Result += "("; return AttrWithBytesToString("dereferenceable_or_null");
Result += utostr(getValueAsInt());
Result += ")";
}
return Result;
}
// Convert target-dependent attributes to strings of the form: // Convert target-dependent attributes to strings of the form:
// //
@ -428,6 +436,11 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::JumpTable: return 1ULL << 45; case Attribute::JumpTable: return 1ULL << 45;
case Attribute::Dereferenceable: case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format"); llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
case Attribute::DereferenceableOrNull:
llvm_unreachable("dereferenceable_or_null attribute not supported in raw "
"format");
break;
} }
llvm_unreachable("Unsupported attribute type"); llvm_unreachable("Unsupported attribute type");
} }
@ -663,6 +676,10 @@ AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index,
Attrs.push_back(std::make_pair(Index, Attrs.push_back(std::make_pair(Index,
Attribute::getWithDereferenceableBytes(C, Attribute::getWithDereferenceableBytes(C,
B.getDereferenceableBytes()))); B.getDereferenceableBytes())));
else if (Kind == Attribute::DereferenceableOrNull)
Attrs.push_back(
std::make_pair(Index, Attribute::getWithDereferenceableOrNullBytes(
C, B.getDereferenceableOrNullBytes())));
else else
Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind))); Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind)));
} }
@ -842,6 +859,14 @@ AttributeSet AttributeSet::addDereferenceableAttr(LLVMContext &C, unsigned Index
return addAttributes(C, Index, AttributeSet::get(C, Index, B)); return addAttributes(C, Index, AttributeSet::get(C, Index, B));
} }
AttributeSet AttributeSet::addDereferenceableOrNullAttr(LLVMContext &C,
unsigned Index,
uint64_t Bytes) const {
llvm::AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
return addAttributes(C, Index, AttributeSet::get(C, Index, B));
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// AttributeSet Accessor Methods // AttributeSet Accessor Methods
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -1011,7 +1036,8 @@ void AttributeSet::dump() const {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index) AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
DerefOrNullBytes(0) {
AttributeSetImpl *pImpl = AS.pImpl; AttributeSetImpl *pImpl = AS.pImpl;
if (!pImpl) return; if (!pImpl) return;
@ -1028,7 +1054,7 @@ AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
void AttrBuilder::clear() { void AttrBuilder::clear() {
Attrs.reset(); Attrs.reset();
Alignment = StackAlignment = DerefBytes = 0; Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0;
} }
AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
@ -1055,6 +1081,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
StackAlignment = Attr.getStackAlignment(); StackAlignment = Attr.getStackAlignment();
else if (Kind == Attribute::Dereferenceable) else if (Kind == Attribute::Dereferenceable)
DerefBytes = Attr.getDereferenceableBytes(); DerefBytes = Attr.getDereferenceableBytes();
else if (Kind == Attribute::DereferenceableOrNull)
DerefOrNullBytes = Attr.getDereferenceableOrNullBytes();
return *this; return *this;
} }
@ -1073,6 +1101,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
StackAlignment = 0; StackAlignment = 0;
else if (Val == Attribute::Dereferenceable) else if (Val == Attribute::Dereferenceable)
DerefBytes = 0; DerefBytes = 0;
else if (Val == Attribute::DereferenceableOrNull)
DerefOrNullBytes = 0;
return *this; return *this;
} }
@ -1099,6 +1129,8 @@ AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) {
StackAlignment = 0; StackAlignment = 0;
else if (Kind == Attribute::Dereferenceable) else if (Kind == Attribute::Dereferenceable)
DerefBytes = 0; DerefBytes = 0;
else if (Kind == Attribute::DereferenceableOrNull)
DerefOrNullBytes = 0;
} else { } else {
assert(Attr.isStringAttribute() && "Invalid attribute type!"); assert(Attr.isStringAttribute() && "Invalid attribute type!");
std::map<std::string, std::string>::iterator std::map<std::string, std::string>::iterator
@ -1149,6 +1181,15 @@ AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
return *this; return *this;
} }
AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
if (Bytes == 0)
return *this;
Attrs[Attribute::DereferenceableOrNull] = true;
DerefOrNullBytes = Bytes;
return *this;
}
AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
// FIXME: What if both have alignments, but they don't match?! // FIXME: What if both have alignments, but they don't match?!
if (!Alignment) if (!Alignment)
@ -1225,7 +1266,8 @@ AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {
for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
I = Attribute::AttrKind(I + 1)) { I = Attribute::AttrKind(I + 1)) {
if (I == Attribute::Dereferenceable) if (I == Attribute::Dereferenceable ||
I == Attribute::DereferenceableOrNull)
continue; continue;
if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) { if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
Attrs[I] = true; Attrs[I] = true;
@ -1261,6 +1303,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
.addAttribute(Attribute::NoCapture) .addAttribute(Attribute::NoCapture)
.addAttribute(Attribute::NonNull) .addAttribute(Attribute::NonNull)
.addDereferenceableAttr(1) // the int here is ignored .addDereferenceableAttr(1) // the int here is ignored
.addDereferenceableOrNullAttr(1) // the int here is ignored
.addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::StructRet) .addAttribute(Attribute::StructRet)

View File

@ -348,6 +348,12 @@ void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
setAttributes(PAL); setAttributes(PAL);
} }
void Function::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
AttributeSet PAL = getAttributes();
PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes);
setAttributes(PAL);
}
// Maintain the GC name for each function in an on-the-side table. This saves // Maintain the GC name for each function in an on-the-side table. This saves
// allocating an additional word in Function for programs which do not use GC // allocating an additional word in Function for programs which do not use GC
// (i.e., most programs) at the cost of increased overhead for clients which do // (i.e., most programs) at the cost of increased overhead for clients which do

View File

@ -352,6 +352,12 @@ void CallInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
setAttributes(PAL); setAttributes(PAL);
} }
void CallInst::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
AttributeSet PAL = getAttributes();
PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes);
setAttributes(PAL);
}
bool CallInst::hasFnAttrImpl(Attribute::AttrKind A) const { bool CallInst::hasFnAttrImpl(Attribute::AttrKind A) const {
if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A)) if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A))
return true; return true;
@ -617,6 +623,12 @@ void InvokeInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
setAttributes(PAL); setAttributes(PAL);
} }
void InvokeInst::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
AttributeSet PAL = getAttributes();
PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes);
setAttributes(PAL);
}
LandingPadInst *InvokeInst::getLandingPadInst() const { LandingPadInst *InvokeInst::getLandingPadInst() const {
return cast<LandingPadInst>(getUnwindDest()->getFirstNonPHI()); return cast<LandingPadInst>(getUnwindDest()->getFirstNonPHI());
} }

View File

@ -245,6 +245,12 @@ define void @f41(i8* align 32, double* align 64) {
ret void ret void
} }
; CHECK: define dereferenceable_or_null(8) i8* @f42(i8* dereferenceable_or_null(8) %foo)
define dereferenceable_or_null(8) i8* @f42(i8* dereferenceable_or_null(8) %foo) {
entry:
ret i8* %foo
}
; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone } ; CHECK: attributes #2 = { readnone }