Skip to content

Commit 2920770

Browse files
committed
[Local] Treat calls that may not return as being alive.
With the addition of the `willreturn` attribute, functions that may not return (e.g. due to an infinite loop) are well defined, if they are not marked as `willreturn`. This patch updates `wouldInstructionBeTriviallyDead` to not consider calls that may not return as dead. This patch still provides an escape hatch for intrinsics, which are still assumed as willreturn unconditionally. It will be removed once all intrinsics definitions have been reviewed and updated. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D94106
1 parent 25531a1 commit 2920770

File tree

29 files changed

+237
-215
lines changed

29 files changed

+237
-215
lines changed

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,10 @@ class CallBase : public Instruction {
17561756
bool onlyReadsMemory() const {
17571757
return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly);
17581758
}
1759+
1760+
/// Returns true if this function is guaranteed to return.
1761+
bool willReturn() const { return hasFnAttr(Attribute::WillReturn); }
1762+
17591763
void setOnlyReadsMemory() {
17601764
addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly);
17611765
}

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,14 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
420420
return true;
421421
}
422422

423+
if (auto *CB = dyn_cast<CallBase>(I)) {
424+
// Treat calls that may not return as alive.
425+
// TODO: Remove the intrinsic escape hatch once all intrinsics set
426+
// willreturn properly.
427+
if (!CB->willReturn() && !isa<IntrinsicInst>(I))
428+
return false;
429+
}
430+
423431
if (!I->mayHaveSideEffects())
424432
return true;
425433

llvm/test/Feature/OperandBundles/early-cse.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
; they're carrying unknown operand bundles since the presence of
66
; unknown operand bundles implies arbitrary memory effects.
77

8-
declare void @readonly_function() readonly nounwind
9-
declare void @readnone_function() readnone nounwind
8+
declare void @readonly_function() readonly nounwind willreturn
9+
declare void @readnone_function() readnone nounwind willreturn
1010

1111
define i32 @test0(i32* %x) {
1212
; CHECK-LABEL: @test0(

llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,32 @@ target triple = "x86_64-unknown-linux-gnu"
1717
@a = internal global %struct.Foo { i32 1, i64 2 }, align 8
1818

1919
define void @run() {
20-
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
21-
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@run
22-
; NOT_CGSCC_NPM-SAME: () [[ATTR0:#.*]] {
23-
; NOT_CGSCC_NPM-NEXT: entry:
24-
; NOT_CGSCC_NPM-NEXT: unreachable
20+
; IS________OPM: Function Attrs: nofree noreturn nosync nounwind readnone
21+
; IS________OPM-LABEL: define {{[^@]+}}@run
22+
; IS________OPM-SAME: () [[ATTR0:#.*]] {
23+
; IS________OPM-NEXT: entry:
24+
; IS________OPM-NEXT: [[TMP0:%.*]] = call i64 @CaptureAStruct(%struct.Foo* nocapture nofree noundef nonnull readonly align 8 dereferenceable(16) @a) [[ATTR0]]
25+
; IS________OPM-NEXT: unreachable
26+
;
27+
; IS__TUNIT_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
28+
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@run
29+
; IS__TUNIT_NPM-SAME: () [[ATTR0:#.*]] {
30+
; IS__TUNIT_NPM-NEXT: entry:
31+
; IS__TUNIT_NPM-NEXT: [[A_CAST:%.*]] = bitcast %struct.Foo* @a to i32*
32+
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_CAST]], align 8
33+
; IS__TUNIT_NPM-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 1
34+
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
35+
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = call i64 @CaptureAStruct(i32 [[TMP0]], i64 [[TMP1]]) [[ATTR0]]
36+
; IS__TUNIT_NPM-NEXT: unreachable
2537
;
2638
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readonly willreturn
2739
; IS__CGSCC____-LABEL: define {{[^@]+}}@run
2840
; IS__CGSCC____-SAME: () [[ATTR0:#.*]] {
2941
; IS__CGSCC____-NEXT: entry:
42+
; IS__CGSCC____-NEXT: [[A_CAST:%.*]] = bitcast %struct.Foo* @a to i32*
43+
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_CAST]], align 8
44+
; IS__CGSCC____-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 1
45+
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
3046
; IS__CGSCC____-NEXT: unreachable
3147
;
3248
entry:
@@ -86,6 +102,37 @@ define internal i64 @CaptureAStruct(%struct.Foo* byval(%struct.Foo) %a) {
86102
; IS__CGSCC_OPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
87103
; IS__CGSCC_OPM-NEXT: br label [[LOOP]]
88104
;
105+
; IS________OPM: Function Attrs: nofree noreturn nosync nounwind readnone
106+
; IS________OPM-LABEL: define {{[^@]+}}@CaptureAStruct
107+
; IS________OPM-SAME: (%struct.Foo* noalias nofree noundef nonnull byval(%struct.Foo) align 8 dereferenceable(16) [[A:%.*]]) [[ATTR0]] {
108+
; IS________OPM-NEXT: entry:
109+
; IS________OPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*, align 8
110+
; IS________OPM-NEXT: br label [[LOOP:%.*]]
111+
; IS________OPM: loop:
112+
; IS________OPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
113+
; IS________OPM-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ]
114+
; IS________OPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
115+
; IS________OPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
116+
; IS________OPM-NEXT: br label [[LOOP]]
117+
;
118+
; IS__TUNIT_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
119+
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@CaptureAStruct
120+
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]]) [[ATTR0]] {
121+
; IS__TUNIT_NPM-NEXT: entry:
122+
; IS__TUNIT_NPM-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
123+
; IS__TUNIT_NPM-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.Foo* [[A_PRIV]] to i32*
124+
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[A_PRIV_CAST]], align 4
125+
; IS__TUNIT_NPM-NEXT: [[A_PRIV_0_1:%.*]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i32 0, i32 1
126+
; IS__TUNIT_NPM-NEXT: store i64 [[TMP1]], i64* [[A_PRIV_0_1]], align 8
127+
; IS__TUNIT_NPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*, align 8
128+
; IS__TUNIT_NPM-NEXT: br label [[LOOP:%.*]]
129+
; IS__TUNIT_NPM: loop:
130+
; IS__TUNIT_NPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
131+
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = phi %struct.Foo* [ [[A_PRIV]], [[ENTRY]] ], [ [[TMP2]], [[LOOP]] ]
132+
; IS__TUNIT_NPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
133+
; IS__TUNIT_NPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i64 0
134+
; IS__TUNIT_NPM-NEXT: br label [[LOOP]]
135+
;
89136
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone
90137
; IS__CGSCC____-LABEL: define {{[^@]+}}@CaptureAStruct
91138
; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]]) [[ATTR2:#.*]] {

llvm/test/Transforms/Attributor/align.ll

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,34 @@ define i32* @test5_2() {
102102
; TEST 6
103103
; SCC
104104
define i32* @test6_1() #0 {
105-
; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
106-
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test6_1
107-
; NOT_CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
108-
; NOT_CGSCC_NPM-NEXT: unreachable
109-
;
110-
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
111-
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test6_1
112-
; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
113-
; IS__CGSCC_NPM-NEXT: unreachable
105+
; NOT_CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
106+
; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@test6_1
107+
; NOT_CGSCC_OPM-SAME: () [[ATTR1:#.*]] {
108+
; NOT_CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_2() [[ATTR11:#.*]]
109+
; NOT_CGSCC_OPM-NEXT: unreachable
110+
;
111+
; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
112+
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test6_1
113+
; IS__CGSCC_OPM-SAME: () [[ATTR1:#.*]] {
114+
; IS__CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_2() [[ATTR12:#.*]]
115+
; IS__CGSCC_OPM-NEXT: unreachable
114116
;
115117
%ret = tail call i32* @test6_2()
116118
ret i32* %ret
117119
}
118120

119121
define i32* @test6_2() #0 {
120-
; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
121-
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test6_2
122-
; NOT_CGSCC_NPM-SAME: () [[ATTR1]] {
123-
; NOT_CGSCC_NPM-NEXT: unreachable
124-
;
125-
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
126-
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test6_2
127-
; IS__CGSCC_NPM-SAME: () [[ATTR1]] {
128-
; IS__CGSCC_NPM-NEXT: unreachable
122+
; NOT_CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
123+
; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@test6_2
124+
; NOT_CGSCC_OPM-SAME: () [[ATTR1]] {
125+
; NOT_CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_1() [[ATTR11]]
126+
; NOT_CGSCC_OPM-NEXT: unreachable
127+
;
128+
; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
129+
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test6_2
130+
; IS__CGSCC_OPM-SAME: () [[ATTR1]] {
131+
; IS__CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_1() [[ATTR12]]
132+
; IS__CGSCC_OPM-NEXT: unreachable
129133
;
130134
%ret = tail call i32* @test6_1()
131135
ret i32* %ret
@@ -967,7 +971,7 @@ define i32 @musttail_caller_1(i32* %p) {
967971
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
968972
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
969973
; IS__CGSCC_OPM: mt:
970-
; IS__CGSCC_OPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR12:#.*]]
974+
; IS__CGSCC_OPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR13:#.*]]
971975
; IS__CGSCC_OPM-NEXT: ret i32 [[V]]
972976
; IS__CGSCC_OPM: exit:
973977
; IS__CGSCC_OPM-NEXT: ret i32 0
@@ -978,7 +982,7 @@ define i32 @musttail_caller_1(i32* %p) {
978982
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
979983
; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
980984
; IS__CGSCC_NPM: mt:
981-
; IS__CGSCC_NPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR11:#.*]]
985+
; IS__CGSCC_NPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR12:#.*]]
982986
; IS__CGSCC_NPM-NEXT: ret i32 [[V]]
983987
; IS__CGSCC_NPM: exit:
984988
; IS__CGSCC_NPM-NEXT: ret i32 0

llvm/test/Transforms/Attributor/nocapture-1.ll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,8 @@ define void @ptr_uses(i8* %ptr, i8* %wptr) {
849849
; CHECK: Function Attrs: nounwind
850850
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
851851
; CHECK-SAME: (i8* [[PTR:%.*]], i8* nocapture nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) [[ATTR13:#.*]] {
852+
; CHECK-NEXT: [[CALL_PTR:%.*]] = call i8* @maybe_returned_ptr(i8* readonly [[PTR]]) [[ATTR4]]
853+
; CHECK-NEXT: [[CALL_VAL:%.*]] = call i8 @maybe_returned_val(i8* readonly [[CALL_PTR]]) [[ATTR4]]
852854
; CHECK-NEXT: store i8 0, i8* [[WPTR]], align 1
853855
; CHECK-NEXT: ret void
854856
;

llvm/test/Transforms/Attributor/nocapture-2.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r
728728
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either3
729729
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) [[ATTR8]] {
730730
; CHECK-NEXT: entry:
731-
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) [[ATTR6]]
731+
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) [[ATTR8]]
732732
; CHECK-NEXT: ret i32* [[CALL]]
733733
;
734734
entry:

llvm/test/Transforms/Attributor/nonnull.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,13 @@ define i8* @test4_helper() {
149149
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
150150
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
151151
; NOT_CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
152+
; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
152153
; NOT_CGSCC_NPM-NEXT: unreachable
153154
;
154-
; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
155+
; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
155156
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
156157
; IS__CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
158+
; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
157159
; IS__CGSCC_NPM-NEXT: unreachable
158160
;
159161
%ret = call i8* @test4()
@@ -164,11 +166,13 @@ define i8* @test4() {
164166
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
165167
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4
166168
; NOT_CGSCC_NPM-SAME: () [[ATTR2]] {
169+
; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
167170
; NOT_CGSCC_NPM-NEXT: unreachable
168171
;
169-
; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
172+
; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
170173
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4
171174
; IS__CGSCC_NPM-SAME: () [[ATTR2]] {
175+
; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
172176
; IS__CGSCC_NPM-NEXT: unreachable
173177
;
174178
%ret = call i8* @test4_helper()

0 commit comments

Comments
 (0)