xref: /llvm-project/llvm/test/Transforms/SROA/select-gep.ll (revision 2f8e37d20114ecb223caaa5a72e8b7c13daf9f34)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG
3; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG
4
5%pair = type { i32, i32 }
6
7define i32 @test_sroa_select_gep(i1 %cond) {
8; CHECK-LABEL: @test_sroa_select_gep(
9; CHECK-NEXT:  bb:
10; CHECK-NEXT:    [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2
11; CHECK-NEXT:    ret i32 [[LOAD_SROA_SPECULATED]]
12;
13bb:
14  %a = alloca %pair, align 4
15  %b = alloca %pair, align 4
16  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
17  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
18  store i32 1, ptr %gep_a, align 4
19  store i32 2, ptr %gep_b, align 4
20  %select = select i1 %cond, ptr %a, ptr %b
21  %gep = getelementptr inbounds %pair, ptr %select, i32 0, i32 1
22  %load = load i32, ptr %gep, align 4
23  ret i32 %load
24}
25
26define i32 @test_sroa_select_gep_non_inbound(i1 %cond) {
27; CHECK-LABEL: @test_sroa_select_gep_non_inbound(
28; CHECK-NEXT:  bb:
29; CHECK-NEXT:    [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2
30; CHECK-NEXT:    ret i32 [[LOAD_SROA_SPECULATED]]
31;
32bb:
33  %a = alloca %pair, align 4
34  %b = alloca %pair, align 4
35  %gep_a = getelementptr %pair, ptr %a, i32 0, i32 1
36  %gep_b = getelementptr %pair, ptr %b, i32 0, i32 1
37  store i32 1, ptr %gep_a, align 4
38  store i32 2, ptr %gep_b, align 4
39  %select = select i1 %cond, ptr %a, ptr %b
40  %gep = getelementptr %pair, ptr %select, i32 0, i32 1
41  %load = load i32, ptr %gep, align 4
42  ret i32 %load
43}
44
45define i32 @test_sroa_select_gep_volatile_load(i1 %cond) {
46; CHECK-LABEL: @test_sroa_select_gep_volatile_load(
47; CHECK-NEXT:  bb:
48; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
49; CHECK-NEXT:    [[A_SROA_2:%.*]] = alloca i32, align 4
50; CHECK-NEXT:    [[B_SROA_0:%.*]] = alloca i32, align 4
51; CHECK-NEXT:    [[B_SROA_2:%.*]] = alloca i32, align 4
52; CHECK-NEXT:    store i32 11, ptr [[A_SROA_0]], align 4
53; CHECK-NEXT:    store i32 12, ptr [[B_SROA_0]], align 4
54; CHECK-NEXT:    store i32 21, ptr [[A_SROA_2]], align 4
55; CHECK-NEXT:    store i32 22, ptr [[B_SROA_2]], align 4
56; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr [[B_SROA_0]]
57; CHECK-NEXT:    [[LOAD1:%.*]] = load volatile i32, ptr [[SELECT]], align 4
58; CHECK-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[COND]], ptr [[A_SROA_2]], ptr [[B_SROA_2]]
59; CHECK-NEXT:    [[LOAD2:%.*]] = load volatile i32, ptr [[SELECT_SROA_SEL]], align 4
60; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[LOAD1]], [[LOAD2]]
61; CHECK-NEXT:    ret i32 [[ADD]]
62;
63bb:
64  %a = alloca %pair, align 4
65  %b = alloca %pair, align 4
66  store i32 11, ptr %a, align 4
67  store i32 12, ptr %b, align 4
68  %gep_a1 = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
69  %gep_b1 = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
70  store i32 21, ptr %gep_a1, align 4
71  store i32 22, ptr %gep_b1, align 4
72  %select = select i1 %cond, ptr %a, ptr %b
73  %load1 = load volatile i32, ptr %select, align 4
74  %gep2 = getelementptr inbounds %pair, ptr %select, i32 0, i32 1
75  %load2 = load volatile i32, ptr %gep2, align 4
76  %add = add i32 %load1, %load2
77  ret i32 %add
78}
79
80define i32 @test_sroa_select_gep_poison(i1 %cond) {
81; CHECK-PRESERVE-CFG-LABEL: @test_sroa_select_gep_poison(
82; CHECK-PRESERVE-CFG-NEXT:  bb:
83; CHECK-PRESERVE-CFG-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
84; CHECK-PRESERVE-CFG-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison
85; CHECK-PRESERVE-CFG-NEXT:    [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4
86; CHECK-PRESERVE-CFG-NEXT:    ret i32 [[LOAD]]
87;
88; CHECK-MODIFY-CFG-LABEL: @test_sroa_select_gep_poison(
89; CHECK-MODIFY-CFG-NEXT:  bb:
90; CHECK-MODIFY-CFG-NEXT:    br i1 [[COND:%.*]], label [[BB_CONT:%.*]], label [[BB_ELSE:%.*]]
91; CHECK-MODIFY-CFG:       bb.else:
92; CHECK-MODIFY-CFG-NEXT:    [[LOAD_ELSE_VAL:%.*]] = load i32, ptr poison, align 4
93; CHECK-MODIFY-CFG-NEXT:    br label [[BB_CONT]]
94; CHECK-MODIFY-CFG:       bb.cont:
95; CHECK-MODIFY-CFG-NEXT:    [[LOAD:%.*]] = phi i32 [ undef, [[BB:%.*]] ], [ [[LOAD_ELSE_VAL]], [[BB_ELSE]] ]
96; CHECK-MODIFY-CFG-NEXT:    ret i32 [[LOAD]]
97;
98bb:
99  %a = alloca %pair, align 4
100  %select = select i1 %cond, ptr %a, ptr poison
101  %gep = getelementptr inbounds %pair, ptr %select, i32 0, i32 1
102  %load = load i32, ptr %gep, align 4
103  ret i32 %load
104}
105
106define i32 @test_sroa_gep_select_gep(i1 %cond) {
107; CHECK-LABEL: @test_sroa_gep_select_gep(
108; CHECK-NEXT:  bb:
109; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
110; CHECK-NEXT:    [[B_SROA_0:%.*]] = alloca i32, align 4
111; CHECK-NEXT:    store i32 1, ptr [[A_SROA_0]], align 4
112; CHECK-NEXT:    store i32 2, ptr [[B_SROA_0]], align 4
113; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr [[B_SROA_0]]
114; CHECK-NEXT:    [[SELECT2:%.*]] = select i1 [[COND]], ptr [[SELECT]], ptr [[A_SROA_0]]
115; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[SELECT2]], align 4
116; CHECK-NEXT:    ret i32 [[LOAD]]
117;
118bb:
119  %a = alloca %pair, align 4
120  %b = alloca %pair, align 4
121  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
122  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
123  store i32 1, ptr %gep_a, align 4
124  store i32 2, ptr %gep_b, align 4
125  %select = select i1 %cond, ptr %gep_a, ptr %gep_b
126  %select2 = select i1 %cond, ptr %select, ptr %gep_a
127  %load = load i32, ptr %select2, align 4
128  ret i32 %load
129}
130
131define i32 @test_sroa_gep_select_gep_nonconst_idx(i1 %cond, i32 %idx) {
132; CHECK-LABEL: @test_sroa_gep_select_gep_nonconst_idx(
133; CHECK-NEXT:  bb:
134; CHECK-NEXT:    [[A:%.*]] = alloca [[PAIR:%.*]], align 4
135; CHECK-NEXT:    [[B:%.*]] = alloca [[PAIR]], align 4
136; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
137; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1
138; CHECK-NEXT:    store i32 1, ptr [[GEP_A]], align 4
139; CHECK-NEXT:    store i32 2, ptr [[GEP_B]], align 4
140; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A]], ptr [[B]]
141; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[SELECT]], i32 [[IDX:%.*]], i32 1
142; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
143; CHECK-NEXT:    ret i32 [[LOAD]]
144;
145bb:
146  %a = alloca %pair, align 4
147  %b = alloca %pair, align 4
148  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
149  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
150  store i32 1, ptr %gep_a, align 4
151  store i32 2, ptr %gep_b, align 4
152  %select = select i1 %cond, ptr %a, ptr %b
153  %gep = getelementptr inbounds %pair, ptr %select, i32 %idx, i32 1
154  %load = load i32, ptr %gep, align 4
155  ret i32 %load
156}
157
158; Test gep of index select unfolding on an alloca that is splittable, but not
159; promotable. The allocas here will be optimized away by subsequent passes.
160define i32 @test_select_idx_memcpy(i1 %c, ptr %p) {
161; CHECK-LABEL: @test_select_idx_memcpy(
162; CHECK-NEXT:    [[ALLOCA_SROA_0:%.*]] = alloca [4 x i8], align 8
163; CHECK-NEXT:    [[ALLOCA_SROA_2:%.*]] = alloca [20 x i8], align 4
164; CHECK-NEXT:    [[ALLOCA_SROA_22:%.*]] = alloca [4 x i8], align 8
165; CHECK-NEXT:    [[ALLOCA_SROA_3:%.*]] = alloca [132 x i8], align 4
166; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA_SROA_0]], ptr align 1 [[P:%.*]], i64 4, i1 false)
167; CHECK-NEXT:    [[ALLOCA_SROA_2_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
168; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ALLOCA_SROA_2]], ptr align 1 [[ALLOCA_SROA_2_0_P_SROA_IDX]], i64 20, i1 false)
169; CHECK-NEXT:    [[ALLOCA_SROA_22_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 24
170; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA_SROA_22]], ptr align 1 [[ALLOCA_SROA_22_0_P_SROA_IDX]], i64 4, i1 false)
171; CHECK-NEXT:    [[ALLOCA_SROA_3_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 28
172; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ALLOCA_SROA_3]], ptr align 1 [[ALLOCA_SROA_3_0_P_SROA_IDX]], i64 132, i1 false)
173; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
174; CHECK-NEXT:    [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[ALLOCA_SROA_22]], ptr [[ALLOCA_SROA_0]]
175; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4
176; CHECK-NEXT:    ret i32 [[RES]]
177;
178  %alloca = alloca [20 x i64], align 8
179  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false)
180  %idx = select i1 %c, i64 24, i64 0
181  %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx
182  %res = load i32, ptr %gep, align 4
183  ret i32 %res
184}
185
186; Test gep of index select unfolding on an alloca that is splittable and
187; promotable.
188define i32 @test_select_idx_mem2reg(i1 %c) {
189; CHECK-LABEL: @test_select_idx_mem2reg(
190; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
191; CHECK-NEXT:    [[RES_SROA_SPECULATED:%.*]] = select i1 [[C]], i32 2, i32 1
192; CHECK-NEXT:    ret i32 [[RES_SROA_SPECULATED]]
193;
194  %alloca = alloca [20 x i64], align 8
195  store i32 1, ptr %alloca
196  %gep1 = getelementptr inbounds i8, ptr %alloca, i64 24
197  store i32 2, ptr %gep1
198  %idx = select i1 %c, i64 24, i64 0
199  %gep2 = getelementptr inbounds i8, ptr %alloca, i64 %idx
200  %res = load i32, ptr %gep2, align 4
201  ret i32 %res
202}
203
204; Test gep of index select unfolding on an alloca that escaped, and as such
205; is not splittable or promotable.
206; FIXME: Ideally, no transform would take place in this case.
207define i32 @test_select_idx_escaped(i1 %c, ptr %p) {
208; CHECK-LABEL: @test_select_idx_escaped(
209; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [20 x i64], align 8
210; CHECK-NEXT:    store ptr [[ALLOCA]], ptr [[P:%.*]], align 8
211; CHECK-NEXT:    store i32 1, ptr [[ALLOCA]], align 4
212; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24
213; CHECK-NEXT:    store i32 2, ptr [[GEP1]], align 4
214; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
215; CHECK-NEXT:    [[DOTSROA_GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24
216; CHECK-NEXT:    [[DOTSROA_GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 0
217; CHECK-NEXT:    [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[DOTSROA_GEP]], ptr [[DOTSROA_GEP1]]
218; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4
219; CHECK-NEXT:    ret i32 [[RES]]
220;
221  %alloca = alloca [20 x i64], align 8
222  store ptr %alloca, ptr %p
223  store i32 1, ptr %alloca
224  %gep1 = getelementptr inbounds i8, ptr %alloca, i64 24
225  store i32 2, ptr %gep1
226  %idx = select i1 %c, i64 24, i64 0
227  %gep2 = getelementptr inbounds i8, ptr %alloca, i64 %idx
228  %res = load i32, ptr %gep2, align 4
229  ret i32 %res
230}
231
232; FIXME: Should we allow recursive select unfolding if all the leaves are
233; constants?
234define i32 @test_select_idx_nested(i1 %c, i1 %c2) {
235; CHECK-LABEL: @test_select_idx_nested(
236; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [20 x i64], align 8
237; CHECK-NEXT:    store i32 1, ptr [[ALLOCA]], align 4
238; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 8
239; CHECK-NEXT:    store i32 2, ptr [[GEP1]], align 4
240; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24
241; CHECK-NEXT:    store i32 3, ptr [[GEP2]], align 4
242; CHECK-NEXT:    [[IDX1:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
243; CHECK-NEXT:    [[IDX2:%.*]] = select i1 [[C2:%.*]], i64 [[IDX1]], i64 8
244; CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX2]]
245; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP3]], align 4
246; CHECK-NEXT:    ret i32 [[RES]]
247;
248  %alloca = alloca [20 x i64], align 8
249  store i32 1, ptr %alloca
250  %gep1 = getelementptr inbounds i8, ptr %alloca, i64 8
251  store i32 2, ptr %gep1
252  %gep2 = getelementptr inbounds i8, ptr %alloca, i64 24
253  store i32 3, ptr %gep2
254  %idx1 = select i1 %c, i64 24, i64 0
255  %idx2 = select i1 %c2, i64 %idx1, i64 8
256  %gep3 = getelementptr inbounds i8, ptr %alloca, i64 %idx2
257  %res = load i32, ptr %gep3, align 4
258  ret i32 %res
259}
260
261; The following cases involve non-constant indices and should not be
262; transformed.
263
264define i32 @test_select_idx_not_constant1(i1 %c, ptr %p, i64 %arg) {
265; CHECK-LABEL: @test_select_idx_not_constant1(
266; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [20 x i64], align 8
267; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false)
268; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 [[ARG:%.*]]
269; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX]]
270; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP]], align 4
271; CHECK-NEXT:    ret i32 [[RES]]
272;
273  %alloca = alloca [20 x i64], align 8
274  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false)
275  %idx = select i1 %c, i64 24, i64 %arg
276  %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx
277  %res = load i32, ptr %gep, align 4
278  ret i32 %res
279}
280
281define i32 @test_select_idx_not_constant2(i1 %c, ptr %p, i64 %arg) {
282; CHECK-LABEL: @test_select_idx_not_constant2(
283; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [20 x i64], align 8
284; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false)
285; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 [[ARG:%.*]], i64 0
286; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX]]
287; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP]], align 4
288; CHECK-NEXT:    ret i32 [[RES]]
289;
290  %alloca = alloca [20 x i64], align 8
291  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false)
292  %idx = select i1 %c, i64 %arg, i64 0
293  %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx
294  %res = load i32, ptr %gep, align 4
295  ret i32 %res
296}
297
298define i32 @test_select_idx_not_constant3(i1 %c, ptr %p, i64 %arg) {
299; CHECK-LABEL: @test_select_idx_not_constant3(
300; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [20 x i64], align 8
301; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false)
302; CHECK-NEXT:    [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
303; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [1 x i8], ptr [[ALLOCA]], i64 [[IDX]], i64 [[ARG:%.*]]
304; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP]], align 4
305; CHECK-NEXT:    ret i32 [[RES]]
306;
307  %alloca = alloca [20 x i64], align 8
308  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false)
309  %idx = select i1 %c, i64 24, i64 0
310  %gep = getelementptr inbounds [1 x i8], ptr %alloca, i64 %idx, i64 %arg
311  %res = load i32, ptr %gep, align 4
312  ret i32 %res
313}
314