Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -371,7 +371,8 @@ 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 Index: include/llvm/IR/Argument.h =================================================================== --- include/llvm/IR/Argument.h +++ include/llvm/IR/Argument.h @@ -55,6 +55,10 @@ /// 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; Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -86,6 +86,7 @@ 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 Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -2076,6 +2076,10 @@ // Alloca never returns null, malloc might. if (isa(V)) return true; + // Is it marked not null? + if (const Argument *A = dyn_cast(V)) + return A->hasNonNullAttr(); + // A byval or inalloca argument is never null. if (const Argument *A = dyn_cast(V)) return A->hasByValOrInAllocaAttr(); Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -593,6 +593,7 @@ KEYWORD(noimplicitfloat); KEYWORD(noinline); KEYWORD(nonlazybind); + KEYWORD(nonnull); KEYWORD(noredzone); KEYWORD(noreturn); KEYWORD(nounwind); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -959,6 +959,7 @@ 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 |= @@ -1173,6 +1174,7 @@ 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; @@ -1225,6 +1227,7 @@ 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; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -116,6 +116,7 @@ kw_noimplicitfloat, kw_noinline, kw_nonlazybind, + kw_nonnull, kw_noredzone, kw_noreturn, kw_nounwind, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -569,6 +569,8 @@ 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: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -197,6 +197,8 @@ 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: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -193,6 +193,8 @@ 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 @@ 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"); } @@ -1176,6 +1179,7 @@ .addAttribute(Attribute::Nest) .addAttribute(Attribute::NoAlias) .addAttribute(Attribute::NoCapture) + .addAttribute(Attribute::NonNull) .addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::StructRet) Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -76,6 +76,14 @@ 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 { Index: test/Analysis/BasicAA/nonnull.ll =================================================================== --- test/Analysis/BasicAA/nonnull.ll +++ test/Analysis/BasicAA/nonnull.ll @@ -0,0 +1,8 @@ +; RUN: opt < %s -basicaa -gvn -instcombine -S | FileCheck %s + +define i8 @foo(i64* nonnull %a) { +; CHECK: ret i8 0 + %b = icmp eq i64* %a, null + %c = zext i1 %b to i8 + ret i8 %c +} Index: test/Bitcode/attributes.ll =================================================================== --- test/Bitcode/attributes.ll +++ test/Bitcode/attributes.ll @@ -218,6 +218,11 @@ 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 }