summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Lewycky <nicholas@mxc.ca>2014-05-20 01:23:40 +0000
committerNick Lewycky <nicholas@mxc.ca>2014-05-20 01:23:40 +0000
commitfe47ebfad39184dfca0733c5ef943a074bfcc187 (patch)
tree2f60176fb1f04022ea8a167ff280bc824f18f11a
parent30e58303015fe880180e3caffdd8a3264cde236a (diff)
downloadllvm-fe47ebfad39184dfca0733c5ef943a074bfcc187.tar.gz
llvm-fe47ebfad39184dfca0733c5ef943a074bfcc187.tar.bz2
llvm-fe47ebfad39184dfca0733c5ef943a074bfcc187.tar.xz
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!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209185 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/LangRef.rst7
-rw-r--r--include/llvm-c/Core.h3
-rw-r--r--include/llvm/Bitcode/LLVMBitCodes.h3
-rw-r--r--include/llvm/IR/Argument.h4
-rw-r--r--include/llvm/IR/Attributes.h1
-rw-r--r--lib/Analysis/ValueTracking.cpp4
-rw-r--r--lib/AsmParser/LLLexer.cpp1
-rw-r--r--lib/AsmParser/LLParser.cpp3
-rw-r--r--lib/AsmParser/LLToken.h1
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp2
-rw-r--r--lib/Bitcode/Writer/BitcodeWriter.cpp2
-rw-r--r--lib/IR/Attributes.cpp4
-rw-r--r--lib/IR/Function.cpp8
-rw-r--r--test/Bitcode/attributes.ll5
14 files changed, 44 insertions, 4 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index d2f9a1d4f1..ceec1bd547 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -847,6 +847,13 @@ Currently, only the following parameter attributes are defined:
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.
+``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:
Garbage Collector Names
diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h
index 151165e704..f37e3f89ca 100644
--- a/include/llvm-c/Core.h
+++ b/include/llvm-c/Core.h
@@ -165,7 +165,8 @@ typedef enum {
LLVMStackProtectStrongAttribute = 1ULL<<33,
LLVMCold = 1ULL << 34,
LLVMOptimizeNone = 1ULL << 35,
- LLVMInAllocaAttribute = 1ULL << 36
+ LLVMInAllocaAttribute = 1ULL << 36,
+ LLVMNonNullAttribute = 1ULL << 37
*/
} LLVMAttribute;
diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h
index a07dc585b8..04c08ab3f4 100644
--- a/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/include/llvm/Bitcode/LLVMBitCodes.h
@@ -371,7 +371,8 @@ namespace bitc {
ATTR_KIND_BUILTIN = 35,
ATTR_KIND_COLD = 36,
ATTR_KIND_OPTIMIZE_NONE = 37,
- ATTR_KIND_IN_ALLOCA = 38
+ ATTR_KIND_IN_ALLOCA = 38,
+ ATTR_KIND_NON_NULL = 39
};
} // End bitc namespace
diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h
index d226bd3c85..3a63e1a1ea 100644
--- a/include/llvm/IR/Argument.h
+++ b/include/llvm/IR/Argument.h
@@ -55,6 +55,10 @@ public:
/// For example in "void foo(int a, float b)" a is 0 and b is 1.
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
/// containing function.
bool hasByValAttr() const;
diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h
index cb4275337d..86f9cc8894 100644
--- a/include/llvm/IR/Attributes.h
+++ b/include/llvm/IR/Attributes.h
@@ -86,6 +86,7 @@ public:
NoInline, ///< inline=never
NonLazyBind, ///< Function is called early and/or
///< often, so lazy binding isn't worthwhile
+ NonNull, ///< Pointer is known to be not null
NoRedZone, ///< Disable redzone
NoReturn, ///< Mark the function as not returning
NoUnwind, ///< Function doesn't unwind stack
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index 44305bb016..280f15b509 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -2065,9 +2065,9 @@ bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
// Alloca never returns null, malloc might.
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))
- return A->hasByValOrInAllocaAttr();
+ return A->hasByValOrInAllocaAttr() || A->hasNonNullAttr();
// Global values are not null unless extern weak.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index 905bc20bc5..44a34126e4 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -593,6 +593,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(noimplicitfloat);
KEYWORD(noinline);
KEYWORD(nonlazybind);
+ KEYWORD(nonnull);
KEYWORD(noredzone);
KEYWORD(noreturn);
KEYWORD(nounwind);
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index 4c020c1bfc..3282e8a23b 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -1003,6 +1003,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_nest:
case lltok::kw_noalias:
case lltok::kw_nocapture:
+ case lltok::kw_nonnull:
case lltok::kw_returned:
case lltok::kw_sret:
HaveError |=
@@ -1217,6 +1218,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); 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_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
@@ -1269,6 +1271,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
return HaveError;
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); 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_zeroext: B.addAttribute(Attribute::ZExt); break;
diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h
index d5d45312c2..b6b7d824b5 100644
--- a/lib/AsmParser/LLToken.h
+++ b/lib/AsmParser/LLToken.h
@@ -117,6 +117,7 @@ namespace lltok {
kw_noimplicitfloat,
kw_noinline,
kw_nonlazybind,
+ kw_nonnull,
kw_noredzone,
kw_noreturn,
kw_nounwind,
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index fe5d57262e..4170f98567 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -569,6 +569,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
return Attribute::NoInline;
case bitc::ATTR_KIND_NON_LAZY_BIND:
return Attribute::NonLazyBind;
+ case bitc::ATTR_KIND_NON_NULL:
+ return Attribute::NonNull;
case bitc::ATTR_KIND_NO_RED_ZONE:
return Attribute::NoRedZone;
case bitc::ATTR_KIND_NO_RETURN:
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index 23374872df..db254e6a94 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -197,6 +197,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NO_INLINE;
case Attribute::NonLazyBind:
return bitc::ATTR_KIND_NON_LAZY_BIND;
+ case Attribute::NonNull:
+ return bitc::ATTR_KIND_NON_NULL;
case Attribute::NoRedZone:
return bitc::ATTR_KIND_NO_RED_ZONE;
case Attribute::NoReturn:
diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp
index 0bbbd55978..a9074bb294 100644
--- a/lib/IR/Attributes.cpp
+++ b/lib/IR/Attributes.cpp
@@ -193,6 +193,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "noinline";
if (hasAttribute(Attribute::NonLazyBind))
return "nonlazybind";
+ if (hasAttribute(Attribute::NonNull))
+ return "nonnull";
if (hasAttribute(Attribute::NoRedZone))
return "noredzone";
if (hasAttribute(Attribute::NoReturn))
@@ -392,6 +394,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::Builtin: return 1ULL << 41;
case Attribute::OptimizeNone: return 1ULL << 42;
case Attribute::InAlloca: return 1ULL << 43;
+ case Attribute::NonNull: return 1ULL << 44;
}
llvm_unreachable("Unsupported attribute type");
}
@@ -1177,6 +1180,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
.addAttribute(Attribute::Nest)
.addAttribute(Attribute::NoAlias)
.addAttribute(Attribute::NoCapture)
+ .addAttribute(Attribute::NonNull)
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::StructRet)
diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp
index de8e66f1bc..fe32c4613e 100644
--- a/lib/IR/Function.cpp
+++ b/lib/IR/Function.cpp
@@ -76,6 +76,14 @@ unsigned Argument::getArgNo() const {
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
/// in its containing function.
bool Argument::hasByValAttr() const {
diff --git a/test/Bitcode/attributes.ll b/test/Bitcode/attributes.ll
index 545f1cbb28..02e1bb1c4e 100644
--- a/test/Bitcode/attributes.ll
+++ b/test/Bitcode/attributes.ll
@@ -218,6 +218,11 @@ define void @f36(i8* inalloca) {
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 #1 = { nounwind }
; CHECK: attributes #2 = { readnone }