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:
parent
a233dc55a3
commit
2d08e46e8b
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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(); }
|
||||||
|
@ -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);
|
||||||
|
@ -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 &&
|
||||||
|
@ -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);
|
||||||
|
@ -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))
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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");
|
||||||
|
@ -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:
|
||||||
|
@ -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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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 }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user