[IR] Convert null-pointer-is-valid into an enum attribute
authorNikita Popov <nikita.ppv@gmail.com>
Sat, 25 Apr 2020 10:57:07 +0000 (12:57 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 15 May 2020 17:41:07 +0000 (19:41 +0200)
The "null-pointer-is-valid" attribute needs to be checked by many
pointer-related combines. To make the check more efficient, convert
it from a string into an enum attribute.

In the future, this attribute may be replaced with data layout
properties.

Differential Revision: https://reviews.llvm.org/D78862

79 files changed:
clang/lib/CodeGen/CGCall.cpp
clang/test/CodeGen/delete-null-pointer-checks.c
llvm/docs/LangRef.rst
llvm/include/llvm/Bitcode/LLVMBitCodes.h
llvm/include/llvm/IR/Attributes.td
llvm/include/llvm/IR/AutoUpgrade.h
llvm/lib/AsmParser/LLLexer.cpp
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/AsmParser/LLToken.h
llvm/lib/Bitcode/Reader/BitcodeReader.cpp
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/IR/Attributes.cpp
llvm/lib/IR/AutoUpgrade.cpp
llvm/lib/IR/Function.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/Utils/CodeExtractor.cpp
llvm/test/Analysis/MemorySSA/cyclicphi.ll
llvm/test/Analysis/ValueTracking/assume.ll
llvm/test/Bitcode/attributes.ll
llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll
llvm/test/Transforms/Attributor/align.ll
llvm/test/Transforms/Attributor/nocapture-1.ll
llvm/test/Transforms/Attributor/nonnull.ll
llvm/test/Transforms/Attributor/norecurse.ll
llvm/test/Transforms/Attributor/undefined_behavior.ll
llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
llvm/test/Transforms/FunctionAttrs/nocapture.ll
llvm/test/Transforms/FunctionAttrs/nonnull.ll
llvm/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-1.ll
llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-2.ll
llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-3.ll
llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-4.ll
llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll
llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll
llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll
llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll
llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll
llvm/test/Transforms/IPConstantProp/PR26044.ll
llvm/test/Transforms/Inline/attributes.ll
llvm/test/Transforms/InstCombine/atomic.ll
llvm/test/Transforms/InstCombine/invariant.group.ll
llvm/test/Transforms/InstCombine/invoke.ll
llvm/test/Transforms/InstCombine/lifetime-no-null-opt.ll
llvm/test/Transforms/InstCombine/load.ll
llvm/test/Transforms/InstCombine/mem-deref-bytes.ll
llvm/test/Transforms/InstCombine/memchr.ll
llvm/test/Transforms/InstCombine/memcpy-addrspace.ll
llvm/test/Transforms/InstCombine/memcpy-from-global.ll
llvm/test/Transforms/InstCombine/memrchr.ll
llvm/test/Transforms/InstCombine/select.ll
llvm/test/Transforms/InstCombine/store.ll
llvm/test/Transforms/InstCombine/strchr-1.ll
llvm/test/Transforms/InstCombine/strcpy_chk-64.ll
llvm/test/Transforms/InstCombine/strlen-1.ll
llvm/test/Transforms/InstCombine/strncat-2.ll
llvm/test/Transforms/InstCombine/strncmp-1.ll
llvm/test/Transforms/InstCombine/strrchr-1.ll
llvm/test/Transforms/InstCombine/strstr-1.ll
llvm/test/Transforms/InstCombine/wcslen-1.ll
llvm/test/Transforms/InstSimplify/compare.ll
llvm/test/Transforms/LoopIdiom/pr28196.ll
llvm/test/Transforms/LoopVersioning/lcssa.ll
llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
llvm/test/Transforms/SimplifyCFG/invoke.ll
llvm/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll
llvm/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll
llvm/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll
llvm/test/Transforms/Util/assume-builder.ll
mlir/test/Target/llvmir.mlir

index 32a9ba4..068d053 100644 (file)
@@ -1744,7 +1744,7 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
                            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 a3c1460..261598f 100644 (file)
@@ -16,5 +16,5 @@ int null_check(int *P) {
   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
index 07320de..a1f3297 100644 (file)
@@ -1580,8 +1580,8 @@ example:
     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 2f09ad3..e0093a1 100644 (file)
@@ -637,6 +637,7 @@ enum AttributeKindCodes {
   ATTR_KIND_SANITIZE_MEMTAG = 64,
   ATTR_KIND_PREALLOCATED = 65,
   ATTR_KIND_NO_MERGE = 66,
+  ATTR_KIND_NULL_POINTER_IS_VALID = 67,
 };
 
 enum ComdatSelectionKindCodes {
index 63b85eb..209b8cc 100644 (file)
@@ -127,6 +127,9 @@ def NoCfCheck : EnumAttr<"nocf_check">;
 /// 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 42f50cc..9ddec28 100644 (file)
@@ -92,9 +92,8 @@ namespace llvm {
   /// 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 eb85ef7..71cf22c 100644 (file)
@@ -665,6 +665,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(nosync);
   KEYWORD(nocf_check);
   KEYWORD(nounwind);
+  KEYWORD(null_pointer_is_valid);
   KEYWORD(optforfuzzing);
   KEYWORD(optnone);
   KEYWORD(optsize);
index d045bcd..8455a02 100644 (file)
@@ -1316,6 +1316,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
     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 ffced33..201ba04 100644 (file)
@@ -211,6 +211,7 @@ enum Kind {
   kw_nosync,
   kw_nocf_check,
   kw_nounwind,
+  kw_null_pointer_is_valid,
   kw_optforfuzzing,
   kw_optnone,
   kw_optsize,
index 21759c5..c3c4996 100644 (file)
@@ -1469,6 +1469,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     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:
@@ -1654,7 +1656,7 @@ Error BitcodeReader::parseAttributeGroupBlock() {
         }
       }
 
-      UpgradeFramePointerAttributes(B);
+      UpgradeAttributes(B);
       MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B);
       break;
     }
index 5b62a47..fd4275f 100644 (file)
@@ -667,6 +667,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     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 ebf5dd9..bf39740 100644 (file)
@@ -385,6 +385,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     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))
@@ -1930,12 +1932,12 @@ adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) {
   }
 }
 
-/// If the inlined function has "null-pointer-is-valid=true" attribute,
+/// If the inlined function has null_pointer_is_valid 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 d61b797..d7a4f44 100644 (file)
@@ -4245,7 +4245,7 @@ std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) {
   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 @@ void llvm::UpgradeFramePointerAttributes(AttrBuilder &B) {
       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 7bf3ab5..d8663be 100644 (file)
@@ -1641,9 +1641,7 @@ Optional<StringRef> Function::getSectionPrefix() const {
 }
 
 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 8fbc9e7..ed211c5 100644 (file)
@@ -1563,6 +1563,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
   case Attribute::SpeculativeLoadHardening:
   case Attribute::Speculatable:
   case Attribute::StrictFP:
+  case Attribute::NullPointerIsValid:
     return true;
   default:
     break;
index e8154ec..2710391 100644 (file)
@@ -911,6 +911,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
       case Attribute::NonLazyBind:
       case Attribute::NoRedZone:
       case Attribute::NoUnwind:
+      case Attribute::NullPointerIsValid:
       case Attribute::OptForFuzzing:
       case Attribute::OptimizeNone:
       case Attribute::OptimizeForSize:
index b643489..9db1968 100644 (file)
@@ -152,4 +152,4 @@ bb77:                                             ; preds = %bb68, %bb26
   br label %bb26
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index f480c80..ece4291 100644 (file)
@@ -91,7 +91,7 @@ A:
   ret i32 %6
 }
 
-define dso_local i32 @test4b(i32* readonly %0, i1 %cond) "null-pointer-is-valid"="true" {
+define dso_local i32 @test4b(i32* readonly %0, i1 %cond) null_pointer_is_valid {
 ; CHECK-LABEL: @test4b(
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[TMP0:%.*]], i32 4) ]
 ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
index d38eaee..71c1fb5 100644 (file)
@@ -380,6 +380,12 @@ define void @f64(i32* preallocated(i32) %a)
   ret void
 }
 
+; CHECK: define void @f65() #40
+define void @f65() null_pointer_is_valid
+{
+  ret void;
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -420,4 +426,5 @@ define void @f64(i32* preallocated(i32) %a)
 ; CHECK: attributes #37 = { nofree }
 ; CHECK: attributes #38 = { nosync }
 ; CHECK: attributes #39 = { sanitize_memtag }
+; CHECK: attributes #40 = { null_pointer_is_valid }
 ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
index 517f8af..4f072d7 100644 (file)
@@ -68,7 +68,7 @@ entry:
   ret i32 %cond
 }
 
-define void @fn_no_null_opt(i32* %P, i1 %C) "null-pointer-is-valid"="true" {
+define void @fn_no_null_opt(i32* %P, i1 %C) null_pointer_is_valid {
 ;
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@fn_no_null_opt
 ; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]])
index 0dd2b96..ab10424 100644 (file)
@@ -779,4 +779,4 @@ exit:
 
 attributes #0 = { nounwind uwtable noinline }
 attributes #1 = { uwtable noinline }
-attributes #2 = { "null-pointer-is-valid"="true" }
+attributes #2 = { null_pointer_is_valid }
index 6ca1a80..559c626 100644 (file)
@@ -528,7 +528,7 @@ define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x
   ret i1 %2
 }
 
-define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
+define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) null_pointer_is_valid {
 ; CHECK-LABEL: define {{[^@]+}}@captureDereferenceableOrNullICmp
 ; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) [[X:%.*]])
 ; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i32* [[X]] to i8*
index c9f380f..9e4a4ac 100644 (file)
@@ -1231,5 +1231,5 @@ define void @nonnull_assume_neg(i8* %arg) {
 declare void @use_i8_ptr(i8* nofree nocapture readnone) nounwind
 declare void @use_i8_ptr_ret(i8* nofree nocapture readnone) nounwind willreturn
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 attributes #1 = { nounwind willreturn}
index 0740ea3..41e8d7c 100644 (file)
@@ -211,8 +211,8 @@ define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
   ret i32 %3
 }
 
-; CHECK-NOT: Function Attrs
-define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{
+; CHECK: Function Attrs: null_pointer_is_valid
+define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr null_pointer_is_valid{
 ; CHECK-LABEL: define {{[^@]+}}@eval_func2
 ; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr
 ; CHECK-NEXT:    [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]])
index c5f9284..8a2185f 100644 (file)
@@ -49,7 +49,7 @@ e:
 
 ; Note that while the load is removed (because it's unused), the block
 ; is not changed to unreachable
-define void @load_null_pointer_is_defined() "null-pointer-is-valid"="true" {
+define void @load_null_pointer_is_defined() null_pointer_is_valid {
 ; CHECK-LABEL: define {{[^@]+}}@load_null_pointer_is_defined()
 ; CHECK-NEXT:    ret void
 ;
@@ -100,7 +100,7 @@ e:
   ret void
 }
 
-define void @store_null_pointer_is_defined() "null-pointer-is-valid"="true" {
+define void @store_null_pointer_is_defined() null_pointer_is_valid {
 ; CHECK-LABEL: define {{[^@]+}}@store_null_pointer_is_defined()
 ; CHECK-NEXT:    store i32 5, i32* null, align 536870912
 ; CHECK-NEXT:    ret void
@@ -148,7 +148,7 @@ e:
   ret void
 }
 
-define void @atomicrmw_null_pointer_is_defined() "null-pointer-is-valid"="true" {
+define void @atomicrmw_null_pointer_is_defined() null_pointer_is_valid {
 ; CHECK-LABEL: define {{[^@]+}}@atomicrmw_null_pointer_is_defined()
 ; CHECK-NEXT:    [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire
 ; CHECK-NEXT:    ret void
@@ -196,7 +196,7 @@ e:
   ret void
 }
 
-define void @atomiccmpxchg_null_pointer_is_defined() "null-pointer-is-valid"="true" {
+define void @atomiccmpxchg_null_pointer_is_defined() null_pointer_is_valid {
 ; CHECK-LABEL: define {{[^@]+}}@atomiccmpxchg_null_pointer_is_defined()
 ; CHECK-NEXT:    [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
 ; CHECK-NEXT:    ret void
index 2a4ff5e..fe4fc09 100644 (file)
@@ -333,4 +333,4 @@ merge:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 25759cf..ba43f96 100644 (file)
@@ -311,7 +311,7 @@ define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x
 }
 
 ; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
-define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
+define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) null_pointer_is_valid {
   %1 = bitcast i32* %x to i8*
   %2 = icmp eq i8* %1, null
   ret i1 %2
index 128a2bd..a71d656 100644 (file)
@@ -770,5 +770,5 @@ define void @PR43833_simple(i32* %0, i32 %1) {
   br i1 %11, label %7, label %8
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 attributes #1 = { nounwind willreturn}
index 88896a4..f6c7314 100644 (file)
@@ -58,7 +58,7 @@ cond.end:
   %call = tail call i32 @bar(i8* %3, i8* %6)
   ret i32 %call
 }
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 declare i32 @bar(i8*, i8*) local_unnamed_addr #1
 !llvm.dbg.cu = !{!0}
index c9b3f6f..2b4bbb5 100644 (file)
@@ -31,4 +31,4 @@ entry:
 
 declare noalias i8* @malloc(i32)
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index c826e7f..95ee0b7 100644 (file)
@@ -36,5 +36,5 @@ bb2:          ; preds = %bb1
        ret i32 %3
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
index 28a20ad..9c060e4 100644 (file)
@@ -42,4 +42,4 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index c33bcba..a8456ea 100644 (file)
@@ -36,4 +36,4 @@ bb2:          ; preds = %bb1
        ret i32 %3
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index ec05b22..150642e 100644 (file)
@@ -42,4 +42,4 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index ba3b0a4..c6760ed 100644 (file)
@@ -38,4 +38,4 @@ bb2:          ; preds = %bb1
        ret i32 %3
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 67058c8..2063966 100644 (file)
@@ -43,4 +43,4 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 607c93d..a17f347 100644 (file)
@@ -41,4 +41,4 @@ bb2:          ; preds = %bb1
        ret i32 %3
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 71832f3..ef6f104 100644 (file)
@@ -43,5 +43,5 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
index 06c74e5..a942fb3 100644 (file)
@@ -51,4 +51,4 @@ bb2:          ; preds = %bb1
        ret i32 %tmp3
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 770220d..e16881a 100644 (file)
@@ -49,4 +49,4 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index d319d16..a1011c6 100644 (file)
@@ -25,4 +25,4 @@ define i64* @bar() {
 ; CHECK: load
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index fc6dab3..81d24e4 100644 (file)
@@ -28,4 +28,4 @@ define i32 @get() #0 {
 ; CHECK: ret i32 %V
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index a8f1274..51f06b1 100644 (file)
@@ -28,5 +28,5 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
index 009a334..c3e958d 100644 (file)
@@ -21,4 +21,4 @@ define void @t() #0 {
 }
 
 declare noalias i8* @malloc(i64)
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 64f3793..5e8d7d4 100644 (file)
@@ -24,4 +24,4 @@ entry:
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 709df17..179e83b 100644 (file)
@@ -37,4 +37,4 @@ isNull:         ; preds = %0
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index c9a63f0..1ffab80 100644 (file)
@@ -24,4 +24,4 @@ define void @doit() #0 {
         ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index efd229e..6e63d24 100644 (file)
@@ -84,4 +84,4 @@ entry:
   ret i32 %cond
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 81c189a..5f27ac5 100644 (file)
@@ -389,18 +389,18 @@ define i32 @test_no-use-jump-tables3(i32 %i) "no-jump-tables"="true" {
 ; CHECK-NEXT: ret i32
 }
 
-; Callee with "null-pointer-is-valid"="true" attribute should not be inlined
+; Callee with null_pointer_is_valid attribute should not be inlined
 ; into a caller without this attribute.
 ; Exception: alwaysinline callee can still be inlined but
-; "null-pointer-is-valid"="true" should get copied to caller.
+; null_pointer_is_valid should get copied to caller.
 
-define i32 @null-pointer-is-valid_callee0(i32 %i) "null-pointer-is-valid"="true" {
+define i32 @null-pointer-is-valid_callee0(i32 %i) null_pointer_is_valid {
   ret i32 %i
 ; CHECK: @null-pointer-is-valid_callee0(i32 %i)
 ; CHECK-NEXT: ret i32
 }
 
-define i32 @null-pointer-is-valid_callee1(i32 %i) alwaysinline "null-pointer-is-valid"="true" {
+define i32 @null-pointer-is-valid_callee1(i32 %i) alwaysinline null_pointer_is_valid {
   ret i32 %i
 ; CHECK: @null-pointer-is-valid_callee1(i32 %i)
 ; CHECK-NEXT: ret i32
@@ -412,7 +412,7 @@ define i32 @null-pointer-is-valid_callee2(i32 %i)  {
 ; CHECK-NEXT: ret i32
 }
 
-; No inlining since caller does not have "null-pointer-is-valid"="true" attribute.
+; No inlining since caller does not have null_pointer_is_valid attribute.
 define i32 @test_null-pointer-is-valid0(i32 %i) {
   %1 = call i32 @null-pointer-is-valid_callee0(i32 %i)
   ret i32 %1
@@ -422,18 +422,18 @@ define i32 @test_null-pointer-is-valid0(i32 %i) {
 }
 
 ; alwaysinline should force inlining even when caller does not have
-; "null-pointer-is-valid"="true" attribute. However, the attribute should be
+; null_pointer_is_valid attribute. However, the attribute should be
 ; copied to caller.
-define i32 @test_null-pointer-is-valid1(i32 %i) "null-pointer-is-valid"="false" {
+define i32 @test_null-pointer-is-valid1(i32 %i) {
   %1 = call i32 @null-pointer-is-valid_callee1(i32 %i)
   ret i32 %1
 ; CHECK: @test_null-pointer-is-valid1(i32 %i) [[NULLPOINTERISVALID:#[0-9]+]] {
 ; CHECK-NEXT: ret i32
 }
 
-; Can inline since both caller and callee have "null-pointer-is-valid"="true"
+; Can inline since both caller and callee have null_pointer_is_valid
 ; attribute.
-define i32 @test_null-pointer-is-valid2(i32 %i) "null-pointer-is-valid"="true" {
+define i32 @test_null-pointer-is-valid2(i32 %i) null_pointer_is_valid {
   %1 = call i32 @null-pointer-is-valid_callee2(i32 %i)
   ret i32 %1
 ; CHECK: @test_null-pointer-is-valid2(i32 %i) [[NULLPOINTERISVALID]] {
@@ -445,4 +445,4 @@ define i32 @test_null-pointer-is-valid2(i32 %i) "null-pointer-is-valid"="true" {
 ; CHECK: attributes [[FPMAD_TRUE]] = { "less-precise-fpmad"="true" }
 ; CHECK: attributes [[NOIMPLICITFLOAT]] = { noimplicitfloat }
 ; CHECK: attributes [[NOUSEJUMPTABLES]] = { "no-jump-tables"="true" }
-; CHECK: attributes [[NULLPOINTERISVALID]] = { "null-pointer-is-valid"="true" }
+; CHECK: attributes [[NULLPOINTERISVALID]] = { null_pointer_is_valid }
index 16b222a..869b125 100644 (file)
@@ -330,4 +330,4 @@ define void @no_atomic_vector_store(<2 x float> %p, i8* %p2) {
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 6b79ceb..f3774ad 100644 (file)
@@ -147,4 +147,4 @@ declare i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)*)
 declare i16* @llvm.strip.invariant.group.p0i16(i16* %c1)
 declare i16 addrspace(42)* @llvm.strip.invariant.group.p42i16(i16 addrspace(42)* %c1)
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index deb4a2b..6585ff0 100644 (file)
@@ -66,7 +66,7 @@ lpad:
   tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
   unreachable
 }
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 ; CHECK-LABEL: @f3(
 define void @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
index ee3668b..bfc9667 100644 (file)
@@ -60,7 +60,7 @@ fin:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!22, !23}
index 3c41176..4fc8721 100644 (file)
@@ -78,7 +78,7 @@ define i32 @test7_no_null_opt(i32 %X) #0 {
   %R = load i32, i32* %V          ; <i32> [#uses=1]
   ret i32 %R
 }
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 define i32 @test8(i32* %P) {
 ; CHECK-LABEL: @test8(
index c19597a..a72f88b 100644 (file)
@@ -55,7 +55,7 @@ define i32 @memcmp_const_size_update_deref4(i8* nocapture readonly %d, i8* nocap
   ret i32 %call
 }
 
-define i32 @memcmp_const_size_update_deref5(i8* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="false" {
+define i32 @memcmp_const_size_update_deref5(i8* nocapture readonly %d, i8* nocapture readonly %s) {
 ; CHECK-LABEL: @memcmp_const_size_update_deref5(
 ; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @memcmp(i8* nonnull dereferenceable(40) [[D:%.*]], i8* nonnull dereferenceable(16) [[S:%.*]], i64 16)
 ; CHECK-NEXT:    ret i32 [[CALL]]
@@ -64,7 +64,7 @@ define i32 @memcmp_const_size_update_deref5(i8* nocapture readonly %d, i8* nocap
   ret i32 %call
 }
 
-define i32 @memcmp_const_size_update_deref6(i8* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="true" {
+define i32 @memcmp_const_size_update_deref6(i8* nocapture readonly %d, i8* nocapture readonly %s) null_pointer_is_valid {
 ; CHECK-LABEL: @memcmp_const_size_update_deref6(
 ; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16)
 ; CHECK-NEXT:    ret i32 [[CALL]]
@@ -73,7 +73,7 @@ define i32 @memcmp_const_size_update_deref6(i8* nocapture readonly %d, i8* nocap
   ret i32 %call
 }
 
-define i32 @memcmp_const_size_update_deref7(i8* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="true" {
+define i32 @memcmp_const_size_update_deref7(i8* nocapture readonly %d, i8* nocapture readonly %s) null_pointer_is_valid {
 ; CHECK-LABEL: @memcmp_const_size_update_deref7(
 ; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @memcmp(i8* nonnull dereferenceable(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16)
 ; CHECK-NEXT:    ret i32 [[CALL]]
index 2e2c29a..a38eca2 100644 (file)
@@ -233,7 +233,7 @@ define i8* @test18(i8* %str, i32 %c) {
   ret i8* %ret
 }
 
-define i8* @test19(i8* %str, i32 %c) "null-pointer-is-valid"="true" {
+define i8* @test19(i8* %str, i32 %c) null_pointer_is_valid {
 ; CHECK-LABEL: @test19(
 ; CHECK-NEXT:    [[RET:%.*]] = call i8* @memchr(i8* dereferenceable(5) [[STR:%.*]], i32 [[C:%.*]], i32 5)
 ; CHECK-NEXT:    ret i8* [[RET]]
index b57a24e..62a2724 100644 (file)
@@ -122,4 +122,4 @@ entry:
 declare void @llvm.memcpy.p0i8.p2i8.i64(i8* nocapture writeonly, i8 addrspace(2)* nocapture readonly, i64, i1)
 declare i32 @foo(i32* %x)
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 96029fa..60a06d2 100644 (file)
@@ -323,4 +323,4 @@ entry:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index feb3847..4ed01f4 100644 (file)
@@ -34,7 +34,7 @@ define i8* @test3(i8* %str, i32 %c) {
   ret i8* %ret
 }
 
-define i8* @test4(i8* %str, i32 %c) "null-pointer-is-valid"="true" {
+define i8* @test4(i8* %str, i32 %c) null_pointer_is_valid {
 ; CHECK-LABEL: @test4(
 ; CHECK-NEXT:    [[RET:%.*]] = call i8* @memrchr(i8* [[STR:%.*]], i32 [[C:%.*]], i32 5)
 ; CHECK-NEXT:    ret i8* [[RET]]
index 20b6dd1..bbed168 100644 (file)
@@ -375,7 +375,7 @@ define i32 @test16_no_null_opt_2(i1 %C, i32* %P) #0 {
   ret i32 %V
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 define i1 @test17(i32* %X, i1 %C) {
 ; CHECK-LABEL: @test17(
index af36289..98869ff 100644 (file)
@@ -45,7 +45,7 @@ define void @store_at_gep_off_no_null_opt(i64 %offset) #0 {
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 ;; Simple sinking tests
 
index 081c3bf..c18859e 100644 (file)
@@ -114,7 +114,7 @@ define i8* @test1(i8* %str, i32 %c) {
   ret i8* %ret
 }
 
-define i8* @test2(i8* %str, i32 %c) "null-pointer-is-valid"="true" {
+define i8* @test2(i8* %str, i32 %c) null_pointer_is_valid {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:    [[RET:%.*]] = call i8* @strchr(i8* [[STR:%.*]], i32 [[C:%.*]])
 ; CHECK-NEXT:    ret i8* [[RET]]
index 6ff063b..34ba063 100644 (file)
@@ -28,4 +28,4 @@ declare i8* @__strcpy_chk(i8*, i8*, i64) nounwind
 
 declare void @func2(i8*)
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 0ecf233..f7629e0 100644 (file)
@@ -219,4 +219,4 @@ define i32 @test2(i8* %str) #0 {
   ret i32 %len
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 4aed718..32eb4a9 100644 (file)
@@ -90,7 +90,7 @@ define i8* @test3(i8* %str1, i8* %str2, i32 %n) {
   ret i8* %temp1
 }
 
-define i8* @test4(i8* %str1, i8* %str2, i32 %n) "null-pointer-is-valid"="true" {
+define i8* @test4(i8* %str1, i8* %str2, i32 %n) null_pointer_is_valid {
 ; CHECK-LABEL: @test4(
 ; CHECK-NEXT:    [[TEMP1:%.*]] = call i8* @strncat(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]])
 ; CHECK-NEXT:    ret i8* [[TEMP1]]
index 4bb03cc..a6ce83b 100644 (file)
@@ -139,7 +139,7 @@ define i32 @test11(i8* %str1, i8* %str2, i32 %n) {
   ret i32 %temp1
 }
 
-define i32 @test12(i8* %str1, i8* %str2, i32 %n) "null-pointer-is-valid"="true" {
+define i32 @test12(i8* %str1, i8* %str2, i32 %n) null_pointer_is_valid {
 ; CHECK-LABEL: @test12(
 ; CHECK-NEXT:    [[TEMP1:%.*]] = call i32 @strncmp(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]])
 ; CHECK-NEXT:    ret i32 [[TEMP1]]
index e60e9bc..ad353fb 100644 (file)
@@ -81,7 +81,7 @@ define i8* @test1(i8* %str, i32 %c) {
   ret i8* %ret
 }
 
-define i8* @test2(i8* %str, i32 %c) "null-pointer-is-valid"="true" {
+define i8* @test2(i8* %str, i32 %c) null_pointer_is_valid {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:    [[RET:%.*]] = call i8* @strrchr(i8* [[STR:%.*]], i32 [[C:%.*]])
 ; CHECK-NEXT:    ret i8* [[RET]]
index 4a9e620..7603f64 100644 (file)
@@ -80,7 +80,7 @@ define i8* @test1(i8* %str1, i8* %str2) {
   ret i8* %ret
 }
 
-define i8* @test2(i8* %str1, i8* %str2) "null-pointer-is-valid"="true" {
+define i8* @test2(i8* %str1, i8* %str2) null_pointer_is_valid {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:    [[RET:%.*]] = call i8* @strstr(i8* [[STR1:%.*]], i8* [[STR2:%.*]])
 ; CHECK-NEXT:    ret i8* [[RET]]
index 1139048..5610681 100644 (file)
@@ -219,4 +219,4 @@ define i64 @test_no_simplify4() {
   ret i64 %l
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 5b997a5..86d26a8 100644 (file)
@@ -1673,4 +1673,4 @@ define i1 @cmp_through_addrspacecast(i32 addrspace(1)* %p1) {
   ret i1 %cmp
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index d65acec..7689bce 100644 (file)
@@ -50,4 +50,4 @@ for.body:                                         ; preds = %for.body, %for.body
 ; CHECK: load
 ; CHECK: store
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 6499306..01178a5 100644 (file)
@@ -69,4 +69,4 @@ bb3:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 36b44a2..c8f59d4 100644 (file)
@@ -206,4 +206,4 @@ else:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index a58e800..dcba88e 100644 (file)
@@ -159,4 +159,4 @@ lpad:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index e7e9e72..af59872 100644 (file)
@@ -236,4 +236,4 @@ if.end7:                                          ; preds = %if.else, %if.then4,
 ; CHECK-NEXT: phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index b3c104d..4cd5d2f 100644 (file)
@@ -7,7 +7,7 @@ define void @foo() nounwind ssp #0 !dbg !0 {
   ret void, !dbg !7
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
 
 !llvm.dbg.cu = !{!2}
 !llvm.module.flags = !{!10}
index b074393..de847c3 100644 (file)
@@ -122,4 +122,4 @@ F:
   ret void
 }
 
-attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #0 = { null_pointer_is_valid }
index 22938ee..f2ca8a3 100644 (file)
@@ -386,7 +386,7 @@ define i32 @test2(%struct.S* %0, i32* %1, i8* %2) {
   ret i32 %28
 }
 
-define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true" {
+define i32 @test3(%struct.S* %0, i32* %1, i8* %2) null_pointer_is_valid {
 ; BASIC-LABEL: define {{[^@]+}}@test3
 ; BASIC-SAME: (%struct.S* [[TMP0:%.*]], i32* [[TMP1:%.*]], i8* [[TMP2:%.*]]) #4
 ; BASIC-NEXT:    [[TMP4:%.*]] = alloca %struct.S*, align 8
index 2dcbc2f..88f0e2f 100644 (file)
@@ -1205,12 +1205,12 @@ llvm.func @callFenceInst() {
 
 // CHECK-LABEL: @passthrough
 // CHECK: #[[ATTR_GROUP:[0-9]*]]
-llvm.func @passthrough() attributes {passthrough = ["noinline", ["alignstack", "4"], "null-pointer-is-valid", ["foo", "bar"]]} {
+llvm.func @passthrough() attributes {passthrough = ["noinline", ["alignstack", "4"], "null_pointer_is_valid", ["foo", "bar"]]} {
   llvm.return
 }
 
 // CHECK: attributes #[[ATTR_GROUP]] = {
 // CHECK-DAG: noinline
 // CHECK-DAG: alignstack=4
-// CHECK-DAG: "null-pointer-is-valid"
+// CHECK-DAG: null_pointer_is_valid
 // CHECK-DAG: "foo"="bar"