forked from OSchip/llvm-project
Add a dereferenceable attribute
This attribute indicates that the parameter or return pointer is dereferenceable. Practically speaking, loads from such a pointer within the associated byte range are safe to speculatively execute. Such pointer parameters are common in source languages (C++ references, for example). llvm-svn: 213385
This commit is contained in:
parent
9cf7ac7589
commit
b0407ba071
|
@ -969,6 +969,17 @@ Currently, only the following parameter attributes are defined:
|
||||||
passed in is non-null, or the callee must ensure that the returned pointer
|
passed in is non-null, or the callee must ensure that the returned pointer
|
||||||
is non-null.
|
is non-null.
|
||||||
|
|
||||||
|
``dereferenceable(<n>)``
|
||||||
|
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(<n>)`` does imply ``nonnull`` in
|
||||||
|
``addrspace(0)`` (which is the default address space).
|
||||||
|
|
||||||
.. _gc:
|
.. _gc:
|
||||||
|
|
||||||
Garbage Collector Names
|
Garbage Collector Names
|
||||||
|
|
|
@ -168,6 +168,7 @@ typedef enum {
|
||||||
LLVMInAllocaAttribute = 1ULL << 36,
|
LLVMInAllocaAttribute = 1ULL << 36,
|
||||||
LLVMNonNullAttribute = 1ULL << 37,
|
LLVMNonNullAttribute = 1ULL << 37,
|
||||||
LLVMJumpTableAttribute = 1ULL << 38,
|
LLVMJumpTableAttribute = 1ULL << 38,
|
||||||
|
LLVMDereferenceableAttribute = 1ULL << 39,
|
||||||
*/
|
*/
|
||||||
} LLVMAttribute;
|
} LLVMAttribute;
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,8 @@ namespace bitc {
|
||||||
ATTR_KIND_OPTIMIZE_NONE = 37,
|
ATTR_KIND_OPTIMIZE_NONE = 37,
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ComdatSelectionKindCodes {
|
enum ComdatSelectionKindCodes {
|
||||||
|
|
|
@ -56,9 +56,15 @@ public:
|
||||||
unsigned getArgNo() const;
|
unsigned getArgNo() const;
|
||||||
|
|
||||||
/// \brief Return true if this argument has the nonnull attribute on it in
|
/// \brief Return true if this argument has the nonnull attribute on it in
|
||||||
/// its containing function.
|
/// its containing function. Also returns true if at least one byte is known
|
||||||
|
/// to be dereferenceable and the pointer is in addrspace(0).
|
||||||
bool hasNonNullAttr() const;
|
bool hasNonNullAttr() const;
|
||||||
|
|
||||||
|
/// \brief If this argument has the dereferenceable attribute on it in its
|
||||||
|
/// containing function, return the number of bytes known to be
|
||||||
|
/// dereferenceable. Otherwise, zero is returned.
|
||||||
|
uint64_t getDereferenceableBytes() const;
|
||||||
|
|
||||||
/// \brief Return true if this argument has the byval attribute on it in its
|
/// \brief Return true if this argument has the byval attribute on it in its
|
||||||
/// containing function.
|
/// containing function.
|
||||||
bool hasByValAttr() const;
|
bool hasByValAttr() const;
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
NonLazyBind, ///< Function is called early and/or
|
NonLazyBind, ///< Function is called early and/or
|
||||||
///< 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
|
||||||
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
|
||||||
|
@ -133,6 +134,8 @@ public:
|
||||||
/// alignment set.
|
/// alignment set.
|
||||||
static Attribute getWithAlignment(LLVMContext &Context, uint64_t Align);
|
static Attribute getWithAlignment(LLVMContext &Context, uint64_t Align);
|
||||||
static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align);
|
static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align);
|
||||||
|
static Attribute getWithDereferenceableBytes(LLVMContext &Context,
|
||||||
|
uint64_t Bytes);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Attribute Accessors
|
// Attribute Accessors
|
||||||
|
@ -178,6 +181,10 @@ public:
|
||||||
/// alignment value.
|
/// alignment value.
|
||||||
unsigned getStackAlignment() const;
|
unsigned getStackAlignment() const;
|
||||||
|
|
||||||
|
/// \brief Returns the number of dereferenceable bytes from the
|
||||||
|
/// dereferenceable attribute (or zero if unknown).
|
||||||
|
uint64_t getDereferenceableBytes() 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;
|
||||||
|
@ -316,6 +323,9 @@ public:
|
||||||
/// \brief Get the stack alignment.
|
/// \brief Get the stack alignment.
|
||||||
unsigned getStackAlignment(unsigned Index) const;
|
unsigned getStackAlignment(unsigned Index) const;
|
||||||
|
|
||||||
|
/// \brief Get the number of dereferenceable bytes (or zero if unknown).
|
||||||
|
uint64_t getDereferenceableBytes(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;
|
||||||
|
|
||||||
|
@ -395,13 +405,15 @@ class AttrBuilder {
|
||||||
std::map<std::string, std::string> TargetDepAttrs;
|
std::map<std::string, std::string> TargetDepAttrs;
|
||||||
uint64_t Alignment;
|
uint64_t Alignment;
|
||||||
uint64_t StackAlignment;
|
uint64_t StackAlignment;
|
||||||
|
uint64_t DerefBytes;
|
||||||
public:
|
public:
|
||||||
AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0) {}
|
AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {}
|
||||||
explicit AttrBuilder(uint64_t Val)
|
explicit AttrBuilder(uint64_t Val)
|
||||||
: Attrs(0), Alignment(0), StackAlignment(0) {
|
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {
|
||||||
addRawValue(Val);
|
addRawValue(Val);
|
||||||
}
|
}
|
||||||
AttrBuilder(const Attribute &A) : Attrs(0), Alignment(0), StackAlignment(0) {
|
AttrBuilder(const Attribute &A)
|
||||||
|
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {
|
||||||
addAttribute(A);
|
addAttribute(A);
|
||||||
}
|
}
|
||||||
AttrBuilder(AttributeSet AS, unsigned Idx);
|
AttrBuilder(AttributeSet AS, unsigned Idx);
|
||||||
|
@ -455,6 +467,10 @@ public:
|
||||||
/// \brief Retrieve the stack alignment attribute, if it exists.
|
/// \brief Retrieve the stack alignment attribute, if it exists.
|
||||||
uint64_t getStackAlignment() const { return StackAlignment; }
|
uint64_t getStackAlignment() const { return StackAlignment; }
|
||||||
|
|
||||||
|
/// \brief Retrieve the number of dereferenceable bytes, if the dereferenceable
|
||||||
|
/// attribute exists (zero is returned otherwise).
|
||||||
|
uint64_t getDereferenceableBytes() const { return DerefBytes; }
|
||||||
|
|
||||||
/// \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);
|
||||||
|
@ -463,6 +479,10 @@ public:
|
||||||
/// the form used internally in Attribute.
|
/// the form used internally in Attribute.
|
||||||
AttrBuilder &addStackAlignmentAttr(unsigned Align);
|
AttrBuilder &addStackAlignmentAttr(unsigned Align);
|
||||||
|
|
||||||
|
/// \brief This turns the number of dereferenceable bytes into the form used
|
||||||
|
/// internally in Attribute.
|
||||||
|
AttrBuilder &addDereferenceableAttr(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(); }
|
||||||
|
|
|
@ -217,6 +217,12 @@ public:
|
||||||
CALLSITE_DELEGATE_GETTER(getParamAlignment(i));
|
CALLSITE_DELEGATE_GETTER(getParamAlignment(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Extract the number of dereferenceable bytes for a call or
|
||||||
|
/// parameter (0=unknown).
|
||||||
|
uint64_t getDereferenceableBytes(uint16_t i) const {
|
||||||
|
CALLSITE_DELEGATE_GETTER(getDereferenceableBytes(i));
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Return true if the call should not be treated as a call to a
|
/// \brief Return true if the call should not be treated as a call to a
|
||||||
/// builtin.
|
/// builtin.
|
||||||
bool isNoBuiltin() const {
|
bool isNoBuiltin() const {
|
||||||
|
@ -302,6 +308,19 @@ public:
|
||||||
paramHasAttr(ArgNo + 1, Attribute::ReadNone);
|
paramHasAttr(ArgNo + 1, Attribute::ReadNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief 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).
|
||||||
|
bool isReturnNonNull() const {
|
||||||
|
if (paramHasAttr(0, Attribute::NonNull))
|
||||||
|
return true;
|
||||||
|
else if (getDereferenceableBytes(0) > 0 &&
|
||||||
|
getType()->getPointerAddressSpace() == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// hasArgument - Returns true if this CallSite passes the given Value* as an
|
/// hasArgument - Returns true if this CallSite passes the given Value* as an
|
||||||
/// argument to the called function.
|
/// argument to the called function.
|
||||||
bool hasArgument(const Value *Arg) const {
|
bool hasArgument(const Value *Arg) const {
|
||||||
|
|
|
@ -233,6 +233,12 @@ public:
|
||||||
return AttributeSets.getParamAlignment(i);
|
return AttributeSets.getParamAlignment(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Extract the number of dereferenceable bytes for a call or
|
||||||
|
/// parameter (0=unknown).
|
||||||
|
uint64_t getDereferenceableBytes(unsigned i) const {
|
||||||
|
return AttributeSets.getDereferenceableBytes(i);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Determine if the function does not access memory.
|
/// @brief Determine if the function does not access memory.
|
||||||
bool doesNotAccessMemory() const {
|
bool doesNotAccessMemory() const {
|
||||||
return AttributeSets.hasAttribute(AttributeSet::FunctionIndex,
|
return AttributeSets.hasAttribute(AttributeSet::FunctionIndex,
|
||||||
|
|
|
@ -1376,6 +1376,12 @@ public:
|
||||||
return AttributeList.getParamAlignment(i);
|
return AttributeList.getParamAlignment(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Extract the number of dereferenceable bytes for a call or
|
||||||
|
/// parameter (0=unknown).
|
||||||
|
uint64_t getDereferenceableBytes(unsigned i) const {
|
||||||
|
return AttributeList.getDereferenceableBytes(i);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Return true if the call should not be treated as a call to a
|
/// \brief Return true if the call should not be treated as a call to a
|
||||||
/// builtin.
|
/// builtin.
|
||||||
bool isNoBuiltin() const {
|
bool isNoBuiltin() const {
|
||||||
|
@ -3051,6 +3057,12 @@ public:
|
||||||
return AttributeList.getParamAlignment(i);
|
return AttributeList.getParamAlignment(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Extract the number of dereferenceable bytes for a call or
|
||||||
|
/// parameter (0=unknown).
|
||||||
|
uint64_t getDereferenceableBytes(unsigned i) const {
|
||||||
|
return AttributeList.getDereferenceableBytes(i);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Return true if the call should not be treated as a call to a
|
/// \brief Return true if the call should not be treated as a call to a
|
||||||
/// builtin.
|
/// builtin.
|
||||||
bool isNoBuiltin() const {
|
bool isNoBuiltin() const {
|
||||||
|
|
|
@ -2086,7 +2086,7 @@ bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
|
||||||
return !GV->hasExternalWeakLinkage();
|
return !GV->hasExternalWeakLinkage();
|
||||||
|
|
||||||
if (ImmutableCallSite CS = V)
|
if (ImmutableCallSite CS = V)
|
||||||
if (CS.paramHasAttr(0, Attribute::NonNull))
|
if (CS.isReturnNonNull())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// operator new never returns null.
|
// operator new never returns null.
|
||||||
|
|
|
@ -612,6 +612,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||||
KEYWORD(byval);
|
KEYWORD(byval);
|
||||||
KEYWORD(inalloca);
|
KEYWORD(inalloca);
|
||||||
KEYWORD(cold);
|
KEYWORD(cold);
|
||||||
|
KEYWORD(dereferenceable);
|
||||||
KEYWORD(inlinehint);
|
KEYWORD(inlinehint);
|
||||||
KEYWORD(inreg);
|
KEYWORD(inreg);
|
||||||
KEYWORD(jumptable);
|
KEYWORD(jumptable);
|
||||||
|
|
|
@ -1052,6 +1052,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
|
||||||
"invalid use of attribute on a function");
|
"invalid use of attribute on a function");
|
||||||
break;
|
break;
|
||||||
case lltok::kw_byval:
|
case lltok::kw_byval:
|
||||||
|
case lltok::kw_dereferenceable:
|
||||||
case lltok::kw_inalloca:
|
case lltok::kw_inalloca:
|
||||||
case lltok::kw_nest:
|
case lltok::kw_nest:
|
||||||
case lltok::kw_noalias:
|
case lltok::kw_noalias:
|
||||||
|
@ -1212,6 +1213,16 @@ bool LLParser::ParseUInt32(unsigned &Val) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ParseUInt64
|
||||||
|
/// ::= uint64
|
||||||
|
bool LLParser::ParseUInt64(uint64_t &Val) {
|
||||||
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
||||||
|
return TokError("expected integer");
|
||||||
|
Val = Lex.getAPSIntVal().getLimitedValue();
|
||||||
|
Lex.Lex();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// ParseTLSModel
|
/// ParseTLSModel
|
||||||
/// := 'localdynamic'
|
/// := 'localdynamic'
|
||||||
/// := 'initialexec'
|
/// := 'initialexec'
|
||||||
|
@ -1284,6 +1295,13 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
|
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
|
||||||
|
case lltok::kw_dereferenceable: {
|
||||||
|
uint64_t Bytes;
|
||||||
|
if (ParseOptionalDereferenceableBytes(Bytes))
|
||||||
|
return true;
|
||||||
|
B.addDereferenceableAttr(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;
|
||||||
|
@ -1341,6 +1359,13 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
|
||||||
switch (Token) {
|
switch (Token) {
|
||||||
default: // End of attributes.
|
default: // End of attributes.
|
||||||
return HaveError;
|
return HaveError;
|
||||||
|
case lltok::kw_dereferenceable: {
|
||||||
|
uint64_t Bytes;
|
||||||
|
if (ParseOptionalDereferenceableBytes(Bytes))
|
||||||
|
return true;
|
||||||
|
B.addDereferenceableAttr(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;
|
||||||
|
@ -1606,6 +1631,26 @@ bool LLParser::ParseOptionalAlignment(unsigned &Alignment) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ParseOptionalDereferenceableBytes
|
||||||
|
/// ::= /* empty */
|
||||||
|
/// ::= 'dereferenceable' '(' 4 ')'
|
||||||
|
bool LLParser::ParseOptionalDereferenceableBytes(uint64_t &Bytes) {
|
||||||
|
Bytes = 0;
|
||||||
|
if (!EatIfPresent(lltok::kw_dereferenceable))
|
||||||
|
return false;
|
||||||
|
LocTy ParenLoc = Lex.getLoc();
|
||||||
|
if (!EatIfPresent(lltok::lparen))
|
||||||
|
return Error(ParenLoc, "expected '('");
|
||||||
|
LocTy DerefLoc = Lex.getLoc();
|
||||||
|
if (ParseUInt64(Bytes)) return true;
|
||||||
|
ParenLoc = Lex.getLoc();
|
||||||
|
if (!EatIfPresent(lltok::rparen))
|
||||||
|
return Error(ParenLoc, "expected ')'");
|
||||||
|
if (!Bytes)
|
||||||
|
return Error(DerefLoc, "dereferenceable bytes must be non-zero");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// ParseOptionalCommaAlign
|
/// ParseOptionalCommaAlign
|
||||||
/// ::=
|
/// ::=
|
||||||
/// ::= ',' align 4
|
/// ::= ',' align 4
|
||||||
|
|
|
@ -202,6 +202,11 @@ namespace llvm {
|
||||||
Loc = Lex.getLoc();
|
Loc = Lex.getLoc();
|
||||||
return ParseUInt32(Val);
|
return ParseUInt32(Val);
|
||||||
}
|
}
|
||||||
|
bool ParseUInt64(uint64_t &Val);
|
||||||
|
bool ParseUInt64(uint64_t &Val, LocTy &Loc) {
|
||||||
|
Loc = Lex.getLoc();
|
||||||
|
return ParseUInt64(Val);
|
||||||
|
}
|
||||||
|
|
||||||
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
|
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
|
||||||
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
|
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
|
||||||
|
@ -219,6 +224,7 @@ namespace llvm {
|
||||||
bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass);
|
bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass);
|
||||||
bool ParseOptionalCallingConv(CallingConv::ID &CC);
|
bool ParseOptionalCallingConv(CallingConv::ID &CC);
|
||||||
bool ParseOptionalAlignment(unsigned &Alignment);
|
bool ParseOptionalAlignment(unsigned &Alignment);
|
||||||
|
bool ParseOptionalDereferenceableBytes(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_byval,
|
kw_byval,
|
||||||
kw_inalloca,
|
kw_inalloca,
|
||||||
kw_cold,
|
kw_cold,
|
||||||
|
kw_dereferenceable,
|
||||||
kw_inlinehint,
|
kw_inlinehint,
|
||||||
kw_inreg,
|
kw_inreg,
|
||||||
kw_jumptable,
|
kw_jumptable,
|
||||||
|
|
|
@ -588,6 +588,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
|
||||||
return Attribute::NonLazyBind;
|
return Attribute::NonLazyBind;
|
||||||
case bitc::ATTR_KIND_NON_NULL:
|
case bitc::ATTR_KIND_NON_NULL:
|
||||||
return Attribute::NonNull;
|
return Attribute::NonNull;
|
||||||
|
case bitc::ATTR_KIND_DEREFERENCEABLE:
|
||||||
|
return Attribute::Dereferenceable;
|
||||||
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:
|
||||||
|
@ -689,8 +691,10 @@ std::error_code BitcodeReader::ParseAttributeGroupBlock() {
|
||||||
return EC;
|
return EC;
|
||||||
if (Kind == Attribute::Alignment)
|
if (Kind == Attribute::Alignment)
|
||||||
B.addAlignmentAttr(Record[++i]);
|
B.addAlignmentAttr(Record[++i]);
|
||||||
else
|
else if (Kind == Attribute::StackAlignment)
|
||||||
B.addStackAlignmentAttr(Record[++i]);
|
B.addStackAlignmentAttr(Record[++i]);
|
||||||
|
else if (Kind == Attribute::Dereferenceable)
|
||||||
|
B.addDereferenceableAttr(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");
|
||||||
|
|
|
@ -201,6 +201,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
||||||
return bitc::ATTR_KIND_NON_LAZY_BIND;
|
return bitc::ATTR_KIND_NON_LAZY_BIND;
|
||||||
case Attribute::NonNull:
|
case Attribute::NonNull:
|
||||||
return bitc::ATTR_KIND_NON_NULL;
|
return bitc::ATTR_KIND_NON_NULL;
|
||||||
|
case Attribute::Dereferenceable:
|
||||||
|
return bitc::ATTR_KIND_DEREFERENCEABLE;
|
||||||
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:
|
||||||
|
|
|
@ -116,7 +116,8 @@ 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) &&
|
||||||
"Wrong kind for int attribute!");
|
"Wrong kind for int attribute!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +165,7 @@ public:
|
||||||
|
|
||||||
unsigned getAlignment() const;
|
unsigned getAlignment() const;
|
||||||
unsigned getStackAlignment() const;
|
unsigned getStackAlignment() const;
|
||||||
|
uint64_t getDereferenceableBytes() const;
|
||||||
std::string getAsString(bool InAttrGrp) const;
|
std::string getAsString(bool InAttrGrp) const;
|
||||||
|
|
||||||
typedef const Attribute *iterator;
|
typedef const Attribute *iterator;
|
||||||
|
|
|
@ -88,6 +88,12 @@ Attribute Attribute::getWithStackAlignment(LLVMContext &Context,
|
||||||
return get(Context, StackAlignment, Align);
|
return get(Context, StackAlignment, Align);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
|
||||||
|
uint64_t Bytes) {
|
||||||
|
assert(Bytes && "Bytes must be non-zero.");
|
||||||
|
return get(Context, Dereferenceable, Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Attribute Accessor Methods
|
// Attribute Accessor Methods
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -156,6 +162,14 @@ unsigned Attribute::getStackAlignment() const {
|
||||||
return pImpl->getValueAsInt();
|
return pImpl->getValueAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This returns the number of dereferenceable bytes.
|
||||||
|
uint64_t Attribute::getDereferenceableBytes() const {
|
||||||
|
assert(hasAttribute(Attribute::Dereferenceable) &&
|
||||||
|
"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,6 +277,20 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasAttribute(Attribute::Dereferenceable)) {
|
||||||
|
std::string Result;
|
||||||
|
Result += "dereferenceable";
|
||||||
|
if (InAttrGrp) {
|
||||||
|
Result += "=";
|
||||||
|
Result += utostr(getValueAsInt());
|
||||||
|
} else {
|
||||||
|
Result += "(";
|
||||||
|
Result += utostr(getValueAsInt());
|
||||||
|
Result += ")";
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert target-dependent attributes to strings of the form:
|
// Convert target-dependent attributes to strings of the form:
|
||||||
//
|
//
|
||||||
// "kind"
|
// "kind"
|
||||||
|
@ -398,6 +426,8 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
|
||||||
case Attribute::InAlloca: return 1ULL << 43;
|
case Attribute::InAlloca: return 1ULL << 43;
|
||||||
case Attribute::NonNull: return 1ULL << 44;
|
case Attribute::NonNull: return 1ULL << 44;
|
||||||
case Attribute::JumpTable: return 1ULL << 45;
|
case Attribute::JumpTable: return 1ULL << 45;
|
||||||
|
case Attribute::Dereferenceable:
|
||||||
|
llvm_unreachable("dereferenceable attribute not supported in raw format");
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unsupported attribute type");
|
llvm_unreachable("Unsupported attribute type");
|
||||||
}
|
}
|
||||||
|
@ -482,6 +512,13 @@ unsigned AttributeSetNode::getStackAlignment() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t AttributeSetNode::getDereferenceableBytes() const {
|
||||||
|
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||||
|
if (I->hasAttribute(Attribute::Dereferenceable))
|
||||||
|
return I->getDereferenceableBytes();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
|
std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
|
||||||
std::string Str;
|
std::string Str;
|
||||||
for (iterator I = begin(), E = end(); I != E; ++I) {
|
for (iterator I = begin(), E = end(); I != E; ++I) {
|
||||||
|
@ -515,6 +552,8 @@ uint64_t AttributeSetImpl::Raw(unsigned Index) const {
|
||||||
Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16;
|
Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16;
|
||||||
else if (Kind == Attribute::StackAlignment)
|
else if (Kind == Attribute::StackAlignment)
|
||||||
Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26;
|
Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26;
|
||||||
|
else if (Kind == Attribute::Dereferenceable)
|
||||||
|
llvm_unreachable("dereferenceable not supported in bit mask");
|
||||||
else
|
else
|
||||||
Mask |= AttributeImpl::getAttrMask(Kind);
|
Mask |= AttributeImpl::getAttrMask(Kind);
|
||||||
}
|
}
|
||||||
|
@ -620,6 +659,10 @@ AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index,
|
||||||
else if (Kind == Attribute::StackAlignment)
|
else if (Kind == Attribute::StackAlignment)
|
||||||
Attrs.push_back(std::make_pair(Index, Attribute::
|
Attrs.push_back(std::make_pair(Index, Attribute::
|
||||||
getWithStackAlignment(C, B.getStackAlignment())));
|
getWithStackAlignment(C, B.getStackAlignment())));
|
||||||
|
else if (Kind == Attribute::Dereferenceable)
|
||||||
|
Attrs.push_back(std::make_pair(Index,
|
||||||
|
Attribute::getWithDereferenceableBytes(C,
|
||||||
|
B.getDereferenceableBytes())));
|
||||||
else
|
else
|
||||||
Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind)));
|
Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind)));
|
||||||
}
|
}
|
||||||
|
@ -877,6 +920,11 @@ unsigned AttributeSet::getStackAlignment(unsigned Index) const {
|
||||||
return ASN ? ASN->getStackAlignment() : 0;
|
return ASN ? ASN->getStackAlignment() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t AttributeSet::getDereferenceableBytes(unsigned Index) const {
|
||||||
|
AttributeSetNode *ASN = getAttributes(Index);
|
||||||
|
return ASN ? ASN->getDereferenceableBytes() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AttributeSet::getAsString(unsigned Index,
|
std::string AttributeSet::getAsString(unsigned Index,
|
||||||
bool InAttrGrp) const {
|
bool InAttrGrp) const {
|
||||||
AttributeSetNode *ASN = getAttributes(Index);
|
AttributeSetNode *ASN = getAttributes(Index);
|
||||||
|
@ -956,7 +1004,7 @@ void AttributeSet::dump() const {
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
|
AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
|
||||||
: Attrs(0), Alignment(0), StackAlignment(0) {
|
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {
|
||||||
AttributeSetImpl *pImpl = AS.pImpl;
|
AttributeSetImpl *pImpl = AS.pImpl;
|
||||||
if (!pImpl) return;
|
if (!pImpl) return;
|
||||||
|
|
||||||
|
@ -973,13 +1021,14 @@ AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
|
||||||
|
|
||||||
void AttrBuilder::clear() {
|
void AttrBuilder::clear() {
|
||||||
Attrs.reset();
|
Attrs.reset();
|
||||||
Alignment = StackAlignment = 0;
|
Alignment = StackAlignment = DerefBytes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
|
AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
|
||||||
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
|
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
|
||||||
assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment &&
|
assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment &&
|
||||||
"Adding alignment attribute without adding alignment value!");
|
Val != Attribute::Dereferenceable &&
|
||||||
|
"Adding integer attribute without adding a value!");
|
||||||
Attrs[Val] = true;
|
Attrs[Val] = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -997,6 +1046,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
|
||||||
Alignment = Attr.getAlignment();
|
Alignment = Attr.getAlignment();
|
||||||
else if (Kind == Attribute::StackAlignment)
|
else if (Kind == Attribute::StackAlignment)
|
||||||
StackAlignment = Attr.getStackAlignment();
|
StackAlignment = Attr.getStackAlignment();
|
||||||
|
else if (Kind == Attribute::Dereferenceable)
|
||||||
|
DerefBytes = Attr.getDereferenceableBytes();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,6 +1064,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
|
||||||
Alignment = 0;
|
Alignment = 0;
|
||||||
else if (Val == Attribute::StackAlignment)
|
else if (Val == Attribute::StackAlignment)
|
||||||
StackAlignment = 0;
|
StackAlignment = 0;
|
||||||
|
else if (Val == Attribute::Dereferenceable)
|
||||||
|
DerefBytes = 0;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1037,6 +1090,8 @@ AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) {
|
||||||
Alignment = 0;
|
Alignment = 0;
|
||||||
else if (Kind == Attribute::StackAlignment)
|
else if (Kind == Attribute::StackAlignment)
|
||||||
StackAlignment = 0;
|
StackAlignment = 0;
|
||||||
|
else if (Kind == Attribute::Dereferenceable)
|
||||||
|
DerefBytes = 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
|
||||||
|
@ -1079,6 +1134,14 @@ AttrBuilder &AttrBuilder::addStackAlignmentAttr(unsigned Align) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
|
||||||
|
if (Bytes == 0) return *this;
|
||||||
|
|
||||||
|
Attrs[Attribute::Dereferenceable] = true;
|
||||||
|
DerefBytes = 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)
|
||||||
|
@ -1087,6 +1150,9 @@ AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
|
||||||
if (!StackAlignment)
|
if (!StackAlignment)
|
||||||
StackAlignment = B.StackAlignment;
|
StackAlignment = B.StackAlignment;
|
||||||
|
|
||||||
|
if (!DerefBytes)
|
||||||
|
DerefBytes = B.DerefBytes;
|
||||||
|
|
||||||
Attrs |= B.Attrs;
|
Attrs |= B.Attrs;
|
||||||
|
|
||||||
for (td_const_iterator I = B.TargetDepAttrs.begin(),
|
for (td_const_iterator I = B.TargetDepAttrs.begin(),
|
||||||
|
@ -1142,7 +1208,8 @@ bool AttrBuilder::operator==(const AttrBuilder &B) {
|
||||||
if (B.TargetDepAttrs.find(I->first) == B.TargetDepAttrs.end())
|
if (B.TargetDepAttrs.find(I->first) == B.TargetDepAttrs.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return Alignment == B.Alignment && StackAlignment == B.StackAlignment;
|
return Alignment == B.Alignment && StackAlignment == B.StackAlignment &&
|
||||||
|
DerefBytes == B.DerefBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {
|
AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {
|
||||||
|
@ -1151,6 +1218,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)
|
||||||
|
continue;
|
||||||
if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
|
if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
|
||||||
Attrs[I] = true;
|
Attrs[I] = true;
|
||||||
|
|
||||||
|
@ -1184,6 +1253,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
|
||||||
.addAttribute(Attribute::NoAlias)
|
.addAttribute(Attribute::NoAlias)
|
||||||
.addAttribute(Attribute::NoCapture)
|
.addAttribute(Attribute::NoCapture)
|
||||||
.addAttribute(Attribute::NonNull)
|
.addAttribute(Attribute::NonNull)
|
||||||
|
.addDereferenceableAttr(1) // the int here is ignored
|
||||||
.addAttribute(Attribute::ReadNone)
|
.addAttribute(Attribute::ReadNone)
|
||||||
.addAttribute(Attribute::ReadOnly)
|
.addAttribute(Attribute::ReadOnly)
|
||||||
.addAttribute(Attribute::StructRet)
|
.addAttribute(Attribute::StructRet)
|
||||||
|
|
|
@ -77,11 +77,17 @@ unsigned Argument::getArgNo() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasNonNullAttr - Return true if this argument has the nonnull attribute on
|
/// hasNonNullAttr - Return true if this argument has the nonnull attribute on
|
||||||
/// it in its containing function.
|
/// it in its containing function. Also returns true if at least one byte is
|
||||||
|
/// known to be dereferenceable and the pointer is in addrspace(0).
|
||||||
bool Argument::hasNonNullAttr() const {
|
bool Argument::hasNonNullAttr() const {
|
||||||
if (!getType()->isPointerTy()) return false;
|
if (!getType()->isPointerTy()) return false;
|
||||||
return getParent()->getAttributes().
|
if (getParent()->getAttributes().
|
||||||
hasAttribute(getArgNo()+1, Attribute::NonNull);
|
hasAttribute(getArgNo()+1, Attribute::NonNull))
|
||||||
|
return true;
|
||||||
|
else if (getDereferenceableBytes() > 0 &&
|
||||||
|
getType()->getPointerAddressSpace() == 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasByValAttr - Return true if this argument has the byval attribute on it
|
/// hasByValAttr - Return true if this argument has the byval attribute on it
|
||||||
|
@ -113,6 +119,12 @@ unsigned Argument::getParamAlignment() const {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Argument::getDereferenceableBytes() const {
|
||||||
|
assert(getType()->isPointerTy() &&
|
||||||
|
"Only pointers have dereferenceable bytes");
|
||||||
|
return getParent()->getDereferenceableBytes(getArgNo()+1);
|
||||||
|
}
|
||||||
|
|
||||||
/// hasNestAttr - Return true if this argument has the nest attribute on
|
/// hasNestAttr - Return true if this argument has the nest attribute on
|
||||||
/// it in its containing function.
|
/// it in its containing function.
|
||||||
bool Argument::hasNestAttr() const {
|
bool Argument::hasNestAttr() const {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "LLVMContextImpl.h"
|
#include "LLVMContextImpl.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/IR/CallSite.h"
|
||||||
#include "llvm/IR/Constant.h"
|
#include "llvm/IR/Constant.h"
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
|
@ -504,9 +505,29 @@ static bool isDereferenceablePointer(const Value *V, const DataLayout *DL,
|
||||||
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
|
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
|
||||||
return !GV->hasExternalWeakLinkage();
|
return !GV->hasExternalWeakLinkage();
|
||||||
|
|
||||||
// byval arguments are ok.
|
// byval arguments are okay. Arguments specifically marked as
|
||||||
if (const Argument *A = dyn_cast<Argument>(V))
|
// dereferenceable are okay too.
|
||||||
return A->hasByValAttr();
|
if (const Argument *A = dyn_cast<Argument>(V)) {
|
||||||
|
if (A->hasByValAttr())
|
||||||
|
return true;
|
||||||
|
else if (uint64_t Bytes = A->getDereferenceableBytes()) {
|
||||||
|
Type *Ty = V->getType()->getPointerElementType();
|
||||||
|
if (Ty->isSized() && DL && DL->getTypeStoreSize(Ty) <= Bytes)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return values from call sites specifically marked as dereferenceable are
|
||||||
|
// also okay.
|
||||||
|
if (ImmutableCallSite CS = V) {
|
||||||
|
if (uint64_t Bytes = CS.getDereferenceableBytes(0)) {
|
||||||
|
Type *Ty = V->getType()->getPointerElementType();
|
||||||
|
if (Ty->isSized() && DL && DL->getTypeStoreSize(Ty) <= Bytes)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For GEPs, determine if the indexing lands within the allocated object.
|
// For GEPs, determine if the indexing lands within the allocated object.
|
||||||
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
|
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
|
||||||
|
|
|
@ -229,6 +229,16 @@ define void @f38() unnamed_addr jumptable {
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define dereferenceable(2) i8* @f39(i8* dereferenceable(1) %a) {
|
||||||
|
; CHECK: define dereferenceable(2) i8* @f39(i8* dereferenceable(1) %a) {
|
||||||
|
ret i8* %a
|
||||||
|
}
|
||||||
|
|
||||||
|
define dereferenceable(18446744073709551606) i8* @f40(i8* dereferenceable(18446744073709551615) %a) {
|
||||||
|
; CHECK: define dereferenceable(18446744073709551606) i8* @f40(i8* dereferenceable(18446744073709551615) %a) {
|
||||||
|
ret i8* %a
|
||||||
|
}
|
||||||
|
|
||||||
; CHECK: attributes #0 = { noreturn }
|
; CHECK: attributes #0 = { noreturn }
|
||||||
; CHECK: attributes #1 = { nounwind }
|
; CHECK: attributes #1 = { nounwind }
|
||||||
; CHECK: attributes #2 = { readnone }
|
; CHECK: attributes #2 = { readnone }
|
||||||
|
|
|
@ -874,6 +874,21 @@ define i1 @nonnull_arg(i32* nonnull %i) {
|
||||||
; CHECK: ret i1 false
|
; CHECK: ret i1 false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i1 @nonnull_deref_arg(i32* dereferenceable(4) %i) {
|
||||||
|
%cmp = icmp eq i32* %i, null
|
||||||
|
ret i1 %cmp
|
||||||
|
; CHECK-LABEL: @nonnull_deref_arg
|
||||||
|
; CHECK: ret i1 false
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @nonnull_deref_as_arg(i32 addrspace(1)* dereferenceable(4) %i) {
|
||||||
|
%cmp = icmp eq i32 addrspace(1)* %i, null
|
||||||
|
ret i1 %cmp
|
||||||
|
; CHECK-LABEL: @nonnull_deref_as_arg
|
||||||
|
; CHECK: icmp
|
||||||
|
; CHECK ret
|
||||||
|
}
|
||||||
|
|
||||||
declare nonnull i32* @returns_nonnull_helper()
|
declare nonnull i32* @returns_nonnull_helper()
|
||||||
define i1 @returns_nonnull() {
|
define i1 @returns_nonnull() {
|
||||||
%call = call nonnull i32* @returns_nonnull_helper()
|
%call = call nonnull i32* @returns_nonnull_helper()
|
||||||
|
@ -883,6 +898,25 @@ define i1 @returns_nonnull() {
|
||||||
; CHECK: ret i1 false
|
; CHECK: ret i1 false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare dereferenceable(4) i32* @returns_nonnull_deref_helper()
|
||||||
|
define i1 @returns_nonnull_deref() {
|
||||||
|
%call = call dereferenceable(4) i32* @returns_nonnull_deref_helper()
|
||||||
|
%cmp = icmp eq i32* %call, null
|
||||||
|
ret i1 %cmp
|
||||||
|
; CHECK-LABEL: @returns_nonnull_deref
|
||||||
|
; CHECK: ret i1 false
|
||||||
|
}
|
||||||
|
|
||||||
|
declare dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
|
||||||
|
define i1 @returns_nonnull_as_deref() {
|
||||||
|
%call = call dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
|
||||||
|
%cmp = icmp eq i32 addrspace(1)* %call, null
|
||||||
|
ret i1 %cmp
|
||||||
|
; CHECK-LABEL: @returns_nonnull_as_deref
|
||||||
|
; CHECK: icmp
|
||||||
|
; CHECK: ret
|
||||||
|
}
|
||||||
|
|
||||||
; If a bit is known to be zero for A and known to be one for B,
|
; If a bit is known to be zero for A and known to be one for B,
|
||||||
; then A and B cannot be equal.
|
; then A and B cannot be equal.
|
||||||
define i1 @icmp_eq_const(i32 %a) nounwind {
|
define i1 @icmp_eq_const(i32 %a) nounwind {
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
; RUN: opt -S -basicaa -licm < %s | FileCheck %s
|
||||||
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
; This test represents the following function:
|
||||||
|
; void test1(int * __restrict__ a, int * __restrict__ b, int &c, int n) {
|
||||||
|
; for (int i = 0; i < n; ++i)
|
||||||
|
; if (a[i] > 0)
|
||||||
|
; a[i] = c*b[i];
|
||||||
|
; }
|
||||||
|
; and we want to hoist the load of %c out of the loop. This can be done only
|
||||||
|
; because the dereferenceable attribute is on %c.
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test1
|
||||||
|
; CHECK: load i32* %c, align 4
|
||||||
|
; CHECK: for.body:
|
||||||
|
|
||||||
|
define void @test1(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull dereferenceable(4) %c, i32 %n) #0 {
|
||||||
|
entry:
|
||||||
|
%cmp11 = icmp sgt i32 %n, 0
|
||||||
|
br i1 %cmp11, label %for.body, label %for.end
|
||||||
|
|
||||||
|
for.body: ; preds = %entry, %for.inc
|
||||||
|
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
|
||||||
|
%arrayidx = getelementptr inbounds i32* %a, i64 %indvars.iv
|
||||||
|
%0 = load i32* %arrayidx, align 4
|
||||||
|
%cmp1 = icmp sgt i32 %0, 0
|
||||||
|
br i1 %cmp1, label %if.then, label %for.inc
|
||||||
|
|
||||||
|
if.then: ; preds = %for.body
|
||||||
|
%1 = load i32* %c, align 4
|
||||||
|
%arrayidx3 = getelementptr inbounds i32* %b, i64 %indvars.iv
|
||||||
|
%2 = load i32* %arrayidx3, align 4
|
||||||
|
%mul = mul nsw i32 %2, %1
|
||||||
|
store i32 %mul, i32* %arrayidx, align 4
|
||||||
|
br label %for.inc
|
||||||
|
|
||||||
|
for.inc: ; preds = %for.body, %if.then
|
||||||
|
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||||
|
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
|
||||||
|
%exitcond = icmp eq i32 %lftr.wideiv, %n
|
||||||
|
br i1 %exitcond, label %for.end, label %for.body
|
||||||
|
|
||||||
|
for.end: ; preds = %for.inc, %entry
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; This is the same as @test1, but without the dereferenceable attribute on %c.
|
||||||
|
; Without this attribute, we should not hoist the load of %c.
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test2
|
||||||
|
; CHECK: if.then:
|
||||||
|
; CHECK: load i32* %c, align 4
|
||||||
|
|
||||||
|
define void @test2(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull %c, i32 %n) #0 {
|
||||||
|
entry:
|
||||||
|
%cmp11 = icmp sgt i32 %n, 0
|
||||||
|
br i1 %cmp11, label %for.body, label %for.end
|
||||||
|
|
||||||
|
for.body: ; preds = %entry, %for.inc
|
||||||
|
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
|
||||||
|
%arrayidx = getelementptr inbounds i32* %a, i64 %indvars.iv
|
||||||
|
%0 = load i32* %arrayidx, align 4
|
||||||
|
%cmp1 = icmp sgt i32 %0, 0
|
||||||
|
br i1 %cmp1, label %if.then, label %for.inc
|
||||||
|
|
||||||
|
if.then: ; preds = %for.body
|
||||||
|
%1 = load i32* %c, align 4
|
||||||
|
%arrayidx3 = getelementptr inbounds i32* %b, i64 %indvars.iv
|
||||||
|
%2 = load i32* %arrayidx3, align 4
|
||||||
|
%mul = mul nsw i32 %2, %1
|
||||||
|
store i32 %mul, i32* %arrayidx, align 4
|
||||||
|
br label %for.inc
|
||||||
|
|
||||||
|
for.inc: ; preds = %for.body, %if.then
|
||||||
|
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||||
|
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
|
||||||
|
%exitcond = icmp eq i32 %lftr.wideiv, %n
|
||||||
|
br i1 %exitcond, label %for.end, label %for.body
|
||||||
|
|
||||||
|
for.end: ; preds = %for.inc, %entry
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { nounwind uwtable }
|
||||||
|
|
Loading…
Reference in New Issue