Add 'nonnull', a new parameter and return attribute which indicates that the pointer is not null. Instcombine will elide comparisons between these and null. Patch by Luqman Aden!

llvm-svn: 209185
This commit is contained in:
Nick Lewycky 2014-05-20 01:23:40 +00:00
parent 57cccec446
commit d52b1528c0
14 changed files with 44 additions and 4 deletions

View File

@ -847,6 +847,13 @@ Currently, only the following parameter attributes are defined:
operands for the :ref:`bitcast instruction <i_bitcast>`. This is not a operands for the :ref:`bitcast instruction <i_bitcast>`. This is not a
valid attribute for return values and can only be applied to one parameter. valid attribute for return values and can only be applied to one parameter.
``nonnull``
This indicates that the parameter or return pointer is not null. This
attribute may only be applied to pointer typed parameters. This is not
checked or enforced by LLVM, the caller must ensure that the pointer
passed in is non-null, or the callee must ensure that the returned pointer
is non-null.
.. _gc: .. _gc:
Garbage Collector Names Garbage Collector Names

View File

@ -165,7 +165,8 @@ typedef enum {
LLVMStackProtectStrongAttribute = 1ULL<<33, LLVMStackProtectStrongAttribute = 1ULL<<33,
LLVMCold = 1ULL << 34, LLVMCold = 1ULL << 34,
LLVMOptimizeNone = 1ULL << 35, LLVMOptimizeNone = 1ULL << 35,
LLVMInAllocaAttribute = 1ULL << 36 LLVMInAllocaAttribute = 1ULL << 36,
LLVMNonNullAttribute = 1ULL << 37
*/ */
} LLVMAttribute; } LLVMAttribute;

View File

@ -371,7 +371,8 @@ namespace bitc {
ATTR_KIND_BUILTIN = 35, ATTR_KIND_BUILTIN = 35,
ATTR_KIND_COLD = 36, ATTR_KIND_COLD = 36,
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
}; };
} // End bitc namespace } // End bitc namespace

View File

@ -55,6 +55,10 @@ public:
/// For example in "void foo(int a, float b)" a is 0 and b is 1. /// For example in "void foo(int a, float b)" a is 0 and b is 1.
unsigned getArgNo() const; unsigned getArgNo() const;
/// \brief Return true if this argument has the nonnull attribute on it in
/// its containing function.
bool hasNonNullAttr() 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;

View File

@ -86,6 +86,7 @@ public:
NoInline, ///< inline=never NoInline, ///< inline=never
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
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

View File

@ -2065,9 +2065,9 @@ bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
// Alloca never returns null, malloc might. // Alloca never returns null, malloc might.
if (isa<AllocaInst>(V)) return true; if (isa<AllocaInst>(V)) return true;
// A byval or inalloca argument is never null. // A byval, inalloca, or nonnull argument is never null.
if (const Argument *A = dyn_cast<Argument>(V)) if (const Argument *A = dyn_cast<Argument>(V))
return A->hasByValOrInAllocaAttr(); return A->hasByValOrInAllocaAttr() || A->hasNonNullAttr();
// Global values are not null unless extern weak. // Global values are not null unless extern weak.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))

View File

@ -593,6 +593,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(noimplicitfloat); KEYWORD(noimplicitfloat);
KEYWORD(noinline); KEYWORD(noinline);
KEYWORD(nonlazybind); KEYWORD(nonlazybind);
KEYWORD(nonnull);
KEYWORD(noredzone); KEYWORD(noredzone);
KEYWORD(noreturn); KEYWORD(noreturn);
KEYWORD(nounwind); KEYWORD(nounwind);

View File

@ -1003,6 +1003,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_nest: case lltok::kw_nest:
case lltok::kw_noalias: case lltok::kw_noalias:
case lltok::kw_nocapture: case lltok::kw_nocapture:
case lltok::kw_nonnull:
case lltok::kw_returned: case lltok::kw_returned:
case lltok::kw_sret: case lltok::kw_sret:
HaveError |= HaveError |=
@ -1217,6 +1218,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break; case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break;
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break; case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break; case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break; case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
@ -1269,6 +1271,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
return HaveError; return HaveError;
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_signext: B.addAttribute(Attribute::SExt); break; case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;

View File

@ -117,6 +117,7 @@ namespace lltok {
kw_noimplicitfloat, kw_noimplicitfloat,
kw_noinline, kw_noinline,
kw_nonlazybind, kw_nonlazybind,
kw_nonnull,
kw_noredzone, kw_noredzone,
kw_noreturn, kw_noreturn,
kw_nounwind, kw_nounwind,

View File

@ -569,6 +569,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
return Attribute::NoInline; return Attribute::NoInline;
case bitc::ATTR_KIND_NON_LAZY_BIND: case bitc::ATTR_KIND_NON_LAZY_BIND:
return Attribute::NonLazyBind; return Attribute::NonLazyBind;
case bitc::ATTR_KIND_NON_NULL:
return Attribute::NonNull;
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:

View File

@ -197,6 +197,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NO_INLINE; return bitc::ATTR_KIND_NO_INLINE;
case Attribute::NonLazyBind: case Attribute::NonLazyBind:
return bitc::ATTR_KIND_NON_LAZY_BIND; return bitc::ATTR_KIND_NON_LAZY_BIND;
case Attribute::NonNull:
return bitc::ATTR_KIND_NON_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

@ -193,6 +193,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "noinline"; return "noinline";
if (hasAttribute(Attribute::NonLazyBind)) if (hasAttribute(Attribute::NonLazyBind))
return "nonlazybind"; return "nonlazybind";
if (hasAttribute(Attribute::NonNull))
return "nonnull";
if (hasAttribute(Attribute::NoRedZone)) if (hasAttribute(Attribute::NoRedZone))
return "noredzone"; return "noredzone";
if (hasAttribute(Attribute::NoReturn)) if (hasAttribute(Attribute::NoReturn))
@ -392,6 +394,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::Builtin: return 1ULL << 41; case Attribute::Builtin: return 1ULL << 41;
case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::OptimizeNone: return 1ULL << 42;
case Attribute::InAlloca: return 1ULL << 43; case Attribute::InAlloca: return 1ULL << 43;
case Attribute::NonNull: return 1ULL << 44;
} }
llvm_unreachable("Unsupported attribute type"); llvm_unreachable("Unsupported attribute type");
} }
@ -1177,6 +1180,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
.addAttribute(Attribute::Nest) .addAttribute(Attribute::Nest)
.addAttribute(Attribute::NoAlias) .addAttribute(Attribute::NoAlias)
.addAttribute(Attribute::NoCapture) .addAttribute(Attribute::NoCapture)
.addAttribute(Attribute::NonNull)
.addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::StructRet) .addAttribute(Attribute::StructRet)

View File

@ -76,6 +76,14 @@ unsigned Argument::getArgNo() const {
return ArgIdx; return ArgIdx;
} }
/// hasNonNullAttr - Return true if this argument has the nonnull attribute on
/// it in its containing function.
bool Argument::hasNonNullAttr() const {
if (!getType()->isPointerTy()) return false;
return getParent()->getAttributes().
hasAttribute(getArgNo()+1, Attribute::NonNull);
}
/// hasByValAttr - Return true if this argument has the byval attribute on it /// hasByValAttr - Return true if this argument has the byval attribute on it
/// in its containing function. /// in its containing function.
bool Argument::hasByValAttr() const { bool Argument::hasByValAttr() const {

View File

@ -218,6 +218,11 @@ define void @f36(i8* inalloca) {
ret void ret void
} }
define nonnull i8* @f37(i8* nonnull %a) {
; CHECK: define nonnull i8* @f37(i8* nonnull %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 }