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
5 %pair = type { i32, i32 }
7 define i32 @test_sroa_select_gep(i1 %cond) {
8 ; CHECK-LABEL: @test_sroa_select_gep(
10 ; CHECK-NEXT: [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2
11 ; CHECK-NEXT: ret i32 [[LOAD_SROA_SPECULATED]]
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
26 define i32 @test_sroa_select_gep_non_inbound(i1 %cond) {
27 ; CHECK-LABEL: @test_sroa_select_gep_non_inbound(
29 ; CHECK-NEXT: [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2
30 ; CHECK-NEXT: ret i32 [[LOAD_SROA_SPECULATED]]
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
45 define i32 @test_sroa_select_gep_volatile_load(i1 %cond) {
46 ; CHECK-LABEL: @test_sroa_select_gep_volatile_load(
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]]
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
80 define 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]]
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]]
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
106 define i32 @test_sroa_gep_select_gep(i1 %cond) {
107 ; CHECK-LABEL: @test_sroa_gep_select_gep(
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]]
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
131 define i32 @test_sroa_gep_select_gep_nonconst_idx(i1 %cond, i32 %idx) {
132 ; CHECK-LABEL: @test_sroa_gep_select_gep_nonconst_idx(
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]]
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
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.
160 define 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]]
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
186 ; Test gep of index select unfolding on an alloca that is splittable and
188 define 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]]
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
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.
207 define 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]]
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
232 ; FIXME: Should we allow recursive select unfolding if all the leaves are
234 define 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]]
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
261 ; The following cases involve non-constant indices and should not be
264 define 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]]
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
281 define 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]]
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
298 define 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]]
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