Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -1196,6 +1196,9 @@ checked or enforced by LLVM; if the parameter or return pointer is null, the behavior is undefined. +``nopoison`` + This indicates that the parameter or return value must not be poison. + ``dereferenceable()`` This indicates that the parameter or return pointer is dereferenceable. This attribute may only be applied to pointer typed parameters. A pointer that Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -643,6 +643,7 @@ ATTR_KIND_PREALLOCATED = 65, ATTR_KIND_NO_MERGE = 66, ATTR_KIND_NULL_POINTER_IS_VALID = 67, + ATTR_KIND_NO_POISON = 68, }; enum ComdatSelectionKindCodes { Index: llvm/include/llvm/IR/Argument.h =================================================================== --- llvm/include/llvm/IR/Argument.h +++ llvm/include/llvm/IR/Argument.h @@ -54,6 +54,9 @@ /// addrspace(0). bool hasNonNullAttr() const; + /// Return true if this argument is not poison + bool hasNoPoisonAttr() const; + /// If this argument has the dereferenceable attribute, return the number of /// bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableBytes() const; Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -151,6 +151,9 @@ /// Return value is always equal to this argument. def Returned : EnumAttr<"returned">; +/// Variable is known to be not poison +def NoPoison : EnumAttr<"nopoison">; + /// Parameter is required to be a trivial constant. def ImmArg : EnumAttr<"immarg">; Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -656,6 +656,7 @@ KEYWORD(nofree); KEYWORD(noimplicitfloat); KEYWORD(noinline); + KEYWORD(nopoison); KEYWORD(norecurse); KEYWORD(nonlazybind); KEYWORD(nomerge); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1376,6 +1376,7 @@ case lltok::kw_noalias: case lltok::kw_nocapture: case lltok::kw_nonnull: + case lltok::kw_nopoison: case lltok::kw_returned: case lltok::kw_sret: case lltok::kw_swifterror: @@ -1681,6 +1682,7 @@ case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break; case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break; case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break; + case lltok::kw_nopoison: B.addAttribute(Attribute::NoPoison); 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; @@ -1775,6 +1777,7 @@ 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_nopoison: B.addAttribute(Attribute::NoPoison); break; case lltok::kw_signext: B.addAttribute(Attribute::SExt); break; case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -206,6 +206,7 @@ kw_nonlazybind, kw_nomerge, kw_nonnull, + kw_nopoison, kw_noredzone, kw_noreturn, kw_nosync, Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1532,6 +1532,8 @@ return Attribute::SanitizeMemTag; case bitc::ATTR_KIND_PREALLOCATED: return Attribute::Preallocated; + case bitc::ATTR_KIND_NO_POISON: + return Attribute::NoPoison; } } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -731,6 +731,8 @@ return bitc::ATTR_KIND_SANITIZE_MEMTAG; case Attribute::Preallocated: return bitc::ATTR_KIND_PREALLOCATED; + case Attribute::NoPoison: + return bitc::ATTR_KIND_NO_POISON; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -379,6 +379,8 @@ return "nomerge"; if (hasAttribute(Attribute::NonNull)) return "nonnull"; + if (hasAttribute(Attribute::NoPoison)) + return "nopoison"; if (hasAttribute(Attribute::NoRedZone)) return "noredzone"; if (hasAttribute(Attribute::NoReturn)) Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -96,6 +96,10 @@ return false; } +bool Argument::hasNoPoisonAttr() const { + return hasAttribute(Attribute::NoPoison); +} + bool Argument::hasByValAttr() const { if (!getType()->isPointerTy()) return false; return hasAttribute(Attribute::ByVal); Index: llvm/test/Bitcode/attributes.ll =================================================================== --- llvm/test/Bitcode/attributes.ll +++ llvm/test/Bitcode/attributes.ll @@ -386,6 +386,12 @@ ret void; } +; CHECK: define nopoison i32 @f66(i32 nopoison %a) +define nopoison i32 @f66(i32 nopoison %a) +{ + ret i32 %a +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone }