1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[IR] Convert null-pointer-is-valid into an enum attribute

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
This commit is contained in:
Nikita Popov 2020-04-25 12:57:07 +02:00
parent 7b938ff5c1
commit cf8ee33937
76 changed files with 119 additions and 89 deletions

View File

@ -1580,8 +1580,8 @@ example:
trap or generate asynchronous exceptions. Exception handling schemes trap or generate asynchronous exceptions. Exception handling schemes
that are recognized by LLVM to handle asynchronous exceptions, such that are recognized by LLVM to handle asynchronous exceptions, such
as SEH, will still provide their implementation defined semantics. as SEH, will still provide their implementation defined semantics.
``"null-pointer-is-valid"`` ``null_pointer_is_valid``
If ``"null-pointer-is-valid"`` is set to ``"true"``, then ``null`` address 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 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 stores. Any analysis or optimization should not treat dereferencing a
pointer to ``null`` as undefined behavior in this function. pointer to ``null`` as undefined behavior in this function.

View File

@ -637,6 +637,7 @@ enum AttributeKindCodes {
ATTR_KIND_SANITIZE_MEMTAG = 64, ATTR_KIND_SANITIZE_MEMTAG = 64,
ATTR_KIND_PREALLOCATED = 65, ATTR_KIND_PREALLOCATED = 65,
ATTR_KIND_NO_MERGE = 66, ATTR_KIND_NO_MERGE = 66,
ATTR_KIND_NULL_POINTER_IS_VALID = 67,
}; };
enum ComdatSelectionKindCodes { enum ComdatSelectionKindCodes {

View File

@ -127,6 +127,9 @@ def NoCfCheck : EnumAttr<"nocf_check">;
/// Function doesn't unwind stack. /// Function doesn't unwind stack.
def NoUnwind : EnumAttr<"nounwind">; 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. /// Select optimizations for best fuzzing signal.
def OptForFuzzing : EnumAttr<"optforfuzzing">; def OptForFuzzing : EnumAttr<"optforfuzzing">;

View File

@ -92,9 +92,8 @@ namespace llvm {
/// pointers. /// pointers.
std::string UpgradeDataLayoutString(StringRef DL, StringRef Triple); std::string UpgradeDataLayoutString(StringRef DL, StringRef Triple);
/// Upgrade function attributes "no-frame-pointer-elim" and /// Upgrade attributes that changed format or kind.
/// "no-frame-pointer-elim-non-leaf" to "frame-pointer". void UpgradeAttributes(AttrBuilder &B);
void UpgradeFramePointerAttributes(AttrBuilder &B);
} // End llvm namespace } // End llvm namespace

View File

@ -665,6 +665,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(nosync); KEYWORD(nosync);
KEYWORD(nocf_check); KEYWORD(nocf_check);
KEYWORD(nounwind); KEYWORD(nounwind);
KEYWORD(null_pointer_is_valid);
KEYWORD(optforfuzzing); KEYWORD(optforfuzzing);
KEYWORD(optnone); KEYWORD(optnone);
KEYWORD(optsize); KEYWORD(optsize);

View File

@ -1316,6 +1316,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break; case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break; case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); 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: case lltok::kw_optforfuzzing:
B.addAttribute(Attribute::OptForFuzzing); break; B.addAttribute(Attribute::OptForFuzzing); break;
case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break;

View File

@ -211,6 +211,7 @@ enum Kind {
kw_nosync, kw_nosync,
kw_nocf_check, kw_nocf_check,
kw_nounwind, kw_nounwind,
kw_null_pointer_is_valid,
kw_optforfuzzing, kw_optforfuzzing,
kw_optnone, kw_optnone,
kw_optsize, kw_optsize,

View File

@ -1469,6 +1469,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::NoCfCheck; return Attribute::NoCfCheck;
case bitc::ATTR_KIND_NO_UNWIND: case bitc::ATTR_KIND_NO_UNWIND:
return Attribute::NoUnwind; return Attribute::NoUnwind;
case bitc::ATTR_KIND_NULL_POINTER_IS_VALID:
return Attribute::NullPointerIsValid;
case bitc::ATTR_KIND_OPT_FOR_FUZZING: case bitc::ATTR_KIND_OPT_FOR_FUZZING:
return Attribute::OptForFuzzing; return Attribute::OptForFuzzing;
case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: 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); MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B);
break; break;
} }

View File

@ -667,6 +667,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NOCF_CHECK; return bitc::ATTR_KIND_NOCF_CHECK;
case Attribute::NoUnwind: case Attribute::NoUnwind:
return bitc::ATTR_KIND_NO_UNWIND; return bitc::ATTR_KIND_NO_UNWIND;
case Attribute::NullPointerIsValid:
return bitc::ATTR_KIND_NULL_POINTER_IS_VALID;
case Attribute::OptForFuzzing: case Attribute::OptForFuzzing:
return bitc::ATTR_KIND_OPT_FOR_FUZZING; return bitc::ATTR_KIND_OPT_FOR_FUZZING;
case Attribute::OptimizeForSize: case Attribute::OptimizeForSize:

View File

@ -385,6 +385,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "noreturn"; return "noreturn";
if (hasAttribute(Attribute::NoSync)) if (hasAttribute(Attribute::NoSync))
return "nosync"; return "nosync";
if (hasAttribute(Attribute::NullPointerIsValid))
return "null_pointer_is_valid";
if (hasAttribute(Attribute::WillReturn)) if (hasAttribute(Attribute::WillReturn))
return "willreturn"; return "willreturn";
if (hasAttribute(Attribute::NoCfCheck)) 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. /// set this attribute in the caller post inlining.
static void static void
adjustNullPointerValidAttr(Function &Caller, const Function &Callee) { adjustNullPointerValidAttr(Function &Caller, const Function &Callee) {
if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) { if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {
Caller.addFnAttr(Callee.getFnAttribute("null-pointer-is-valid")); Caller.addFnAttr(Attribute::NullPointerIsValid);
} }
} }

View File

@ -4245,7 +4245,7 @@ std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) {
return Res; return Res;
} }
void llvm::UpgradeFramePointerAttributes(AttrBuilder &B) { void llvm::UpgradeAttributes(AttrBuilder &B) {
StringRef FramePointer; StringRef FramePointer;
if (B.contains("no-frame-pointer-elim")) { if (B.contains("no-frame-pointer-elim")) {
// The value can be "true" or "false". // The value can be "true" or "false".
@ -4260,7 +4260,17 @@ void llvm::UpgradeFramePointerAttributes(AttrBuilder &B) {
FramePointer = "non-leaf"; FramePointer = "non-leaf";
B.removeAttribute("no-frame-pointer-elim-non-leaf"); B.removeAttribute("no-frame-pointer-elim-non-leaf");
} }
if (!FramePointer.empty()) if (!FramePointer.empty())
B.addAttribute("frame-pointer", FramePointer); 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);
}
} }

View File

@ -1641,9 +1641,7 @@ Optional<StringRef> Function::getSectionPrefix() const {
} }
bool Function::nullPointerIsDefined() const { bool Function::nullPointerIsDefined() const {
return getFnAttribute("null-pointer-is-valid") return hasFnAttribute(Attribute::NullPointerIsValid);
.getValueAsString()
.equals("true");
} }
bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) { bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) {

View File

@ -1563,6 +1563,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
case Attribute::SpeculativeLoadHardening: case Attribute::SpeculativeLoadHardening:
case Attribute::Speculatable: case Attribute::Speculatable:
case Attribute::StrictFP: case Attribute::StrictFP:
case Attribute::NullPointerIsValid:
return true; return true;
default: default:
break; break;

View File

@ -911,6 +911,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::NonLazyBind: case Attribute::NonLazyBind:
case Attribute::NoRedZone: case Attribute::NoRedZone:
case Attribute::NoUnwind: case Attribute::NoUnwind:
case Attribute::NullPointerIsValid:
case Attribute::OptForFuzzing: case Attribute::OptForFuzzing:
case Attribute::OptimizeNone: case Attribute::OptimizeNone:
case Attribute::OptimizeForSize: case Attribute::OptimizeForSize:

View File

@ -152,4 +152,4 @@ bb77: ; preds = %bb68, %bb26
br label %bb26 br label %bb26
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -91,7 +91,7 @@ A:
ret i32 %6 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-LABEL: @test4b(
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[TMP0:%.*]], i32 4) ] ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[TMP0:%.*]], i32 4) ]
; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]] ; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]

View File

@ -380,6 +380,12 @@ define void @f64(i32* preallocated(i32) %a)
ret void ret void
} }
; CHECK: define void @f65() #40
define void @f65() null_pointer_is_valid
{
ret void;
}
; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone } ; CHECK: attributes #2 = { readnone }
@ -420,4 +426,5 @@ define void @f64(i32* preallocated(i32) %a)
; CHECK: attributes #37 = { nofree } ; CHECK: attributes #37 = { nofree }
; CHECK: attributes #38 = { nosync } ; CHECK: attributes #38 = { nosync }
; CHECK: attributes #39 = { sanitize_memtag } ; CHECK: attributes #39 = { sanitize_memtag }
; CHECK: attributes #40 = { null_pointer_is_valid }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin } ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }

View File

@ -68,7 +68,7 @@ entry:
ret i32 %cond 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____-LABEL: define {{[^@]+}}@fn_no_null_opt
; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) ; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]])

View File

@ -779,4 +779,4 @@ exit:
attributes #0 = { nounwind uwtable noinline } attributes #0 = { nounwind uwtable noinline }
attributes #1 = { uwtable noinline } attributes #1 = { uwtable noinline }
attributes #2 = { "null-pointer-is-valid"="true" } attributes #2 = { null_pointer_is_valid }

View File

@ -528,7 +528,7 @@ define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x
ret i1 %2 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-LABEL: define {{[^@]+}}@captureDereferenceableOrNullICmp
; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) [[X:%.*]]) ; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[X]] to i8* ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[X]] to i8*

View 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(i8* nofree nocapture readnone) nounwind
declare void @use_i8_ptr_ret(i8* nofree nocapture readnone) nounwind willreturn 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} attributes #1 = { nounwind willreturn}

View File

@ -211,8 +211,8 @@ define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
ret i32 %3 ret i32 %3
} }
; CHECK-NOT: Function Attrs ; CHECK: Function Attrs: null_pointer_is_valid
define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{ define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr null_pointer_is_valid{
; CHECK-LABEL: define {{[^@]+}}@eval_func2 ; CHECK-LABEL: define {{[^@]+}}@eval_func2
; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr ; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]])

View File

@ -49,7 +49,7 @@ e:
; Note that while the load is removed (because it's unused), the block ; Note that while the load is removed (because it's unused), the block
; is not changed to unreachable ; 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-LABEL: define {{[^@]+}}@load_null_pointer_is_defined()
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;
@ -100,7 +100,7 @@ e:
ret void 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-LABEL: define {{[^@]+}}@store_null_pointer_is_defined()
; CHECK-NEXT: store i32 5, i32* null, align 536870912 ; CHECK-NEXT: store i32 5, i32* null, align 536870912
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
@ -148,7 +148,7 @@ e:
ret void 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-LABEL: define {{[^@]+}}@atomicrmw_null_pointer_is_defined()
; CHECK-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire ; CHECK-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
@ -196,7 +196,7 @@ e:
ret void 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-LABEL: define {{[^@]+}}@atomiccmpxchg_null_pointer_is_defined()
; CHECK-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic ; CHECK-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void

View File

@ -333,4 +333,4 @@ merge:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View 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) ; 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* %1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1, null %2 = icmp eq i8* %1, null
ret i1 %2 ret i1 %2

View File

@ -770,5 +770,5 @@ define void @PR43833_simple(i32* %0, i32 %1) {
br i1 %11, label %7, label %8 br i1 %11, label %7, label %8
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
attributes #1 = { nounwind willreturn} attributes #1 = { nounwind willreturn}

View File

@ -58,7 +58,7 @@ cond.end:
%call = tail call i32 @bar(i8* %3, i8* %6) %call = tail call i32 @bar(i8* %3, i8* %6)
ret i32 %call 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 declare i32 @bar(i8*, i8*) local_unnamed_addr #1
!llvm.dbg.cu = !{!0} !llvm.dbg.cu = !{!0}

View File

@ -31,4 +31,4 @@ entry:
declare noalias i8* @malloc(i32) declare noalias i8* @malloc(i32)
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -36,5 +36,5 @@ bb2: ; preds = %bb1
ret i32 %3 ret i32 %3
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -42,4 +42,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -36,4 +36,4 @@ bb2: ; preds = %bb1
ret i32 %3 ret i32 %3
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -42,4 +42,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -38,4 +38,4 @@ bb2: ; preds = %bb1
ret i32 %3 ret i32 %3
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -43,4 +43,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -41,4 +41,4 @@ bb2: ; preds = %bb1
ret i32 %3 ret i32 %3
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -43,5 +43,5 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -51,4 +51,4 @@ bb2: ; preds = %bb1
ret i32 %tmp3 ret i32 %tmp3
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -49,4 +49,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -25,4 +25,4 @@ define i64* @bar() {
; CHECK: load ; CHECK: load
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -28,4 +28,4 @@ define i32 @get() #0 {
; CHECK: ret i32 %V ; CHECK: ret i32 %V
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -28,5 +28,5 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -21,4 +21,4 @@ define void @t() #0 {
} }
declare noalias i8* @malloc(i64) declare noalias i8* @malloc(i64)
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -24,4 +24,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -37,4 +37,4 @@ isNull: ; preds = %0
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -24,4 +24,4 @@ define void @doit() #0 {
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -84,4 +84,4 @@ entry:
ret i32 %cond ret i32 %cond
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -389,18 +389,18 @@ define i32 @test_no-use-jump-tables3(i32 %i) "no-jump-tables"="true" {
; CHECK-NEXT: ret i32 ; 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. ; into a caller without this attribute.
; Exception: alwaysinline callee can still be inlined but ; 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 ret i32 %i
; CHECK: @null-pointer-is-valid_callee0(i32 %i) ; CHECK: @null-pointer-is-valid_callee0(i32 %i)
; CHECK-NEXT: ret i32 ; 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 ret i32 %i
; CHECK: @null-pointer-is-valid_callee1(i32 %i) ; CHECK: @null-pointer-is-valid_callee1(i32 %i)
; CHECK-NEXT: ret i32 ; CHECK-NEXT: ret i32
@ -412,7 +412,7 @@ define i32 @null-pointer-is-valid_callee2(i32 %i) {
; CHECK-NEXT: ret i32 ; 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) { define i32 @test_null-pointer-is-valid0(i32 %i) {
%1 = call i32 @null-pointer-is-valid_callee0(i32 %i) %1 = call i32 @null-pointer-is-valid_callee0(i32 %i)
ret i32 %1 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 ; 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. ; 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) %1 = call i32 @null-pointer-is-valid_callee1(i32 %i)
ret i32 %1 ret i32 %1
; CHECK: @test_null-pointer-is-valid1(i32 %i) [[NULLPOINTERISVALID:#[0-9]+]] { ; CHECK: @test_null-pointer-is-valid1(i32 %i) [[NULLPOINTERISVALID:#[0-9]+]] {
; CHECK-NEXT: ret i32 ; 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. ; 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) %1 = call i32 @null-pointer-is-valid_callee2(i32 %i)
ret i32 %1 ret i32 %1
; CHECK: @test_null-pointer-is-valid2(i32 %i) [[NULLPOINTERISVALID]] { ; 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 [[FPMAD_TRUE]] = { "less-precise-fpmad"="true" }
; CHECK: attributes [[NOIMPLICITFLOAT]] = { noimplicitfloat } ; CHECK: attributes [[NOIMPLICITFLOAT]] = { noimplicitfloat }
; CHECK: attributes [[NOUSEJUMPTABLES]] = { "no-jump-tables"="true" } ; CHECK: attributes [[NOUSEJUMPTABLES]] = { "no-jump-tables"="true" }
; CHECK: attributes [[NULLPOINTERISVALID]] = { "null-pointer-is-valid"="true" } ; CHECK: attributes [[NULLPOINTERISVALID]] = { null_pointer_is_valid }

View File

@ -330,4 +330,4 @@ define void @no_atomic_vector_store(<2 x float> %p, i8* %p2) {
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View 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* @llvm.strip.invariant.group.p0i16(i16* %c1)
declare i16 addrspace(42)* @llvm.strip.invariant.group.p42i16(i16 addrspace(42)* %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 }

View File

@ -66,7 +66,7 @@ lpad:
tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
unreachable unreachable
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
; CHECK-LABEL: @f3( ; CHECK-LABEL: @f3(
define void @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { define void @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {

View File

@ -60,7 +60,7 @@ fin:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
!llvm.dbg.cu = !{!0} !llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!22, !23} !llvm.module.flags = !{!22, !23}

View File

@ -78,7 +78,7 @@ define i32 @test7_no_null_opt(i32 %X) #0 {
%R = load i32, i32* %V ; <i32> [#uses=1] %R = load i32, i32* %V ; <i32> [#uses=1]
ret i32 %R ret i32 %R
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
define i32 @test8(i32* %P) { define i32 @test8(i32* %P) {
; CHECK-LABEL: @test8( ; CHECK-LABEL: @test8(

View File

@ -55,7 +55,7 @@ define i32 @memcmp_const_size_update_deref4(i8* nocapture readonly %d, i8* nocap
ret i32 %call 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-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: [[CALL:%.*]] = tail call i32 @memcmp(i8* nonnull dereferenceable(40) [[D:%.*]], i8* nonnull dereferenceable(16) [[S:%.*]], i64 16)
; CHECK-NEXT: ret i32 [[CALL]] ; 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 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-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: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16)
; CHECK-NEXT: ret i32 [[CALL]] ; 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 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-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: [[CALL:%.*]] = tail call i32 @memcmp(i8* nonnull dereferenceable(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16)
; CHECK-NEXT: ret i32 [[CALL]] ; CHECK-NEXT: ret i32 [[CALL]]

View File

@ -233,7 +233,7 @@ define i8* @test18(i8* %str, i32 %c) {
ret i8* %ret 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-LABEL: @test19(
; CHECK-NEXT: [[RET:%.*]] = call i8* @memchr(i8* dereferenceable(5) [[STR:%.*]], i32 [[C:%.*]], i32 5) ; CHECK-NEXT: [[RET:%.*]] = call i8* @memchr(i8* dereferenceable(5) [[STR:%.*]], i32 [[C:%.*]], i32 5)
; CHECK-NEXT: ret i8* [[RET]] ; CHECK-NEXT: ret i8* [[RET]]

View File

@ -122,4 +122,4 @@ entry:
declare void @llvm.memcpy.p0i8.p2i8.i64(i8* nocapture writeonly, i8 addrspace(2)* nocapture readonly, i64, i1) declare void @llvm.memcpy.p0i8.p2i8.i64(i8* nocapture writeonly, i8 addrspace(2)* nocapture readonly, i64, i1)
declare i32 @foo(i32* %x) declare i32 @foo(i32* %x)
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -323,4 +323,4 @@ entry:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -34,7 +34,7 @@ define i8* @test3(i8* %str, i32 %c) {
ret i8* %ret 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-LABEL: @test4(
; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* [[STR:%.*]], i32 [[C:%.*]], i32 5) ; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* [[STR:%.*]], i32 [[C:%.*]], i32 5)
; CHECK-NEXT: ret i8* [[RET]] ; CHECK-NEXT: ret i8* [[RET]]

View File

@ -375,7 +375,7 @@ define i32 @test16_no_null_opt_2(i1 %C, i32* %P) #0 {
ret i32 %V ret i32 %V
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
define i1 @test17(i32* %X, i1 %C) { define i1 @test17(i32* %X, i1 %C) {
; CHECK-LABEL: @test17( ; CHECK-LABEL: @test17(

View File

@ -45,7 +45,7 @@ define void @store_at_gep_off_no_null_opt(i64 %offset) #0 {
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
;; Simple sinking tests ;; Simple sinking tests

View File

@ -114,7 +114,7 @@ define i8* @test1(i8* %str, i32 %c) {
ret i8* %ret 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-LABEL: @test2(
; CHECK-NEXT: [[RET:%.*]] = call i8* @strchr(i8* [[STR:%.*]], i32 [[C:%.*]]) ; CHECK-NEXT: [[RET:%.*]] = call i8* @strchr(i8* [[STR:%.*]], i32 [[C:%.*]])
; CHECK-NEXT: ret i8* [[RET]] ; CHECK-NEXT: ret i8* [[RET]]

View File

@ -28,4 +28,4 @@ declare i8* @__strcpy_chk(i8*, i8*, i64) nounwind
declare void @func2(i8*) declare void @func2(i8*)
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -219,4 +219,4 @@ define i32 @test2(i8* %str) #0 {
ret i32 %len ret i32 %len
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -90,7 +90,7 @@ define i8* @test3(i8* %str1, i8* %str2, i32 %n) {
ret i8* %temp1 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-LABEL: @test4(
; CHECK-NEXT: [[TEMP1:%.*]] = call i8* @strncat(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]]) ; CHECK-NEXT: [[TEMP1:%.*]] = call i8* @strncat(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]])
; CHECK-NEXT: ret i8* [[TEMP1]] ; CHECK-NEXT: ret i8* [[TEMP1]]

View File

@ -139,7 +139,7 @@ define i32 @test11(i8* %str1, i8* %str2, i32 %n) {
ret i32 %temp1 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-LABEL: @test12(
; CHECK-NEXT: [[TEMP1:%.*]] = call i32 @strncmp(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]]) ; CHECK-NEXT: [[TEMP1:%.*]] = call i32 @strncmp(i8* [[STR1:%.*]], i8* [[STR2:%.*]], i32 [[N:%.*]])
; CHECK-NEXT: ret i32 [[TEMP1]] ; CHECK-NEXT: ret i32 [[TEMP1]]

View File

@ -81,7 +81,7 @@ define i8* @test1(i8* %str, i32 %c) {
ret i8* %ret 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-LABEL: @test2(
; CHECK-NEXT: [[RET:%.*]] = call i8* @strrchr(i8* [[STR:%.*]], i32 [[C:%.*]]) ; CHECK-NEXT: [[RET:%.*]] = call i8* @strrchr(i8* [[STR:%.*]], i32 [[C:%.*]])
; CHECK-NEXT: ret i8* [[RET]] ; CHECK-NEXT: ret i8* [[RET]]

View File

@ -80,7 +80,7 @@ define i8* @test1(i8* %str1, i8* %str2) {
ret i8* %ret 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-LABEL: @test2(
; CHECK-NEXT: [[RET:%.*]] = call i8* @strstr(i8* [[STR1:%.*]], i8* [[STR2:%.*]]) ; CHECK-NEXT: [[RET:%.*]] = call i8* @strstr(i8* [[STR1:%.*]], i8* [[STR2:%.*]])
; CHECK-NEXT: ret i8* [[RET]] ; CHECK-NEXT: ret i8* [[RET]]

View File

@ -219,4 +219,4 @@ define i64 @test_no_simplify4() {
ret i64 %l ret i64 %l
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -1673,4 +1673,4 @@ define i1 @cmp_through_addrspacecast(i32 addrspace(1)* %p1) {
ret i1 %cmp ret i1 %cmp
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -50,4 +50,4 @@ for.body: ; preds = %for.body, %for.body
; CHECK: load ; CHECK: load
; CHECK: store ; CHECK: store
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -69,4 +69,4 @@ bb3:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -206,4 +206,4 @@ else:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -159,4 +159,4 @@ lpad:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View 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 ] ; 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 }

View File

@ -7,7 +7,7 @@ define void @foo() nounwind ssp #0 !dbg !0 {
ret void, !dbg !7 ret void, !dbg !7
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }
!llvm.dbg.cu = !{!2} !llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!10} !llvm.module.flags = !{!10}

View File

@ -122,4 +122,4 @@ F:
ret void ret void
} }
attributes #0 = { "null-pointer-is-valid"="true" } attributes #0 = { null_pointer_is_valid }

View File

@ -386,7 +386,7 @@ define i32 @test2(%struct.S* %0, i32* %1, i8* %2) {
ret i32 %28 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-LABEL: define {{[^@]+}}@test3
; BASIC-SAME: (%struct.S* [[TMP0:%.*]], i32* [[TMP1:%.*]], i8* [[TMP2:%.*]]) #4 ; BASIC-SAME: (%struct.S* [[TMP0:%.*]], i32* [[TMP1:%.*]], i8* [[TMP2:%.*]]) #4
; BASIC-NEXT: [[TMP4:%.*]] = alloca %struct.S*, align 8 ; BASIC-NEXT: [[TMP4:%.*]] = alloca %struct.S*, align 8