[rtsan] Add fork/execve interceptors (#117198)
[llvm-project.git] / llvm / test / Transforms / DeadArgElim / aggregates.ll
blob784ac3af64c75451e86b30fee24f7b4720cec6be
1 ; RUN: opt -S -passes=deadargelim %s | FileCheck %s
3 ; Case 0: the basic example: an entire aggregate use is returned, but it's
4 ; actually only used in ways we can eliminate. We gain benefit from analysing
5 ; the "use" and applying its results to all sub-values.
7 ; CHECK-LABEL: define internal void @agguse_dead()
9 define internal { i32, i32 } @agguse_dead() {
10   ret { i32, i32 } { i32 0, i32 1 }
13 define internal { i32, i32 } @test_agguse_dead() {
14   %val = call { i32, i32 } @agguse_dead()
15   ret { i32, i32 } %val
20 ; Case 1: an opaque use of the aggregate exists (in this case dead). Otherwise
21 ; only one value is used, so function can be simplified.
23 ; CHECK-LABEL: define internal i32 @rets_independent_if_agguse_dead()
24 ; CHECK: [[RET:%.*]] = extractvalue { i32, i32 } { i32 0, i32 1 }, 1
25 ; CHECK: ret i32 [[RET]]
27 define internal { i32, i32 } @rets_independent_if_agguse_dead() {
28   ret { i32, i32 } { i32 0, i32 1 }
31 define internal { i32, i32 } @test_rets_independent_if_agguse_dead(i1 %tst) {
32   %val = call { i32, i32 } @rets_independent_if_agguse_dead()
33   br i1 %tst, label %use_1, label %use_aggregate
35 use_1:
36   ; This use can be classified as applying only to ret 1.
37   %val0 = extractvalue { i32, i32 } %val, 1
38   call void @callee(i32 %val0)
39   ret { i32, i32 } poison
41 use_aggregate:
42   ; This use is assumed to apply to both 0 and 1.
43   ret { i32, i32 } %val
46 ; Case 2: an opaque use of the aggregate exists (in this case *live*). Other
47 ; uses shouldn't matter.
49 ; CHECK-LABEL: define internal { i32, i32 } @rets_live_agguse()
50 ; CHECK: ret { i32, i32 } { i32 0, i32 1 }
52 define internal { i32, i32 } @rets_live_agguse() {
53   ret { i32, i32} { i32 0, i32 1 }
56 define { i32, i32 } @test_rets_live_aggues(i1 %tst) {
57   %val = call { i32, i32 } @rets_live_agguse()
58   br i1 %tst, label %use_1, label %use_aggregate
60 use_1:
61   ; This use can be classified as applying only to ret 1.
62   %val0 = extractvalue { i32, i32 } %val, 1
63   call void @callee(i32 %val0)
64   ret { i32, i32 } poison
66 use_aggregate:
67   ; This use is assumed to apply to both 0 and 1.
68   ret { i32, i32 } %val
71 declare void @callee(i32)
73 ; Case 3: the insertvalue meant %in was live if ret-slot-1 was, but we were only
74 ; tracking multiple ret-slots for struct types. So %in was eliminated
75 ; incorrectly.
77 ; CHECK-LABEL: define internal [2 x i32] @array_rets_have_multiple_slots(i32 %in)
79 define internal [2 x i32] @array_rets_have_multiple_slots(i32 %in) {
80   %ret = insertvalue [2 x i32] poison, i32 %in, 1
81   ret [2 x i32] %ret
84 define [2 x i32] @test_array_rets_have_multiple_slots() {
85   %res = call [2 x i32] @array_rets_have_multiple_slots(i32 42)
86   ret [2 x i32] %res
89 ; Case 4: we can remove some retvals from the array. It's nice to produce an
90 ; array again having done so (rather than converting it to a struct).
92 ; CHECK-LABEL: define internal [2 x i32] @can_shrink_arrays()
93 ; CHECK: [[VAL0:%.*]] = extractvalue [3 x i32] [i32 42, i32 43, i32 44], 0
94 ; CHECK: [[RESTMP:%.*]] = insertvalue [2 x i32] poison, i32 [[VAL0]], 0
95 ; CHECK: [[VAL2:%.*]] = extractvalue [3 x i32] [i32 42, i32 43, i32 44], 2
96 ; CHECK: [[RES:%.*]] = insertvalue [2 x i32] [[RESTMP]], i32 [[VAL2]], 1
97 ; CHECK: ret [2 x i32] [[RES]]
99 ; CHECK-LABEL: define void @test_can_shrink_arrays()
101 define internal [3 x i32] @can_shrink_arrays() {
102   ret [3 x i32] [i32 42, i32 43, i32 44]
105 define void @test_can_shrink_arrays() {
106   %res = call [3 x i32] @can_shrink_arrays()
108   %res.0 = extractvalue [3 x i32] %res, 0
109   call void @callee(i32 %res.0)
111   %res.2 = extractvalue [3 x i32] %res, 2
112   call void @callee(i32 %res.2)
114   ret void
117 ; Case 5: %in gets passed directly to the return. It should mark be marked as
118 ; used if *any* of the return values are, not just if value 0 is.
120 ; CHECK-LABEL: define internal i32 @ret_applies_to_all({ i32, i32 } %in)
121 ; CHECK: [[RET:%.*]] = extractvalue { i32, i32 } %in, 1
122 ; CHECK: ret i32 [[RET]]
124 define internal {i32, i32} @ret_applies_to_all({i32, i32} %in) {
125   ret {i32, i32} %in
128 define i32 @test_ret_applies_to_all() {
129   %val = call {i32, i32} @ret_applies_to_all({i32, i32} {i32 42, i32 43})
130   %ret = extractvalue {i32, i32} %val, 1
131   ret i32 %ret
134 ; Case 6: When considering @mid, the return instruciton has sub-value 0
135 ; unconditionally live, but 1 only conditionally live. Since at that level we're
136 ; applying the results to the whole of %res, this means %res is live and cannot
137 ; be reduced. There is scope for further optimisation here (though not visible
138 ; in this test-case).
140 ; CHECK-LABEL: define internal { ptr, i32 } @inner()
142 define internal {ptr, i32} @mid() {
143   %res = call {ptr, i32} @inner()
144   %intval = extractvalue {ptr, i32} %res, 1
145   %tst = icmp eq i32 %intval, 42
146   br i1 %tst, label %true, label %true
148 true:
149   ret {ptr, i32} %res
152 define internal {ptr, i32} @inner() {
153   ret {ptr, i32} {ptr null, i32 42}
156 define internal i8 @outer() {
157   %res = call {ptr, i32} @mid()
158   %resptr = extractvalue {ptr, i32} %res, 0
160   %val = load i8, ptr %resptr
161   ret i8 %val
164 define internal { i32 } @agg_ret() {
165 entry:
166   unreachable
169 ; CHECK-LABEL: define void @PR24906
170 ; CHECK: %[[invoke:.*]] = invoke i32 @agg_ret()
171 ; CHECK: %[[oldret:.*]] = insertvalue { i32 } poison, i32 %[[invoke]], 0
172 ; CHECK: phi { i32 } [ %[[oldret]],
173 define void @PR24906() personality ptr poison {
174 entry:
175   %tmp2 = invoke { i32 } @agg_ret()
176           to label %bb3 unwind label %bb4
178 bb3:
179   %tmp3 = phi { i32 } [ %tmp2, %entry ]
180   unreachable
182 bb4:
183   %tmp4 = landingpad { ptr, i32 }
184           cleanup
185   unreachable