xref: /aosp_15_r20/external/llvm/test/Transforms/DeadArgElim/aggregates.ll (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker; RUN: opt -S -deadargelim %s | FileCheck %s
2*9880d681SAndroid Build Coastguard Worker
3*9880d681SAndroid Build Coastguard Worker; Case 0: the basic example: an entire aggregate use is returned, but it's
4*9880d681SAndroid Build Coastguard Worker; actually only used in ways we can eliminate. We gain benefit from analysing
5*9880d681SAndroid Build Coastguard Worker; the "use" and applying its results to all sub-values.
6*9880d681SAndroid Build Coastguard Worker
7*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal void @agguse_dead()
8*9880d681SAndroid Build Coastguard Worker
9*9880d681SAndroid Build Coastguard Workerdefine internal { i32, i32 } @agguse_dead() {
10*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } { i32 0, i32 1 }
11*9880d681SAndroid Build Coastguard Worker}
12*9880d681SAndroid Build Coastguard Worker
13*9880d681SAndroid Build Coastguard Workerdefine internal { i32, i32 } @test_agguse_dead() {
14*9880d681SAndroid Build Coastguard Worker  %val = call { i32, i32 } @agguse_dead()
15*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } %val
16*9880d681SAndroid Build Coastguard Worker}
17*9880d681SAndroid Build Coastguard Worker
18*9880d681SAndroid Build Coastguard Worker
19*9880d681SAndroid Build Coastguard Worker
20*9880d681SAndroid Build Coastguard Worker; Case 1: an opaque use of the aggregate exists (in this case dead). Otherwise
21*9880d681SAndroid Build Coastguard Worker; only one value is used, so function can be simplified.
22*9880d681SAndroid Build Coastguard Worker
23*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal i32 @rets_independent_if_agguse_dead()
24*9880d681SAndroid Build Coastguard Worker; CHECK: [[RET:%.*]] = extractvalue { i32, i32 } { i32 0, i32 1 }, 1
25*9880d681SAndroid Build Coastguard Worker; CHECK: ret i32 [[RET]]
26*9880d681SAndroid Build Coastguard Worker
27*9880d681SAndroid Build Coastguard Workerdefine internal { i32, i32 } @rets_independent_if_agguse_dead() {
28*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } { i32 0, i32 1 }
29*9880d681SAndroid Build Coastguard Worker}
30*9880d681SAndroid Build Coastguard Worker
31*9880d681SAndroid Build Coastguard Workerdefine internal { i32, i32 } @test_rets_independent_if_agguse_dead(i1 %tst) {
32*9880d681SAndroid Build Coastguard Worker  %val = call { i32, i32 } @rets_independent_if_agguse_dead()
33*9880d681SAndroid Build Coastguard Worker  br i1 %tst, label %use_1, label %use_aggregate
34*9880d681SAndroid Build Coastguard Worker
35*9880d681SAndroid Build Coastguard Workeruse_1:
36*9880d681SAndroid Build Coastguard Worker  ; This use can be classified as applying only to ret 1.
37*9880d681SAndroid Build Coastguard Worker  %val0 = extractvalue { i32, i32 } %val, 1
38*9880d681SAndroid Build Coastguard Worker  call void @callee(i32 %val0)
39*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } undef
40*9880d681SAndroid Build Coastguard Worker
41*9880d681SAndroid Build Coastguard Workeruse_aggregate:
42*9880d681SAndroid Build Coastguard Worker  ; This use is assumed to apply to both 0 and 1.
43*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } %val
44*9880d681SAndroid Build Coastguard Worker}
45*9880d681SAndroid Build Coastguard Worker
46*9880d681SAndroid Build Coastguard Worker; Case 2: an opaque use of the aggregate exists (in this case *live*). Other
47*9880d681SAndroid Build Coastguard Worker; uses shouldn't matter.
48*9880d681SAndroid Build Coastguard Worker
49*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal { i32, i32 } @rets_live_agguse()
50*9880d681SAndroid Build Coastguard Worker; CHECK: ret { i32, i32 } { i32 0, i32 1 }
51*9880d681SAndroid Build Coastguard Worker
52*9880d681SAndroid Build Coastguard Workerdefine internal { i32, i32 } @rets_live_agguse() {
53*9880d681SAndroid Build Coastguard Worker  ret { i32, i32} { i32 0, i32 1 }
54*9880d681SAndroid Build Coastguard Worker}
55*9880d681SAndroid Build Coastguard Worker
56*9880d681SAndroid Build Coastguard Workerdefine { i32, i32 } @test_rets_live_aggues(i1 %tst) {
57*9880d681SAndroid Build Coastguard Worker  %val = call { i32, i32 } @rets_live_agguse()
58*9880d681SAndroid Build Coastguard Worker  br i1 %tst, label %use_1, label %use_aggregate
59*9880d681SAndroid Build Coastguard Worker
60*9880d681SAndroid Build Coastguard Workeruse_1:
61*9880d681SAndroid Build Coastguard Worker  ; This use can be classified as applying only to ret 1.
62*9880d681SAndroid Build Coastguard Worker  %val0 = extractvalue { i32, i32 } %val, 1
63*9880d681SAndroid Build Coastguard Worker  call void @callee(i32 %val0)
64*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } undef
65*9880d681SAndroid Build Coastguard Worker
66*9880d681SAndroid Build Coastguard Workeruse_aggregate:
67*9880d681SAndroid Build Coastguard Worker  ; This use is assumed to apply to both 0 and 1.
68*9880d681SAndroid Build Coastguard Worker  ret { i32, i32 } %val
69*9880d681SAndroid Build Coastguard Worker}
70*9880d681SAndroid Build Coastguard Worker
71*9880d681SAndroid Build Coastguard Workerdeclare void @callee(i32)
72*9880d681SAndroid Build Coastguard Worker
73*9880d681SAndroid Build Coastguard Worker; Case 3: the insertvalue meant %in was live if ret-slot-1 was, but we were only
74*9880d681SAndroid Build Coastguard Worker; tracking multiple ret-slots for struct types. So %in was eliminated
75*9880d681SAndroid Build Coastguard Worker; incorrectly.
76*9880d681SAndroid Build Coastguard Worker
77*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal [2 x i32] @array_rets_have_multiple_slots(i32 %in)
78*9880d681SAndroid Build Coastguard Worker
79*9880d681SAndroid Build Coastguard Workerdefine internal [2 x i32] @array_rets_have_multiple_slots(i32 %in) {
80*9880d681SAndroid Build Coastguard Worker  %ret = insertvalue [2 x i32] undef, i32 %in, 1
81*9880d681SAndroid Build Coastguard Worker  ret [2 x i32] %ret
82*9880d681SAndroid Build Coastguard Worker}
83*9880d681SAndroid Build Coastguard Worker
84*9880d681SAndroid Build Coastguard Workerdefine [2 x i32] @test_array_rets_have_multiple_slots() {
85*9880d681SAndroid Build Coastguard Worker  %res = call [2 x i32] @array_rets_have_multiple_slots(i32 42)
86*9880d681SAndroid Build Coastguard Worker  ret [2 x i32] %res
87*9880d681SAndroid Build Coastguard Worker}
88*9880d681SAndroid Build Coastguard Worker
89*9880d681SAndroid Build Coastguard Worker; Case 4: we can remove some retvals from the array. It's nice to produce an
90*9880d681SAndroid Build Coastguard Worker; array again having done so (rather than converting it to a struct).
91*9880d681SAndroid Build Coastguard Worker
92*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal [2 x i32] @can_shrink_arrays()
93*9880d681SAndroid Build Coastguard Worker; CHECK: [[VAL0:%.*]] = extractvalue [3 x i32] [i32 42, i32 43, i32 44], 0
94*9880d681SAndroid Build Coastguard Worker; CHECK: [[RESTMP:%.*]] = insertvalue [2 x i32] undef, i32 [[VAL0]], 0
95*9880d681SAndroid Build Coastguard Worker; CHECK: [[VAL2:%.*]] = extractvalue [3 x i32] [i32 42, i32 43, i32 44], 2
96*9880d681SAndroid Build Coastguard Worker; CHECK: [[RES:%.*]] = insertvalue [2 x i32] [[RESTMP]], i32 [[VAL2]], 1
97*9880d681SAndroid Build Coastguard Worker; CHECK: ret [2 x i32] [[RES]]
98*9880d681SAndroid Build Coastguard Worker
99*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define void @test_can_shrink_arrays()
100*9880d681SAndroid Build Coastguard Worker
101*9880d681SAndroid Build Coastguard Workerdefine internal [3 x i32] @can_shrink_arrays() {
102*9880d681SAndroid Build Coastguard Worker  ret [3 x i32] [i32 42, i32 43, i32 44]
103*9880d681SAndroid Build Coastguard Worker}
104*9880d681SAndroid Build Coastguard Worker
105*9880d681SAndroid Build Coastguard Workerdefine void @test_can_shrink_arrays() {
106*9880d681SAndroid Build Coastguard Worker  %res = call [3 x i32] @can_shrink_arrays()
107*9880d681SAndroid Build Coastguard Worker
108*9880d681SAndroid Build Coastguard Worker  %res.0 = extractvalue [3 x i32] %res, 0
109*9880d681SAndroid Build Coastguard Worker  call void @callee(i32 %res.0)
110*9880d681SAndroid Build Coastguard Worker
111*9880d681SAndroid Build Coastguard Worker  %res.2 = extractvalue [3 x i32] %res, 2
112*9880d681SAndroid Build Coastguard Worker  call void @callee(i32 %res.2)
113*9880d681SAndroid Build Coastguard Worker
114*9880d681SAndroid Build Coastguard Worker  ret void
115*9880d681SAndroid Build Coastguard Worker}
116*9880d681SAndroid Build Coastguard Worker
117*9880d681SAndroid Build Coastguard Worker; Case 5: %in gets passed directly to the return. It should mark be marked as
118*9880d681SAndroid Build Coastguard Worker; used if *any* of the return values are, not just if value 0 is.
119*9880d681SAndroid Build Coastguard Worker
120*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal i32 @ret_applies_to_all({ i32, i32 } %in)
121*9880d681SAndroid Build Coastguard Worker; CHECK: [[RET:%.*]] = extractvalue { i32, i32 } %in, 1
122*9880d681SAndroid Build Coastguard Worker; CHECK: ret i32 [[RET]]
123*9880d681SAndroid Build Coastguard Worker
124*9880d681SAndroid Build Coastguard Workerdefine internal {i32, i32} @ret_applies_to_all({i32, i32} %in) {
125*9880d681SAndroid Build Coastguard Worker  ret {i32, i32} %in
126*9880d681SAndroid Build Coastguard Worker}
127*9880d681SAndroid Build Coastguard Worker
128*9880d681SAndroid Build Coastguard Workerdefine i32 @test_ret_applies_to_all() {
129*9880d681SAndroid Build Coastguard Worker  %val = call {i32, i32} @ret_applies_to_all({i32, i32} {i32 42, i32 43})
130*9880d681SAndroid Build Coastguard Worker  %ret = extractvalue {i32, i32} %val, 1
131*9880d681SAndroid Build Coastguard Worker  ret i32 %ret
132*9880d681SAndroid Build Coastguard Worker}
133*9880d681SAndroid Build Coastguard Worker
134*9880d681SAndroid Build Coastguard Worker; Case 6: When considering @mid, the return instruciton has sub-value 0
135*9880d681SAndroid Build Coastguard Worker; unconditionally live, but 1 only conditionally live. Since at that level we're
136*9880d681SAndroid Build Coastguard Worker; applying the results to the whole of %res, this means %res is live and cannot
137*9880d681SAndroid Build Coastguard Worker; be reduced. There is scope for further optimisation here (though not visible
138*9880d681SAndroid Build Coastguard Worker; in this test-case).
139*9880d681SAndroid Build Coastguard Worker
140*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define internal { i8*, i32 } @inner()
141*9880d681SAndroid Build Coastguard Worker
142*9880d681SAndroid Build Coastguard Workerdefine internal {i8*, i32} @mid() {
143*9880d681SAndroid Build Coastguard Worker  %res = call {i8*, i32} @inner()
144*9880d681SAndroid Build Coastguard Worker  %intval = extractvalue {i8*, i32} %res, 1
145*9880d681SAndroid Build Coastguard Worker  %tst = icmp eq i32 %intval, 42
146*9880d681SAndroid Build Coastguard Worker  br i1 %tst, label %true, label %true
147*9880d681SAndroid Build Coastguard Worker
148*9880d681SAndroid Build Coastguard Workertrue:
149*9880d681SAndroid Build Coastguard Worker  ret {i8*, i32} %res
150*9880d681SAndroid Build Coastguard Worker}
151*9880d681SAndroid Build Coastguard Worker
152*9880d681SAndroid Build Coastguard Workerdefine internal {i8*, i32} @inner() {
153*9880d681SAndroid Build Coastguard Worker  ret {i8*, i32} {i8* null, i32 42}
154*9880d681SAndroid Build Coastguard Worker}
155*9880d681SAndroid Build Coastguard Worker
156*9880d681SAndroid Build Coastguard Workerdefine internal i8 @outer() {
157*9880d681SAndroid Build Coastguard Worker  %res = call {i8*, i32} @mid()
158*9880d681SAndroid Build Coastguard Worker  %resptr = extractvalue {i8*, i32} %res, 0
159*9880d681SAndroid Build Coastguard Worker
160*9880d681SAndroid Build Coastguard Worker  %val = load i8, i8* %resptr
161*9880d681SAndroid Build Coastguard Worker  ret i8 %val
162*9880d681SAndroid Build Coastguard Worker}
163*9880d681SAndroid Build Coastguard Worker
164*9880d681SAndroid Build Coastguard Workerdefine internal { i32 } @agg_ret() {
165*9880d681SAndroid Build Coastguard Workerentry:
166*9880d681SAndroid Build Coastguard Worker  unreachable
167*9880d681SAndroid Build Coastguard Worker}
168*9880d681SAndroid Build Coastguard Worker
169*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: define void @PR24906
170*9880d681SAndroid Build Coastguard Worker; CHECK: %[[invoke:.*]] = invoke i32 @agg_ret()
171*9880d681SAndroid Build Coastguard Worker; CHECK: %[[oldret:.*]] = insertvalue { i32 } undef, i32 %[[invoke]], 0
172*9880d681SAndroid Build Coastguard Worker; CHECK: phi { i32 } [ %[[oldret]],
173*9880d681SAndroid Build Coastguard Workerdefine void @PR24906() personality i32 (i32)* undef {
174*9880d681SAndroid Build Coastguard Workerentry:
175*9880d681SAndroid Build Coastguard Worker  %tmp2 = invoke { i32 } @agg_ret()
176*9880d681SAndroid Build Coastguard Worker          to label %bb3 unwind label %bb4
177*9880d681SAndroid Build Coastguard Worker
178*9880d681SAndroid Build Coastguard Workerbb3:
179*9880d681SAndroid Build Coastguard Worker  %tmp3 = phi { i32 } [ %tmp2, %entry ]
180*9880d681SAndroid Build Coastguard Worker  unreachable
181*9880d681SAndroid Build Coastguard Worker
182*9880d681SAndroid Build Coastguard Workerbb4:
183*9880d681SAndroid Build Coastguard Worker  %tmp4 = landingpad { i8*, i32 }
184*9880d681SAndroid Build Coastguard Worker          cleanup
185*9880d681SAndroid Build Coastguard Worker  unreachable
186*9880d681SAndroid Build Coastguard Worker}
187