[llvm] [Attributor] Support nested conditional branches (PR #168532)
Cullen Rhodes via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 18 05:21:43 PST 2025
https://github.com/c-rhodes created https://github.com/llvm/llvm-project/pull/168532
The attributor can infer the alignment of %p at the call-site in this
example [1]:
```
define void @f(ptr align 8 %p, i1 %c1, i1 %c2) {
entry:
br i1 %c1, label %bb.1, label %exit
bb.1:
call void (...) @llvm.fake.use(ptr %p)
br label %exit
exit:
ret void
}
```
but not when there's an additional conditional branch:
```
define void @f(ptr align 8 %p, i1 %c1, i1 %c2) {
entry:
br i1 %c1, label %bb.1, label %exit
bb.1:
br i1 %c2, label %bb.2, label %exit
bb.2:
call void (...) @llvm.fake.use(ptr %p)
br label %exit
exit:
ret void
}
```
unless `-attributor-annotate-decl-cs` is enabled. This patch extends
`followUsesInMBEC` to handle such recursive branches.
n.b. admittedly I wrote this patch before discovering inferring the
alignment in this example is already possible with
`-attributor-annotate-decl-cs`, I came to realise this once writing the
tests, but this seems like a gap regardless looking at existing FIXMEs,
plus the alignment can now be inferred in this particular example
without the flag.
[1] https://godbolt.org/z/aKoc75so5
>From afd3668016853765397b4905c7a56d43d87b7944 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Mon, 17 Nov 2025 16:36:42 +0000
Subject: [PATCH 1/2] Re-generate llvm/test/Transforms/Attributor/nonnull.ll
---
llvm/test/Transforms/Attributor/nonnull.ll | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index 2ff8a3fa3a688..eb3cfa1526574 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -400,7 +400,7 @@ define internal ptr @f1(ptr %arg) {
; TUNIT-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
; TUNIT-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
; TUNIT: bb1:
-; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4
+; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4, !invariant.load [[META0:![0-9]+]]
; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; TUNIT-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
; TUNIT: bb4:
@@ -422,7 +422,7 @@ define internal ptr @f1(ptr %arg) {
; CGSCC-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
; CGSCC-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
; CGSCC: bb1:
-; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4
+; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4, !invariant.load [[META0:![0-9]+]]
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
; CGSCC: bb4:
@@ -1685,3 +1685,7 @@ attributes #1 = { nounwind willreturn}
; CGSCC: attributes #[[ATTR20]] = { nofree nosync willreturn memory(read) }
; CGSCC: attributes #[[ATTR21]] = { nofree willreturn }
;.
+; TUNIT: [[META0]] = !{}
+;.
+; CGSCC: [[META0]] = !{}
+;.
>From a8459e1b89fe304ee0f001528042ca412972bd92 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Mon, 17 Nov 2025 13:00:53 +0000
Subject: [PATCH 2/2] [Attributor] Support nested conditional branches
The attributor can infer the alignment of %p at the call-site in this
example [1]:
```
define void @f(ptr align 8 %p, i1 %c1, i1 %c2) {
entry:
br i1 %c1, label %bb.1, label %exit
bb.1:
call void (...) @llvm.fake.use(ptr %p)
br label %exit
exit:
ret void
}
```
but not when there's an additional conditional branch:
```
define void @f(ptr align 8 %p, i1 %c1, i1 %c2) {
entry:
br i1 %c1, label %bb.1, label %exit
bb.1:
br i1 %c2, label %bb.2, label %exit
bb.2:
call void (...) @llvm.fake.use(ptr %p)
br label %exit
exit:
ret void
}
```
unless `-attributor-annotate-decl-cs` is enabled. This patch extends
`followUsesInMBEC` to handle such recursive branches.
n.b. admittedly I wrote this patch before discovering inferring the
alignment in this example is already possible with
`-attributor-annotate-decl-cs`, I came to realise this once writing the
tests, but this seems like a gap regardless looking at existing FIXMEs,
plus the alignment can now be inferred in this particular example
without the flag.
[1] https://godbolt.org/z/aKoc75so5
---
.../Transforms/IPO/AttributorAttributes.cpp | 32 +-
.../Attributor/dereferenceable-1.ll | 9 +-
llvm/test/Transforms/Attributor/nonnull.ll | 407 +++++++++---------
.../Attributor/value-simplify-pointer-info.ll | 6 +-
llvm/test/Transforms/Attributor/willreturn.ll | 2 +-
llvm/test/Transforms/FunctionAttrs/nonnull.ll | 3 +-
6 files changed, 230 insertions(+), 229 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index a6ac7610a2c7a..e806a02a1f58f 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -665,7 +665,10 @@ static void followUsesInMBEC(AAType &AA, Attributor &A, StateType &S,
return;
SmallVector<const BranchInst *, 4> BrInsts;
+ SmallPtrSet<const Instruction *, 16> Visited;
auto Pred = [&](const Instruction *I) {
+ if (!Visited.insert(I).second)
+ return false;
if (const BranchInst *Br = dyn_cast<BranchInst>(I))
if (Br->isConditional())
BrInsts.push_back(Br);
@@ -684,28 +687,10 @@ static void followUsesInMBEC(AAType &AA, Attributor &A, StateType &S,
// ParentS_m = ChildS_{m, 1} /\ ChildS_{m, 2} /\ ... /\ ChildS_{m, n_m}
//
// Known State |= ParentS_1 \/ ParentS_2 \/... \/ ParentS_m
- //
- // FIXME: Currently, recursive branches are not handled. For example, we
- // can't deduce that ptr must be dereferenced in below function.
- //
- // void f(int a, int c, int *ptr) {
- // if(a)
- // if (b) {
- // *ptr = 0;
- // } else {
- // *ptr = 1;
- // }
- // else {
- // if (b) {
- // *ptr = 0;
- // } else {
- // *ptr = 1;
- // }
- // }
- // }
Explorer->checkForAllContext(&CtxI, Pred);
- for (const BranchInst *Br : BrInsts) {
+ while (!BrInsts.empty()) {
+ const BranchInst *Br = BrInsts.pop_back_val();
StateType ParentState;
// The known state of the parent state is a conjunction of children's
@@ -714,15 +699,18 @@ static void followUsesInMBEC(AAType &AA, Attributor &A, StateType &S,
for (const BasicBlock *BB : Br->successors()) {
StateType ChildState;
-
size_t BeforeSize = Uses.size();
- followUsesInContext(AA, A, *Explorer, &BB->front(), Uses, ChildState);
+ const Instruction *I = &BB->front();
+ followUsesInContext(AA, A, *Explorer, I, Uses, ChildState);
// Erase uses which only appear in the child.
for (auto It = Uses.begin() + BeforeSize; It != Uses.end();)
It = Uses.erase(It);
ParentState &= ChildState;
+
+ // Check for recursive conditional branches.
+ Explorer->checkForAllContext(I, Pred);
}
// Use only known state.
diff --git a/llvm/test/Transforms/Attributor/dereferenceable-1.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll
index 5bff2a2e6b208..246a8c42ba912 100644
--- a/llvm/test/Transforms/Attributor/dereferenceable-1.ll
+++ b/llvm/test/Transforms/Attributor/dereferenceable-1.ll
@@ -555,12 +555,10 @@ cont2:
; *ptr = 4;
; }
; }
-;
-; FIXME: %ptr should be dereferenceable(4)
define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, ptr %ptr) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
; CHECK-LABEL: define {{[^@]+}}@rec-branch-1
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree writeonly captures(none) [[PTR:%.*]]) #[[ATTR3]] {
+; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
@@ -630,11 +628,10 @@ if.end8: ; preds = %if.then5, %if.else6
; rec-branch-2(1, 1, 1, ptr);
; }
; }
-; FIXME: %ptr should be dereferenceable(4)
define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, ptr %ptr) {
; CHECK: Function Attrs: nofree nosync nounwind memory(argmem: write)
; CHECK-LABEL: define {{[^@]+}}@rec-branch-2
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree writeonly captures(none) [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
@@ -654,7 +651,7 @@ define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, ptr %ptr) {
; CHECK-NEXT: store i32 3, ptr [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.else6:
-; CHECK-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, ptr nofree writeonly captures(none) [[PTR]]) #[[ATTR8:[0-9]+]]
+; CHECK-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR]]) #[[ATTR8:[0-9]+]]
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.end8:
; CHECK-NEXT: ret void
diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index eb3cfa1526574..57a6d09af64fa 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -32,16 +32,27 @@ define ptr @test2(ptr nonnull %p) {
}
define ptr @test2A(i1 %c, ptr %ret) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
-; CHECK-LABEL: define {{[^@]+}}@test2A
-; CHECK-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2:[0-9]+]] {
-; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
-; CHECK: A:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16:[0-9]+]] [ "nonnull"(ptr [[RET]]) ]
-; CHECK-NEXT: ret ptr [[RET]]
-; CHECK: B:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "nonnull"(ptr [[RET]]) ]
-; CHECK-NEXT: ret ptr [[RET]]
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; TUNIT-LABEL: define {{[^@]+}}@test2A
+; TUNIT-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2:[0-9]+]] {
+; TUNIT-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
+; TUNIT: A:
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nonnull"(ptr [[RET]]) ]
+; TUNIT-NEXT: ret ptr [[RET]]
+; TUNIT: B:
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15]] [ "nonnull"(ptr [[RET]]) ]
+; TUNIT-NEXT: ret ptr [[RET]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; CGSCC-LABEL: define {{[^@]+}}@test2A
+; CGSCC-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2:[0-9]+]] {
+; CGSCC-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
+; CGSCC: A:
+; CGSCC-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16:[0-9]+]] [ "nonnull"(ptr [[RET]]) ]
+; CGSCC-NEXT: ret ptr [[RET]]
+; CGSCC: B:
+; CGSCC-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "nonnull"(ptr [[RET]]) ]
+; CGSCC-NEXT: ret ptr [[RET]]
;
br i1 %c, label %A, label %B
A:
@@ -53,16 +64,27 @@ B:
}
define ptr @test2B(i1 %c, ptr %ret) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
-; CHECK-LABEL: define {{[^@]+}}@test2B
-; CHECK-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
-; CHECK: A:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
-; CHECK-NEXT: ret ptr [[RET]]
-; CHECK: B:
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
-; CHECK-NEXT: ret ptr [[RET]]
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; TUNIT-LABEL: define {{[^@]+}}@test2B
+; TUNIT-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
+; TUNIT: A:
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
+; TUNIT-NEXT: ret ptr [[RET]]
+; TUNIT: B:
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
+; TUNIT-NEXT: ret ptr [[RET]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; CGSCC-LABEL: define {{[^@]+}}@test2B
+; CGSCC-SAME: (i1 noundef [[C:%.*]], ptr nofree nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[RET:%.*]]) #[[ATTR2]] {
+; CGSCC-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
+; CGSCC: A:
+; CGSCC-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
+; CGSCC-NEXT: ret ptr [[RET]]
+; CGSCC: B:
+; CGSCC-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "dereferenceable"(ptr [[RET]], i32 4) ]
+; CGSCC-NEXT: ret ptr [[RET]]
;
br i1 %c, label %A, label %B
A:
@@ -273,13 +295,21 @@ define ptr @test9(ptr %a, i64 %n) {
; ATTRIBUTOR_OPM: define ptr @test10
; ATTRIBUTOR_NPM: define nonnull ptr @test10
define ptr @test10(ptr %a, i64 %n) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
-; CHECK-LABEL: define {{[^@]+}}@test10
-; CHECK-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[A:%.*]], i64 [[N:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CMP]]) #[[ATTR16]]
-; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
-; CHECK-NEXT: ret ptr [[B]]
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; TUNIT-LABEL: define {{[^@]+}}@test10
+; TUNIT-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[A:%.*]], i64 [[N:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[CMP]]) #[[ATTR15]]
+; TUNIT-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
+; TUNIT-NEXT: ret ptr [[B]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write)
+; CGSCC-LABEL: define {{[^@]+}}@test10
+; CGSCC-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[A:%.*]], i64 [[N:%.*]]) #[[ATTR2]] {
+; CGSCC-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
+; CGSCC-NEXT: call void @llvm.assume(i1 noundef [[CMP]]) #[[ATTR16]]
+; CGSCC-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
+; CGSCC-NEXT: ret ptr [[B]]
;
%cmp = icmp ne i64 %n, 0
call void @llvm.assume(i1 %cmp)
@@ -392,50 +422,22 @@ declare nonnull ptr @nonnull()
define internal ptr @f1(ptr %arg) {
-; FIXME: missing nonnull It should be nonnull @f1(ptr nonnull readonly %arg)
-; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: read)
-; TUNIT-LABEL: define {{[^@]+}}@f1
-; TUNIT-SAME: (ptr nofree readonly [[ARG:%.*]]) #[[ATTR6:[0-9]+]] {
-; TUNIT-NEXT: bb:
-; TUNIT-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
-; TUNIT-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
-; TUNIT: bb1:
-; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4, !invariant.load [[META0:![0-9]+]]
-; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
-; TUNIT-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
-; TUNIT: bb4:
-; TUNIT-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1
-; TUNIT-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr nofree nonnull readonly [[TMP5]]) #[[ATTR17:[0-9]+]]
-; TUNIT-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1
-; TUNIT-NEXT: br label [[BB9]]
-; TUNIT: bb6:
-; TUNIT-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr nofree nonnull readonly align 4 dereferenceable(4) [[ARG]]) #[[ATTR17]]
-; TUNIT-NEXT: ret ptr [[TMP7]]
-; TUNIT: bb9:
-; TUNIT-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ]
-; TUNIT-NEXT: ret ptr [[TMP10]]
-;
-; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: read)
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@f1
-; CGSCC-SAME: (ptr nofree readonly [[ARG:%.*]]) #[[ATTR5:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree nonnull readonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR5:[0-9]+]] {
; CGSCC-NEXT: bb:
-; CGSCC-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
-; CGSCC-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
+; CGSCC-NEXT: br label [[BB1:%.*]]
; CGSCC: bb1:
; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4, !invariant.load [[META0:![0-9]+]]
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
; CGSCC: bb4:
-; CGSCC-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1
-; CGSCC-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr nofree nonnull readonly [[TMP5]]) #[[ATTR17:[0-9]+]]
-; CGSCC-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1
-; CGSCC-NEXT: br label [[BB9]]
+; CGSCC-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr undef, i64 -1
+; CGSCC-NEXT: br label [[BB9:%.*]]
; CGSCC: bb6:
-; CGSCC-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr nofree nonnull readonly align 4 dereferenceable(4) [[ARG]]) #[[ATTR17]]
-; CGSCC-NEXT: ret ptr [[TMP7]]
+; CGSCC-NEXT: ret ptr undef
; CGSCC: bb9:
-; CGSCC-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ]
-; CGSCC-NEXT: ret ptr [[TMP10]]
+; CGSCC-NEXT: ret ptr undef
;
bb:
@@ -463,19 +465,11 @@ bb9: ; preds = %bb4, %bb
}
define internal ptr @f2(ptr %arg) {
-; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: read)
-; TUNIT-LABEL: define {{[^@]+}}@f2
-; TUNIT-SAME: (ptr nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]]) #[[ATTR6]] {
-; TUNIT-NEXT: bb:
-; TUNIT-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR17]]
-; TUNIT-NEXT: ret ptr [[TMP]]
-;
-; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: read)
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@f2
-; CGSCC-SAME: (ptr nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]]) #[[ATTR5]] {
+; CGSCC-SAME: (ptr noalias nofree nonnull readnone align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR6:[0-9]+]] {
; CGSCC-NEXT: bb:
-; CGSCC-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR17]]
-; CGSCC-NEXT: ret ptr [[TMP]]
+; CGSCC-NEXT: ret ptr undef
;
bb:
%tmp = tail call ptr @f1(ptr %arg)
@@ -484,19 +478,17 @@ bb:
define dso_local noalias ptr @f3(ptr %arg) {
; FIXME: missing nonnull. It should be nonnull @f3(ptr nonnull readonly %arg)
-; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: read)
+; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@f3
-; TUNIT-SAME: (ptr nofree readonly [[ARG:%.*]]) #[[ATTR6]] {
+; TUNIT-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: bb:
-; TUNIT-NEXT: [[TMP:%.*]] = call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR17]]
-; TUNIT-NEXT: ret ptr [[TMP]]
+; TUNIT-NEXT: ret ptr undef
;
-; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: read)
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@f3
-; CGSCC-SAME: (ptr nofree readonly [[ARG:%.*]]) #[[ATTR5]] {
+; CGSCC-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: bb:
-; CGSCC-NEXT: [[TMP:%.*]] = call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR17]]
-; CGSCC-NEXT: ret ptr [[TMP]]
+; CGSCC-NEXT: ret ptr undef
;
bb:
; FIXME: missing nonnull. It should be @f1(ptr nonnull readonly %arg)
@@ -529,26 +521,26 @@ declare void @fun3(ptr, ptr, ptr) #1
define void @f16(ptr %a, ptr %b, i8 %c) {
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@f16
-; TUNIT-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR8:[0-9]+]] {
+; TUNIT-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] {
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; TUNIT: if.then:
-; TUNIT-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR7:[0-9]+]]
+; TUNIT-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR6:[0-9]+]]
; TUNIT-NEXT: ret void
; TUNIT: if.else:
-; TUNIT-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR6]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@f16
-; CGSCC-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] {
+; CGSCC-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR8:[0-9]+]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CGSCC: if.then:
-; CGSCC-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR6:[0-9]+]]
+; CGSCC-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR7:[0-9]+]]
; CGSCC-NEXT: ret void
; CGSCC: if.else:
-; CGSCC-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR7]]
; CGSCC-NEXT: ret void
;
%cmp = icmp eq i8 %c, 0
@@ -571,32 +563,32 @@ define void @f17(ptr %a, i8 %c) {
;
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@f17
-; TUNIT-SAME: (ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; TUNIT: if.then:
-; TUNIT-NEXT: tail call void @fun0() #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun0() #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT:%.*]]
; TUNIT: if.else:
-; TUNIT-NEXT: tail call void @fun0() #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun0() #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT]]
; TUNIT: cont:
-; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR6]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@f17
-; CGSCC-SAME: (ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CGSCC: if.then:
-; CGSCC-NEXT: tail call void @fun0() #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun0() #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT:%.*]]
; CGSCC: if.else:
-; CGSCC-NEXT: tail call void @fun0() #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun0() #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT]]
; CGSCC: cont:
-; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR7]]
; CGSCC-NEXT: ret void
;
%cmp = icmp eq i8 %c, 0
@@ -625,50 +617,50 @@ cont:
define void @f18(ptr %a, ptr %b, i8 %c) {
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@f18
-; TUNIT-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0
; TUNIT-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; TUNIT: if.then:
-; TUNIT-NEXT: tail call void @fun0() #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun0() #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT:%.*]]
; TUNIT: if.else:
-; TUNIT-NEXT: tail call void @fun0() #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun0() #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT]]
; TUNIT: cont:
; TUNIT-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1
; TUNIT-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
; TUNIT: cont.then:
-; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT2:%.*]]
; TUNIT: cont.else:
-; TUNIT-NEXT: tail call void @fun0() #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun0() #[[ATTR6]]
; TUNIT-NEXT: br label [[CONT2]]
; TUNIT: cont2:
-; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR6]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@f18
-; CGSCC-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0
; CGSCC-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CGSCC: if.then:
-; CGSCC-NEXT: tail call void @fun0() #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun0() #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT:%.*]]
; CGSCC: if.else:
-; CGSCC-NEXT: tail call void @fun0() #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun0() #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT]]
; CGSCC: cont:
; CGSCC-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1
; CGSCC-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
; CGSCC: cont.then:
-; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT2:%.*]]
; CGSCC: cont.else:
-; CGSCC-NEXT: tail call void @fun0() #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun0() #[[ATTR7]]
; CGSCC-NEXT: br label [[CONT2]]
; CGSCC: cont2:
-; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR7]]
; CGSCC-NEXT: ret void
;
%cmp1 = icmp eq i8 %c, 0
@@ -857,11 +849,17 @@ define i8 @parent6(ptr %a, ptr %b) {
; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent.
define i8 @parent7(ptr %a) {
-; CHECK-LABEL: define {{[^@]+}}@parent7
-; CHECK-SAME: (ptr nonnull [[A:%.*]]) {
-; CHECK-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr nonnull readonly [[A]]) #[[ATTR18:[0-9]+]]
-; CHECK-NEXT: call void @use1nonnull(ptr nonnull [[A]])
-; CHECK-NEXT: ret i8 [[RET]]
+; TUNIT-LABEL: define {{[^@]+}}@parent7
+; TUNIT-SAME: (ptr nonnull [[A:%.*]]) {
+; TUNIT-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr nonnull readonly [[A]]) #[[ATTR16:[0-9]+]]
+; TUNIT-NEXT: call void @use1nonnull(ptr nonnull [[A]])
+; TUNIT-NEXT: ret i8 [[RET]]
+;
+; CGSCC-LABEL: define {{[^@]+}}@parent7
+; CGSCC-SAME: (ptr nonnull [[A:%.*]]) {
+; CGSCC-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr nonnull readonly [[A]]) #[[ATTR17:[0-9]+]]
+; CGSCC-NEXT: call void @use1nonnull(ptr nonnull [[A]])
+; CGSCC-NEXT: ret i8 [[RET]]
;
@@ -931,13 +929,13 @@ define ptr @gep1_no_null_opt(ptr %p) #0 {
; Should't be able to derive nonnull based on gep.
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@gep1_no_null_opt
-; TUNIT-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR10:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR9:[0-9]+]] {
; TUNIT-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
; TUNIT-NEXT: ret ptr [[Q]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@gep1_no_null_opt
-; CGSCC-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR9:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR10:[0-9]+]] {
; CGSCC-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
; CGSCC-NEXT: ret ptr [[Q]]
;
@@ -983,8 +981,8 @@ define ptr @g1() {
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@g1
-; CGSCC-SAME: () #[[ATTR10:[0-9]+]] {
-; CGSCC-NEXT: [[C:%.*]] = call noundef nonnull align 4 ptr @g2() #[[ATTR19:[0-9]+]]
+; CGSCC-SAME: () #[[ATTR6]] {
+; CGSCC-NEXT: [[C:%.*]] = call noundef nonnull align 4 ptr @g2() #[[ATTR18:[0-9]+]]
; CGSCC-NEXT: ret ptr [[C]]
;
%c = call ptr @g2()
@@ -1045,21 +1043,32 @@ define internal void @control(ptr dereferenceable(4) %a) {
}
; Avoid nonnull as we do not touch naked functions
define internal void @naked(ptr dereferenceable(4) %a) naked {
-; CHECK: Function Attrs: naked
-; CHECK-LABEL: define {{[^@]+}}@naked
-; CHECK-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] {
-; CHECK-NEXT: ret void
+; TUNIT: Function Attrs: naked
+; TUNIT-LABEL: define {{[^@]+}}@naked
+; TUNIT-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR10:[0-9]+]] {
+; TUNIT-NEXT: ret void
+;
+; CGSCC: Function Attrs: naked
+; CGSCC-LABEL: define {{[^@]+}}@naked
+; CGSCC-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] {
+; CGSCC-NEXT: ret void
;
ret void
}
; Avoid nonnull as we do not touch optnone
define internal void @optnone(ptr dereferenceable(4) %a) optnone noinline {
;
-; CHECK: Function Attrs: noinline optnone
-; CHECK-LABEL: define {{[^@]+}}@optnone
-; CHECK-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR12:[0-9]+]] {
-; CHECK-NEXT: call void @use_i32_ptr(ptr nofree noundef nonnull captures(none) [[A]])
-; CHECK-NEXT: ret void
+; TUNIT: Function Attrs: noinline optnone
+; TUNIT-LABEL: define {{[^@]+}}@optnone
+; TUNIT-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] {
+; TUNIT-NEXT: call void @use_i32_ptr(ptr nofree noundef nonnull captures(none) [[A]])
+; TUNIT-NEXT: ret void
+;
+; CGSCC: Function Attrs: noinline optnone
+; CGSCC-LABEL: define {{[^@]+}}@optnone
+; CGSCC-SAME: (ptr noundef nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR12:[0-9]+]] {
+; CGSCC-NEXT: call void @use_i32_ptr(ptr nofree noundef nonnull captures(none) [[A]])
+; CGSCC-NEXT: ret void
;
call void @use_i32_ptr(ptr %a)
ret void
@@ -1098,32 +1107,32 @@ define i32 @nonnull_exec_ctx_1(ptr %a, i32 %b) {
;
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1
-; TUNIT-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: en:
; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; TUNIT-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
; TUNIT: ex:
-; TUNIT-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR6]]
; TUNIT-NEXT: ret i32 [[TMP5]]
; TUNIT: hd:
; TUNIT-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
-; TUNIT-NEXT: tail call void @h(ptr [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @h(ptr [[A]]) #[[ATTR6]]
; TUNIT-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
; TUNIT-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; TUNIT-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1
-; CGSCC-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: en:
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
; CGSCC: ex:
-; CGSCC-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR7]]
; CGSCC-NEXT: ret i32 [[TMP5]]
; CGSCC: hd:
; CGSCC-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
-; CGSCC-NEXT: tail call void @h(ptr [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @h(ptr [[A]]) #[[ATTR7]]
; CGSCC-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
; CGSCC-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; CGSCC-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
@@ -1148,16 +1157,16 @@ define i32 @nonnull_exec_ctx_1b(ptr %a, i32 %b) {
;
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b
-; TUNIT-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: en:
; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; TUNIT-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
; TUNIT: ex:
-; TUNIT-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR6]]
; TUNIT-NEXT: ret i32 [[TMP5]]
; TUNIT: hd:
; TUNIT-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
-; TUNIT-NEXT: tail call void @h(ptr [[A]]) #[[ATTR7]]
+; TUNIT-NEXT: tail call void @h(ptr [[A]]) #[[ATTR6]]
; TUNIT-NEXT: br label [[HD2]]
; TUNIT: hd2:
; TUNIT-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
@@ -1166,16 +1175,16 @@ define i32 @nonnull_exec_ctx_1b(ptr %a, i32 %b) {
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b
-; CGSCC-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: en:
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
; CGSCC: ex:
-; CGSCC-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) #[[ATTR7]]
; CGSCC-NEXT: ret i32 [[TMP5]]
; CGSCC: hd:
; CGSCC-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
-; CGSCC-NEXT: tail call void @h(ptr [[A]]) #[[ATTR6]]
+; CGSCC-NEXT: tail call void @h(ptr [[A]]) #[[ATTR7]]
; CGSCC-NEXT: br label [[HD2]]
; CGSCC: hd2:
; CGSCC-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
@@ -1205,7 +1214,7 @@ define i32 @nonnull_exec_ctx_2(ptr %a, i32 %b) willreturn nounwind {
;
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2
-; TUNIT-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: en:
; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; TUNIT-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
@@ -1221,7 +1230,7 @@ define i32 @nonnull_exec_ctx_2(ptr %a, i32 %b) willreturn nounwind {
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2
-; CGSCC-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: en:
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
@@ -1255,7 +1264,7 @@ define i32 @nonnull_exec_ctx_2b(ptr %a, i32 %b) willreturn nounwind {
;
; TUNIT: Function Attrs: mustprogress nounwind willreturn
; TUNIT-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b
-; TUNIT-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
+; TUNIT-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
; TUNIT-NEXT: en:
; TUNIT-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; TUNIT-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
@@ -1273,7 +1282,7 @@ define i32 @nonnull_exec_ctx_2b(ptr %a, i32 %b) willreturn nounwind {
;
; CGSCC: Function Attrs: mustprogress nounwind willreturn
; CGSCC-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b
-; CGSCC-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
+; CGSCC-SAME: (ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR8]] {
; CGSCC-NEXT: en:
; CGSCC-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
; CGSCC-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
@@ -1392,8 +1401,8 @@ declare ptr @strrchr(ptr %0, i32 %1) nofree nounwind readonly willreturn
define ptr @mybasename(ptr nofree readonly %str) {
; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@mybasename
-; TUNIT-SAME: (ptr nofree readonly [[STR:%.*]]) #[[ATTR14:[0-9]+]] {
-; TUNIT-NEXT: [[CALL:%.*]] = call ptr @strrchr(ptr nofree readonly [[STR]], i32 noundef 47) #[[ATTR19:[0-9]+]]
+; TUNIT-SAME: (ptr nofree readonly [[STR:%.*]]) #[[ATTR13:[0-9]+]] {
+; TUNIT-NEXT: [[CALL:%.*]] = call ptr @strrchr(ptr nofree readonly [[STR]], i32 noundef 47) #[[ATTR17:[0-9]+]]
; TUNIT-NEXT: [[TOBOOL:%.*]] = icmp ne ptr [[CALL]], null
; TUNIT-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 1
; TUNIT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], ptr [[ADD_PTR]], ptr [[STR]]
@@ -1402,7 +1411,7 @@ define ptr @mybasename(ptr nofree readonly %str) {
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@mybasename
; CGSCC-SAME: (ptr nofree readonly [[STR:%.*]]) #[[ATTR14:[0-9]+]] {
-; CGSCC-NEXT: [[CALL:%.*]] = call ptr @strrchr(ptr nofree readonly [[STR]], i32 noundef 47) #[[ATTR20:[0-9]+]]
+; CGSCC-NEXT: [[CALL:%.*]] = call ptr @strrchr(ptr nofree readonly [[STR]], i32 noundef 47) #[[ATTR19:[0-9]+]]
; CGSCC-NEXT: [[TOBOOL:%.*]] = icmp ne ptr [[CALL]], null
; CGSCC-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 1
; CGSCC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], ptr [[ADD_PTR]], ptr [[STR]]
@@ -1425,7 +1434,7 @@ define void @nonnull_assume_pos(ptr %arg) {
;
; TUNIT-LABEL: define {{[^@]+}}@nonnull_assume_pos
; TUNIT-SAME: (ptr nofree nonnull readnone captures(none) [[ARG:%.*]]) {
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16]] [ "nonnull"(ptr [[ARG]]) ]
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15]] [ "nonnull"(ptr [[ARG]]) ]
; TUNIT-NEXT: call void @use_i8_ptr(ptr noalias nofree nonnull readnone captures(none) [[ARG]]) #[[ATTR5]]
; TUNIT-NEXT: [[TMP1:%.*]] = call ptr @unknown()
; TUNIT-NEXT: ret void
@@ -1554,14 +1563,14 @@ define void @phi_caller(ptr %p) {
; TUNIT: Function Attrs: nounwind
; TUNIT-LABEL: define {{[^@]+}}@phi_caller
; TUNIT-SAME: (ptr nofree [[P:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT: [[C:%.*]] = call nonnull ptr @phi(ptr noalias nofree readnone [[P]]) #[[ATTR20:[0-9]+]]
+; TUNIT-NEXT: [[C:%.*]] = call nonnull ptr @phi(ptr noalias nofree readnone [[P]]) #[[ATTR18:[0-9]+]]
; TUNIT-NEXT: call void @use_i8_ptr(ptr noalias nofree nonnull readnone captures(none) [[C]]) #[[ATTR5]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: nounwind
; CGSCC-LABEL: define {{[^@]+}}@phi_caller
; CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT: [[C:%.*]] = call nonnull ptr @phi(ptr noalias nofree readnone [[P]]) #[[ATTR21:[0-9]+]]
+; CGSCC-NEXT: [[C:%.*]] = call nonnull ptr @phi(ptr noalias nofree readnone [[P]]) #[[ATTR20:[0-9]+]]
; CGSCC-NEXT: call void @use_i8_ptr(ptr noalias nofree nonnull readnone captures(none) [[C]]) #[[ATTR4]]
; CGSCC-NEXT: ret void
;
@@ -1594,14 +1603,14 @@ define void @multi_ret_caller(ptr %p) {
; TUNIT: Function Attrs: nounwind
; TUNIT-LABEL: define {{[^@]+}}@multi_ret_caller
; TUNIT-SAME: (ptr nofree [[P:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT: [[C:%.*]] = call nonnull ptr @multi_ret(ptr noalias nofree readnone [[P]]) #[[ATTR20]]
+; TUNIT-NEXT: [[C:%.*]] = call nonnull ptr @multi_ret(ptr noalias nofree readnone [[P]]) #[[ATTR18]]
; TUNIT-NEXT: call void @use_i8_ptr(ptr noalias nofree nonnull readnone captures(none) [[C]]) #[[ATTR5]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: nounwind
; CGSCC-LABEL: define {{[^@]+}}@multi_ret_caller
; CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT: [[C:%.*]] = call nonnull ptr @multi_ret(ptr noalias nofree readnone [[P]]) #[[ATTR21]]
+; CGSCC-NEXT: [[C:%.*]] = call nonnull ptr @multi_ret(ptr noalias nofree readnone [[P]]) #[[ATTR20]]
; CGSCC-NEXT: call void @use_i8_ptr(ptr noalias nofree nonnull readnone captures(none) [[C]]) #[[ATTR4]]
; CGSCC-NEXT: ret void
;
@@ -1613,18 +1622,31 @@ define void @multi_ret_caller(ptr %p) {
; From https://github.com/llvm/llvm-project/pull/85810
@G = internal global i64 1, align 8
define dso_local ptr @update_global_in_alive_bb() {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
-; CHECK-LABEL: define {{[^@]+}}@update_global_in_alive_bb
-; CHECK-SAME: () #[[ATTR15:[0-9]+]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @G, align 8
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[TMP0]], 0
-; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
-; CHECK: if.then:
-; CHECK-NEXT: store i64 0, ptr @G, align 8
-; CHECK-NEXT: ret ptr inttoptr (i64 5 to ptr)
-; CHECK: if.else:
-; CHECK-NEXT: ret ptr null
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; TUNIT-LABEL: define {{[^@]+}}@update_global_in_alive_bb
+; TUNIT-SAME: () #[[ATTR14:[0-9]+]] {
+; TUNIT-NEXT: entry:
+; TUNIT-NEXT: [[TMP0:%.*]] = load i64, ptr @G, align 8
+; TUNIT-NEXT: [[CMP:%.*]] = icmp ne i64 [[TMP0]], 0
+; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; TUNIT: if.then:
+; TUNIT-NEXT: store i64 0, ptr @G, align 8
+; TUNIT-NEXT: ret ptr inttoptr (i64 5 to ptr)
+; TUNIT: if.else:
+; TUNIT-NEXT: ret ptr null
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; CGSCC-LABEL: define {{[^@]+}}@update_global_in_alive_bb
+; CGSCC-SAME: () #[[ATTR15:[0-9]+]] {
+; CGSCC-NEXT: entry:
+; CGSCC-NEXT: [[TMP0:%.*]] = load i64, ptr @G, align 8
+; CGSCC-NEXT: [[CMP:%.*]] = icmp ne i64 [[TMP0]], 0
+; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CGSCC: if.then:
+; CGSCC-NEXT: store i64 0, ptr @G, align 8
+; CGSCC-NEXT: ret ptr inttoptr (i64 5 to ptr)
+; CGSCC: if.else:
+; CGSCC-NEXT: ret ptr null
;
entry:
%0 = load i64, ptr @G, align 8
@@ -1640,52 +1662,47 @@ if.else:
attributes #0 = { null_pointer_is_valid }
attributes #1 = { nounwind willreturn}
;.
-; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
-; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write) }
-; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR4]] = { noreturn }
-; TUNIT: attributes #[[ATTR5]] = { nounwind }
-; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind memory(argmem: read) }
-; TUNIT: attributes #[[ATTR7]] = { nounwind willreturn }
-; TUNIT: attributes #[[ATTR8]] = { mustprogress nounwind willreturn }
-; TUNIT: attributes #[[ATTR9:[0-9]+]] = { nounwind willreturn memory(read) }
-; TUNIT: attributes #[[ATTR10]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
-; TUNIT: attributes #[[ATTR11]] = { naked }
-; TUNIT: attributes #[[ATTR12]] = { noinline optnone }
-; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nofree nounwind willreturn memory(read) }
-; TUNIT: attributes #[[ATTR14]] = { mustprogress nofree nosync nounwind willreturn memory(read) }
-; TUNIT: attributes #[[ATTR15]] = { mustprogress nofree norecurse nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR16]] = { nofree willreturn memory(write) }
-; TUNIT: attributes #[[ATTR17]] = { nofree nosync nounwind memory(read) }
-; TUNIT: attributes #[[ATTR18]] = { nosync willreturn memory(read) }
-; TUNIT: attributes #[[ATTR19]] = { nofree nosync willreturn memory(read) }
-; TUNIT: attributes #[[ATTR20]] = { nofree nosync nounwind willreturn memory(none) }
-;.
; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write) }
; CGSCC: attributes #[[ATTR3]] = { noreturn }
; CGSCC: attributes #[[ATTR4]] = { nounwind }
-; CGSCC: attributes #[[ATTR5]] = { nofree nosync nounwind memory(argmem: read) }
-; CGSCC: attributes #[[ATTR6]] = { nounwind willreturn }
-; CGSCC: attributes #[[ATTR7]] = { mustprogress nounwind willreturn }
-; CGSCC: attributes #[[ATTR8:[0-9]+]] = { nounwind willreturn memory(read) }
-; CGSCC: attributes #[[ATTR9]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
-; CGSCC: attributes #[[ATTR10]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: read) }
+; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR7]] = { nounwind willreturn }
+; CGSCC: attributes #[[ATTR8]] = { mustprogress nounwind willreturn }
+; CGSCC: attributes #[[ATTR9:[0-9]+]] = { nounwind willreturn memory(read) }
+; CGSCC: attributes #[[ATTR10]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
; CGSCC: attributes #[[ATTR11]] = { naked }
; CGSCC: attributes #[[ATTR12]] = { noinline optnone }
; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nofree nounwind willreturn memory(read) }
; CGSCC: attributes #[[ATTR14]] = { mustprogress nofree nosync nounwind willreturn memory(read) }
; CGSCC: attributes #[[ATTR15]] = { mustprogress nofree norecurse nosync nounwind willreturn }
; CGSCC: attributes #[[ATTR16]] = { nofree willreturn memory(write) }
-; CGSCC: attributes #[[ATTR17]] = { nofree nosync nounwind memory(read) }
-; CGSCC: attributes #[[ATTR18]] = { nosync willreturn memory(read) }
-; CGSCC: attributes #[[ATTR19]] = { nofree nosync willreturn }
-; CGSCC: attributes #[[ATTR20]] = { nofree nosync willreturn memory(read) }
-; CGSCC: attributes #[[ATTR21]] = { nofree willreturn }
+; CGSCC: attributes #[[ATTR17]] = { nosync willreturn memory(read) }
+; CGSCC: attributes #[[ATTR18]] = { nofree nosync willreturn }
+; CGSCC: attributes #[[ATTR19]] = { nofree nosync willreturn memory(read) }
+; CGSCC: attributes #[[ATTR20]] = { nofree willreturn }
;.
-; TUNIT: [[META0]] = !{}
+; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
+; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(inaccessiblemem: write) }
+; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR4]] = { noreturn }
+; TUNIT: attributes #[[ATTR5]] = { nounwind }
+; TUNIT: attributes #[[ATTR6]] = { nounwind willreturn }
+; TUNIT: attributes #[[ATTR7]] = { mustprogress nounwind willreturn }
+; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nounwind willreturn memory(read) }
+; TUNIT: attributes #[[ATTR9]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
+; TUNIT: attributes #[[ATTR10]] = { naked }
+; TUNIT: attributes #[[ATTR11]] = { noinline optnone }
+; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nofree nounwind willreturn memory(read) }
+; TUNIT: attributes #[[ATTR13]] = { mustprogress nofree nosync nounwind willreturn memory(read) }
+; TUNIT: attributes #[[ATTR14]] = { mustprogress nofree norecurse nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
+; TUNIT: attributes #[[ATTR16]] = { nosync willreturn memory(read) }
+; TUNIT: attributes #[[ATTR17]] = { nofree nosync willreturn memory(read) }
+; TUNIT: attributes #[[ATTR18]] = { nofree nosync nounwind willreturn memory(none) }
;.
; CGSCC: [[META0]] = !{}
;.
diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index 3e07fe42261e9..2235f194af8ea 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -1267,7 +1267,7 @@ entry:
define void @noalias_arg_simplifiable_2(ptr %Bytes) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; TUNIT-LABEL: define void @noalias_arg_simplifiable_2(
-; TUNIT-SAME: ptr nofree captures(none) [[BYTES:%.*]]) #[[ATTR3]] {
+; TUNIT-SAME: ptr nofree nonnull captures(none) dereferenceable(24) [[BYTES:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[ENTRY:.*]]:
; TUNIT-NEXT: br label %[[FOR_COND:.*]]
; TUNIT: [[FOR_COND]]:
@@ -1344,7 +1344,7 @@ define void @noalias_arg_simplifiable_2(ptr %Bytes) {
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
; CGSCC-LABEL: define void @noalias_arg_simplifiable_2(
-; CGSCC-SAME: ptr nofree captures(none) [[BYTES:%.*]]) #[[ATTR3]] {
+; CGSCC-SAME: ptr nofree nonnull align 4 captures(none) dereferenceable(1024) [[BYTES:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[ENTRY:.*]]:
; CGSCC-NEXT: br label %[[FOR_COND:.*]]
; CGSCC: [[FOR_COND]]:
@@ -1399,7 +1399,7 @@ define void @noalias_arg_simplifiable_2(ptr %Bytes) {
; CGSCC-NEXT: [[ARRAYIDX24:%.*]] = getelementptr inbounds i8, ptr [[BYTES]], i64 1023
; CGSCC-NEXT: store i8 0, ptr [[ARRAYIDX24]], align 1, !tbaa [[CHAR_TBAA15]]
; CGSCC-NEXT: [[ARRAYIDX25:%.*]] = getelementptr inbounds i8, ptr [[BYTES]], i64 500
-; CGSCC-NEXT: call void @write_arg(ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARRAYIDX25]], i32 noundef 0) #[[ATTR21]]
+; CGSCC-NEXT: call void @write_arg(ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(524) [[ARRAYIDX25]], i32 noundef 0) #[[ATTR21]]
; CGSCC-NEXT: br label %[[FOR_COND27:.*]]
; CGSCC: [[FOR_COND27]]:
; CGSCC-NEXT: [[INDVARS_IV12:%.*]] = phi i64 [ [[INDVARS_IV_NEXT13:%.*]], %[[FOR_INC35:.*]] ], [ 0, %[[FOR_END23]] ]
diff --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll
index d65480b05759a..543f33ee0621b 100644
--- a/llvm/test/Transforms/Attributor/willreturn.ll
+++ b/llvm/test/Transforms/Attributor/willreturn.ll
@@ -238,7 +238,7 @@ define void @only_exit() local_unnamed_addr #0 {
define void @conditional_exit(i32 %0, ptr nocapture readonly %1) local_unnamed_addr #0 {
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@conditional_exit
-; CHECK-SAME: (i32 [[TMP0:%.*]], ptr nofree readonly captures(none) [[TMP1:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
+; CHECK-SAME: (i32 [[TMP0:%.*]], ptr nofree nonnull readonly align 4 captures(none) dereferenceable(4) [[TMP1:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; CHECK: 4:
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index 9d5ae1606f2e3..e06fb1cfd9656 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -360,7 +360,6 @@ declare nonnull ptr @nonnull()
define internal ptr @f1(ptr %arg) {
-; FIXME: missing nonnull It should be nonnull @f1(ptr nonnull readonly %arg)
; FNATTRS-LABEL: define internal nonnull ptr @f1(
; FNATTRS-SAME: ptr readonly captures(address_is_null) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
; FNATTRS-NEXT: bb:
@@ -383,7 +382,7 @@ define internal ptr @f1(ptr %arg) {
; FNATTRS-NEXT: ret ptr [[TMP10]]
;
; ATTRIBUTOR-LABEL: define internal ptr @f1(
-; ATTRIBUTOR-SAME: ptr nofree readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
+; ATTRIBUTOR-SAME: ptr nofree nonnull readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
; ATTRIBUTOR-NEXT: bb:
; ATTRIBUTOR-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
; ATTRIBUTOR-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
More information about the llvm-commits
mailing list