Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1543,8 +1543,8 @@ trap or generate asynchronous exceptions. Exception handling schemes that are recognized by LLVM to handle asynchronous exceptions, such as SEH, will still provide their implementation defined semantics. -``"null-pointer-is-valid"`` - If ``"null-pointer-is-valid"`` is set to ``"true"``, then ``null`` address +``null_pointer_is_valid`` + If ``null_pointer_is_valid`` is set, then the ``null`` address in address-space 0 is considered to be a valid address for memory loads and stores. Any analysis or optimization should not treat dereferencing a pointer to ``null`` as undefined behavior in this function. Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -633,6 +633,7 @@ ATTR_KIND_NOFREE = 62, ATTR_KIND_NOSYNC = 63, ATTR_KIND_SANITIZE_MEMTAG = 64, + ATTR_KIND_NULL_POINTER_IS_VALID = 65, }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -118,6 +118,9 @@ /// Function doesn't unwind stack. def NoUnwind : EnumAttr<"nounwind">; +/// Null pointer in address space zero is valid. +def NullPointerIsValid : EnumAttr<"null_pointer_is_valid">; + /// Select optimizations for best fuzzing signal. def OptForFuzzing : EnumAttr<"optforfuzzing">; Index: include/llvm/IR/AutoUpgrade.h =================================================================== --- include/llvm/IR/AutoUpgrade.h +++ include/llvm/IR/AutoUpgrade.h @@ -92,9 +92,8 @@ /// pointers. std::string UpgradeDataLayoutString(StringRef DL, StringRef Triple); - /// Upgrade function attributes "no-frame-pointer-elim" and - /// "no-frame-pointer-elim-non-leaf" to "frame-pointer". - void UpgradeFramePointerAttributes(AttrBuilder &B); + /// Upgrade attributes that changed format or kind. + void UpgradeAttributes(AttrBuilder &B); } // End llvm namespace Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -664,6 +664,7 @@ KEYWORD(nosync); KEYWORD(nocf_check); KEYWORD(nounwind); + KEYWORD(null_pointer_is_valid); KEYWORD(optforfuzzing); KEYWORD(optnone); KEYWORD(optsize); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1312,6 +1312,8 @@ case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break; case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break; case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break; + case lltok::kw_null_pointer_is_valid: + B.addAttribute(Attribute::NullPointerIsValid); break; case lltok::kw_optforfuzzing: B.addAttribute(Attribute::OptForFuzzing); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -210,6 +210,7 @@ kw_nosync, kw_nocf_check, kw_nounwind, + kw_null_pointer_is_valid, kw_optforfuzzing, kw_optnone, kw_optsize, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1303,6 +1303,10 @@ case Attribute::SanitizeMemTag: llvm_unreachable("sanitize_memtag attribute not supported in raw format"); break; + case Attribute::NullPointerIsValid: + llvm_unreachable( + "null_pointer_is_valid attribute not supported in raw format"); + break; } llvm_unreachable("Unsupported attribute type"); } @@ -1312,7 +1316,8 @@ for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { - if (I == Attribute::SanitizeMemTag || + if (I == Attribute::NullPointerIsValid || + I == Attribute::SanitizeMemTag || I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || @@ -1484,6 +1489,8 @@ return Attribute::NoCfCheck; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; + case bitc::ATTR_KIND_NULL_POINTER_IS_VALID: + return Attribute::NullPointerIsValid; case bitc::ATTR_KIND_OPT_FOR_FUZZING: return Attribute::OptForFuzzing; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: @@ -1664,7 +1671,7 @@ } } - UpgradeFramePointerAttributes(B); + UpgradeAttributes(B); MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -666,6 +666,8 @@ return bitc::ATTR_KIND_NOCF_CHECK; case Attribute::NoUnwind: return bitc::ATTR_KIND_NO_UNWIND; + case Attribute::NullPointerIsValid: + return bitc::ATTR_KIND_NULL_POINTER_IS_VALID; case Attribute::OptForFuzzing: return bitc::ATTR_KIND_OPT_FOR_FUZZING; case Attribute::OptimizeForSize: Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1747,7 +1747,7 @@ llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD)); if (CodeGenOpts.NullPointerIsValid) - FuncAttrs.addAttribute("null-pointer-is-valid", "true"); + FuncAttrs.addAttribute(llvm::Attribute::NullPointerIsValid); if (CodeGenOpts.FPDenormalMode != llvm::DenormalMode::getIEEE()) FuncAttrs.addAttribute("denormal-fp-math", Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -376,6 +376,8 @@ return "noreturn"; if (hasAttribute(Attribute::NoSync)) return "nosync"; + if (hasAttribute(Attribute::NullPointerIsValid)) + return "null_pointer_is_valid"; if (hasAttribute(Attribute::WillReturn)) return "willreturn"; if (hasAttribute(Attribute::NoCfCheck)) @@ -1877,12 +1879,12 @@ } } -/// If the inlined function has "null-pointer-is-valid=true" attribute, +/// If the inlined function has null_pointer_is_defined attribute, /// set this attribute in the caller post inlining. static void adjustNullPointerValidAttr(Function &Caller, const Function &Callee) { if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) { - Caller.addFnAttr(Callee.getFnAttribute("null-pointer-is-valid")); + Caller.addFnAttr(Attribute::NullPointerIsValid); } } Index: lib/IR/AutoUpgrade.cpp =================================================================== --- lib/IR/AutoUpgrade.cpp +++ lib/IR/AutoUpgrade.cpp @@ -4245,7 +4245,7 @@ return Res; } -void llvm::UpgradeFramePointerAttributes(AttrBuilder &B) { +void llvm::UpgradeAttributes(AttrBuilder &B) { StringRef FramePointer; if (B.contains("no-frame-pointer-elim")) { // The value can be "true" or "false". @@ -4260,7 +4260,17 @@ FramePointer = "non-leaf"; B.removeAttribute("no-frame-pointer-elim-non-leaf"); } - if (!FramePointer.empty()) B.addAttribute("frame-pointer", FramePointer); + + if (B.contains("null-pointer-is-valid")) { + // The value can be "true" or "false". + bool NullPointerIsValid = false; + for (const auto &I : B.td_attrs()) + if (I.first == "null-pointer-is-valid") + NullPointerIsValid = I.second == "true"; + B.removeAttribute("null-pointer-is-valid"); + if (NullPointerIsValid) + B.addAttribute(Attribute::NullPointerIsValid); + } } Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -1634,9 +1634,7 @@ } bool Function::nullPointerIsDefined() const { - return getFnAttribute("null-pointer-is-valid") - .getValueAsString() - .equals("true"); + return hasFnAttribute(Attribute::NullPointerIsValid); } bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) { Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1552,6 +1552,7 @@ case Attribute::SpeculativeLoadHardening: case Attribute::Speculatable: case Attribute::StrictFP: + case Attribute::NullPointerIsValid: return true; default: break; Index: lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- lib/Transforms/Utils/CodeExtractor.cpp +++ lib/Transforms/Utils/CodeExtractor.cpp @@ -903,6 +903,7 @@ case Attribute::NonLazyBind: case Attribute::NoRedZone: case Attribute::NoUnwind: + case Attribute::NullPointerIsValid: case Attribute::OptForFuzzing: case Attribute::OptimizeNone: case Attribute::OptimizeForSize: Index: test/Bitcode/attributes.ll =================================================================== --- test/Bitcode/attributes.ll +++ test/Bitcode/attributes.ll @@ -374,6 +374,12 @@ ret void; } +; CHECK: define void @f64() #40 +define void @f64() null_pointer_is_valid +{ + ret void; +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -414,4 +420,5 @@ ; CHECK: attributes #37 = { nofree } ; CHECK: attributes #38 = { nosync } ; CHECK: attributes #39 = { sanitize_memtag } -; CHECK: attributes #40 = { nobuiltin } +; CHECK: attributes #40 = { null_pointer_is_valid } +; CHECK: attributes #41 = { nobuiltin } Index: test/CodeGen/delete-null-pointer-checks.c =================================================================== --- test/CodeGen/delete-null-pointer-checks.c +++ test/CodeGen/delete-null-pointer-checks.c @@ -16,5 +16,5 @@ return *Q; } -// NULL-POINTER-INVALID-NOT: attributes #0 = {{.*}} "null-pointer-is-valid"="true" -// NULL-POINTER-VALID: attributes #0 = {{.*}} "null-pointer-is-valid"="true" +// NULL-POINTER-INVALID-NOT: attributes #0 = {{.*}} null_pointer_is_valid +// NULL-POINTER-VALID: attributes #0 = {{.*}} null_pointer_is_valid