1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -sroa -S | FileCheck %s
3; RUN: opt < %s -passes=sroa -S | FileCheck %s
4
5target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
6
7declare void @llvm.memcpy.p0i8.p1i8.i32(i8* nocapture writeonly, i8 addrspace(1)* nocapture readonly, i32, i1 immarg) #0
8declare void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* nocapture writeonly, i8* nocapture readonly, i32, i1 immarg) #0
9
10define i64 @alloca_addrspacecast_bitcast(i64 %X) {
11; CHECK-LABEL: @alloca_addrspacecast_bitcast(
12; CHECK-NEXT:  entry:
13; CHECK-NEXT:    ret i64 [[X:%.*]]
14;
15entry:
16  %A = alloca [8 x i8]
17  %A.cast = addrspacecast [8 x i8]* %A to [8 x i8] addrspace(1)*
18  %B = bitcast [8 x i8] addrspace(1)* %A.cast to i64 addrspace(1)*
19  store i64 %X, i64 addrspace(1)* %B
20  %Z = load i64, i64 addrspace(1)* %B
21  ret i64 %Z
22}
23
24define i64 @alloca_bitcast_addrspacecast(i64 %X) {
25; CHECK-LABEL: @alloca_bitcast_addrspacecast(
26; CHECK-NEXT:  entry:
27; CHECK-NEXT:    ret i64 [[X:%.*]]
28;
29entry:
30  %A = alloca [8 x i8]
31  %A.cast = bitcast [8 x i8]* %A to i64*
32  %B = addrspacecast i64* %A.cast to i64 addrspace(1)*
33  store i64 %X, i64 addrspace(1)* %B
34  %Z = load i64, i64 addrspace(1)* %B
35  ret i64 %Z
36}
37
38define i64 @alloca_addrspacecast_gep(i64 %X) {
39; CHECK-LABEL: @alloca_addrspacecast_gep(
40; CHECK-NEXT:  entry:
41; CHECK-NEXT:    ret i64 [[X:%.*]]
42;
43entry:
44  %A.as0 = alloca [256 x i8], align 4
45
46  %gepA.as0 = getelementptr [256 x i8], [256 x i8]* %A.as0, i16 0, i16 32
47  %gepA.as0.bc = bitcast i8* %gepA.as0 to i64*
48  store i64 %X, i64* %gepA.as0.bc, align 4
49
50  %A.as1 = addrspacecast [256 x i8]* %A.as0 to [256 x i8] addrspace(1)*
51  %gepA.as1 = getelementptr [256 x i8], [256 x i8] addrspace(1)* %A.as1, i16 0, i16 32
52  %gepA.as1.bc = bitcast i8 addrspace(1)* %gepA.as1 to i64 addrspace(1)*
53  %Z = load i64, i64 addrspace(1)* %gepA.as1.bc, align 4
54
55  ret i64 %Z
56}
57
58define i64 @alloca_gep_addrspacecast(i64 %X) {
59; CHECK-LABEL: @alloca_gep_addrspacecast(
60; CHECK-NEXT:  entry:
61; CHECK-NEXT:    ret i64 [[X:%.*]]
62;
63entry:
64  %A.as0 = alloca [256 x i8], align 4
65
66  %gepA.as0 = getelementptr [256 x i8], [256 x i8]* %A.as0, i16 0, i16 32
67  %gepA.as0.bc = bitcast i8* %gepA.as0 to i64*
68  store i64 %X, i64* %gepA.as0.bc, align 4
69
70  %gepA.as1.bc = addrspacecast i64* %gepA.as0.bc to i64 addrspace(1)*
71  %Z = load i64, i64 addrspace(1)* %gepA.as1.bc, align 4
72  ret i64 %Z
73}
74
75define i64 @alloca_gep_addrspacecast_gep(i64 %X) {
76; CHECK-LABEL: @alloca_gep_addrspacecast_gep(
77; CHECK-NEXT:  entry:
78; CHECK-NEXT:    ret i64 [[X:%.*]]
79;
80entry:
81  %A.as0 = alloca [256 x i8], align 4
82
83  %gepA.as0 = getelementptr [256 x i8], [256 x i8]* %A.as0, i16 0, i16 32
84  %gepA.as0.bc = bitcast i8* %gepA.as0 to i64*
85  store i64 %X, i64* %gepA.as0.bc, align 4
86
87
88  %gepB.as0 = getelementptr [256 x i8], [256 x i8]* %A.as0, i16 0, i16 16
89  %gepB.as1 = addrspacecast i8* %gepB.as0 to i8 addrspace(1)*
90  %gepC.as1 = getelementptr i8, i8 addrspace(1)* %gepB.as1, i16 16
91  %gepC.as1.bc = bitcast i8 addrspace(1)* %gepC.as1 to i64 addrspace(1)*
92  %Z = load i64, i64 addrspace(1)* %gepC.as1.bc, align 4
93
94  ret i64 %Z
95}
96
97define i64 @getAdjustedPtr_addrspacecast_gep([32 x i8]* %x) {
98; CHECK-LABEL: @getAdjustedPtr_addrspacecast_gep(
99; CHECK-NEXT:  entry:
100; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast [32 x i8]* [[X:%.*]] to i8 addrspace(1)*
101; CHECK-NEXT:    [[A_SROA_0_0_CAST1_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[CAST1]] to i64 addrspace(1)*
102; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_0_0_CAST1_SROA_CAST]], align 1
103; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_IDX:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[CAST1]], i16 8
104; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[A_SROA_2_0_CAST1_SROA_IDX]] to i64 addrspace(1)*
105; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_2_0_CAST1_SROA_CAST]], align 1
106; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
107;
108entry:
109  %a = alloca [32 x i8], align 8
110  %cast1 = addrspacecast [32 x i8]* %x to i8 addrspace(1)*
111  %cast2 = bitcast [32 x i8]* %a to i8*
112  call void @llvm.memcpy.p0i8.p1i8.i32(i8* %cast2, i8 addrspace(1)* %cast1, i32 16, i1 false)
113  %gep = getelementptr [32 x i8], [32 x i8]* %a, i32 0
114  %gep.bitcast = bitcast [32 x i8]* %gep to i64*
115  %val = load i64, i64* %gep.bitcast
116  ret i64 %val
117}
118
119define i64 @getAdjustedPtr_gep_addrspacecast([32 x i8]* %x) {
120; CHECK-LABEL: @getAdjustedPtr_gep_addrspacecast(
121; CHECK-NEXT:  entry:
122; CHECK-NEXT:    [[GEP_X:%.*]] = getelementptr [32 x i8], [32 x i8]* [[X:%.*]], i32 0, i32 16
123; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast i8* [[GEP_X]] to i8 addrspace(1)*
124; CHECK-NEXT:    [[A_SROA_0_0_CAST1_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[CAST1]] to i64 addrspace(1)*
125; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_0_0_CAST1_SROA_CAST]], align 1
126; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_IDX:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[CAST1]], i16 8
127; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[A_SROA_2_0_CAST1_SROA_IDX]] to i64 addrspace(1)*
128; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_2_0_CAST1_SROA_CAST]], align 1
129; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
130;
131entry:
132  %a = alloca [32 x i8], align 8
133  %gep.x = getelementptr [32 x i8], [32 x i8]* %x, i32 0, i32 16
134  %cast1 = addrspacecast i8* %gep.x to i8 addrspace(1)*
135
136  %cast2 = bitcast [32 x i8]* %a to i8*
137  call void @llvm.memcpy.p0i8.p1i8.i32(i8* %cast2, i8 addrspace(1)* %cast1, i32 16, i1 false)
138  %gep = getelementptr [32 x i8], [32 x i8]* %a, i32 0
139  %gep.bitcast = bitcast [32 x i8]* %gep to i64*
140  %val = load i64, i64* %gep.bitcast
141  ret i64 %val
142}
143
144define i64 @getAdjustedPtr_gep_addrspacecast_gep([32 x i8]* %x) {
145; CHECK-LABEL: @getAdjustedPtr_gep_addrspacecast_gep(
146; CHECK-NEXT:  entry:
147; CHECK-NEXT:    [[GEP0_X:%.*]] = getelementptr [32 x i8], [32 x i8]* [[X:%.*]], i32 0, i32 8
148; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast i8* [[GEP0_X]] to i8 addrspace(1)*
149; CHECK-NEXT:    [[A_SROA_0_0_GEP1_X_SROA_IDX:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[CAST1]], i16 8
150; CHECK-NEXT:    [[A_SROA_0_0_GEP1_X_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[A_SROA_0_0_GEP1_X_SROA_IDX]] to i64 addrspace(1)*
151; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_0_0_GEP1_X_SROA_CAST]], align 1
152; CHECK-NEXT:    [[A_SROA_2_0_GEP1_X_SROA_IDX:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[CAST1]], i16 16
153; CHECK-NEXT:    [[A_SROA_2_0_GEP1_X_SROA_CAST:%.*]] = bitcast i8 addrspace(1)* [[A_SROA_2_0_GEP1_X_SROA_IDX]] to i64 addrspace(1)*
154; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, i64 addrspace(1)* [[A_SROA_2_0_GEP1_X_SROA_CAST]], align 1
155; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
156;
157entry:
158  %a = alloca [32 x i8], align 8
159  %gep0.x = getelementptr [32 x i8], [32 x i8]* %x, i32 0, i32 8
160  %cast1 = addrspacecast i8* %gep0.x to i8 addrspace(1)*
161  %gep1.x = getelementptr i8, i8 addrspace(1)* %cast1, i32 8
162
163  %cast2 = bitcast [32 x i8]* %a to i8*
164  call void @llvm.memcpy.p0i8.p1i8.i32(i8* %cast2, i8 addrspace(1)* %gep1.x, i32 16, i1 false)
165  %gep = getelementptr [32 x i8], [32 x i8]* %a, i32 0
166  %gep.bitcast = bitcast [32 x i8]* %gep to i64*
167  %val = load i64, i64* %gep.bitcast
168  ret i64 %val
169}
170
171; Don't change the address space of a volatile operation
172define i64 @alloca_addrspacecast_bitcast_volatile_store(i64 %X) {
173; CHECK-LABEL: @alloca_addrspacecast_bitcast_volatile_store(
174; CHECK-NEXT:  entry:
175; CHECK-NEXT:    [[A:%.*]] = alloca [8 x i8]
176; CHECK-NEXT:    [[A_CAST:%.*]] = addrspacecast [8 x i8]* [[A]] to [8 x i8] addrspace(1)*
177; CHECK-NEXT:    [[B:%.*]] = bitcast [8 x i8] addrspace(1)* [[A_CAST]] to i64 addrspace(1)*
178; CHECK-NEXT:    store volatile i64 [[X:%.*]], i64 addrspace(1)* [[B]]
179; CHECK-NEXT:    [[Z:%.*]] = load i64, i64 addrspace(1)* [[B]]
180; CHECK-NEXT:    ret i64 [[Z]]
181;
182entry:
183  %A = alloca [8 x i8]
184  %A.cast = addrspacecast [8 x i8]* %A to [8 x i8] addrspace(1)*
185  %B = bitcast [8 x i8] addrspace(1)* %A.cast to i64 addrspace(1)*
186  store volatile i64 %X, i64 addrspace(1)* %B
187  %Z = load i64, i64 addrspace(1)* %B
188  ret i64 %Z
189}
190
191; Don't change the address space of a volatile operation
192define i64 @alloca_addrspacecast_bitcast_volatile_load(i64 %X) {
193; CHECK-LABEL: @alloca_addrspacecast_bitcast_volatile_load(
194; CHECK-NEXT:  entry:
195; CHECK-NEXT:    [[A:%.*]] = alloca [8 x i8]
196; CHECK-NEXT:    [[A_CAST:%.*]] = addrspacecast [8 x i8]* [[A]] to [8 x i8] addrspace(1)*
197; CHECK-NEXT:    [[B:%.*]] = bitcast [8 x i8] addrspace(1)* [[A_CAST]] to i64 addrspace(1)*
198; CHECK-NEXT:    store i64 [[X:%.*]], i64 addrspace(1)* [[B]]
199; CHECK-NEXT:    [[Z:%.*]] = load volatile i64, i64 addrspace(1)* [[B]]
200; CHECK-NEXT:    ret i64 [[Z]]
201;
202entry:
203  %A = alloca [8 x i8]
204  %A.cast = addrspacecast [8 x i8]* %A to [8 x i8] addrspace(1)*
205  %B = bitcast [8 x i8] addrspace(1)* %A.cast to i64 addrspace(1)*
206  store i64 %X, i64 addrspace(1)* %B
207  %Z = load volatile i64, i64 addrspace(1)* %B
208  ret i64 %Z
209}
210
211declare void @llvm.memset.p1i8.i32(i8 addrspace(1)* nocapture, i8, i32, i1) nounwind
212
213; Don't change the address space of a volatile operation
214define i32 @volatile_memset() {
215; CHECK-LABEL: @volatile_memset(
216; CHECK-NEXT:  entry:
217; CHECK-NEXT:    [[A:%.*]] = alloca [4 x i8]
218; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [4 x i8], [4 x i8]* [[A]], i32 0, i32 0
219; CHECK-NEXT:    [[ASC:%.*]] = addrspacecast i8* [[PTR]] to i8 addrspace(1)*
220; CHECK-NEXT:    call void @llvm.memset.p1i8.i32(i8 addrspace(1)* [[ASC]], i8 42, i32 4, i1 true)
221; CHECK-NEXT:    [[IPTR:%.*]] = bitcast i8* [[PTR]] to i32*
222; CHECK-NEXT:    [[VAL:%.*]] = load i32, i32* [[IPTR]]
223; CHECK-NEXT:    ret i32 [[VAL]]
224;
225entry:
226  %a = alloca [4 x i8]
227  %ptr = getelementptr [4 x i8], [4 x i8]* %a, i32 0, i32 0
228  %asc = addrspacecast i8* %ptr to i8 addrspace(1)*
229  call void @llvm.memset.p1i8.i32(i8 addrspace(1)* %asc, i8 42, i32 4, i1 true)
230  %iptr = bitcast i8* %ptr to i32*
231  %val = load i32, i32* %iptr
232  ret i32 %val
233}
234
235; Don't change the address space of a volatile operation
236define void @volatile_memcpy(i8* %src, i8* %dst) {
237; CHECK-LABEL: @volatile_memcpy(
238; CHECK-NEXT:  entry:
239; CHECK-NEXT:    [[A:%.*]] = alloca [4 x i8]
240; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [4 x i8], [4 x i8]* [[A]], i32 0, i32 0
241; CHECK-NEXT:    [[ASC:%.*]] = addrspacecast i8* [[PTR]] to i8 addrspace(1)*
242; CHECK-NEXT:    call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* [[ASC]], i8* [[SRC:%.*]], i32 4, i1 true), !tbaa !0
243; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p1i8.i32(i8* [[DST:%.*]], i8 addrspace(1)* [[ASC]], i32 4, i1 true), !tbaa !3
244; CHECK-NEXT:    ret void
245;
246entry:
247  %a = alloca [4 x i8]
248  %ptr = getelementptr [4 x i8], [4 x i8]* %a, i32 0, i32 0
249  %asc = addrspacecast i8* %ptr to i8 addrspace(1)*
250  call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* %asc, i8* %src, i32 4, i1 true), !tbaa !0
251  call void @llvm.memcpy.p0i8.p1i8.i32(i8* %dst, i8 addrspace(1)* %asc, i32 4, i1 true), !tbaa !3
252  ret void
253}
254
255define void @select_addrspacecast(i1 %a, i1 %b) {
256; CHECK-LABEL: @select_addrspacecast(
257; CHECK-NEXT:    ret void
258;
259  %c = alloca i64, align 8
260  %p.0.c = select i1 undef, i64* %c, i64* %c
261  %asc = addrspacecast i64* %p.0.c to i64 addrspace(1)*
262
263  %cond.in = select i1 undef, i64 addrspace(1)* %asc, i64 addrspace(1)* %asc
264  %cond = load i64, i64 addrspace(1)* %cond.in, align 8
265  ret void
266}
267
268define void @select_addrspacecast_const_op(i1 %a, i1 %b) {
269; CHECK-LABEL: @select_addrspacecast_const_op(
270; CHECK-NEXT:    [[C:%.*]] = alloca i64, align 8
271; CHECK-NEXT:    [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast i64* [[C]] to i64 addrspace(1)*
272; CHECK-NEXT:    [[COND_IN:%.*]] = select i1 undef, i64 addrspace(1)* [[C_0_ASC_SROA_CAST]], i64 addrspace(1)* null
273; CHECK-NEXT:    [[COND:%.*]] = load i64, i64 addrspace(1)* [[COND_IN]], align 8
274; CHECK-NEXT:    ret void
275;
276  %c = alloca i64, align 8
277  %p.0.c = select i1 undef, i64* %c, i64* %c
278  %asc = addrspacecast i64* %p.0.c to i64 addrspace(1)*
279
280  %cond.in = select i1 undef, i64 addrspace(1)* %asc, i64 addrspace(1)* null
281  %cond = load i64, i64 addrspace(1)* %cond.in, align 8
282  ret void
283}
284
285;; If this was external, we wouldn't be able to prove dereferenceability
286;; of the location.
287@gv = addrspace(1) global i64 zeroinitializer
288
289define void @select_addrspacecast_gv(i1 %a, i1 %b) {
290; CHECK-LABEL: @select_addrspacecast_gv(
291; CHECK-NEXT:    [[COND_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i64, i64 addrspace(1)* @gv, align 8
292; CHECK-NEXT:    [[COND_SROA_SPECULATED:%.*]] = select i1 undef, i64 undef, i64 [[COND_SROA_SPECULATE_LOAD_FALSE]]
293; CHECK-NEXT:    ret void
294;
295  %c = alloca i64, align 8
296  %p.0.c = select i1 undef, i64* %c, i64* %c
297  %asc = addrspacecast i64* %p.0.c to i64 addrspace(1)*
298
299  %cond.in = select i1 undef, i64 addrspace(1)* %asc, i64 addrspace(1)* @gv
300  %cond = load i64, i64 addrspace(1)* %cond.in, align 8
301  ret void
302}
303
304define i8 @select_addrspacecast_i8() {
305; CHECK-LABEL: @select_addrspacecast_i8(
306; CHECK-NEXT:    [[RET_SROA_SPECULATED:%.*]] = select i1 undef, i8 undef, i8 undef
307; CHECK-NEXT:    ret i8 [[RET_SROA_SPECULATED]]
308;
309  %a = alloca i8
310  %b = alloca i8
311
312  %a.ptr = addrspacecast i8* %a to i8 addrspace(1)*
313  %b.ptr = addrspacecast i8* %b to i8 addrspace(1)*
314
315  %ptr = select i1 undef, i8 addrspace(1)* %a.ptr, i8 addrspace(1)* %b.ptr
316  %ret = load i8, i8 addrspace(1)* %ptr
317  ret i8 %ret
318}
319
320!0 = !{!1, !1, i64 0, i64 1}
321!1 = !{!2, i64 1, !"type_0"}
322!2 = !{!"root"}
323!3 = !{!4, !4, i64 0, i64 1}
324!4 = !{!2, i64 1, !"type_3"}
325