xref: /llvm-project/llvm/test/Transforms/SROA/addrspacecast.ll (revision 4f7e5d22060e8a89237ffb93c3e7be6e92fee8fe)
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
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.p0.p1.i32(ptr nocapture writeonly, ptr addrspace(1) nocapture readonly, i32, i1 immarg) #0
8declare void @llvm.memcpy.p1.p0.i32(ptr addrspace(1) nocapture writeonly, ptr 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 ptr %A to ptr addrspace(1)
18  store i64 %X, ptr addrspace(1) %A.cast
19  %Z = load i64, ptr addrspace(1) %A.cast
20  ret i64 %Z
21}
22
23define i64 @alloca_bitcast_addrspacecast(i64 %X) {
24; CHECK-LABEL: @alloca_bitcast_addrspacecast(
25; CHECK-NEXT:  entry:
26; CHECK-NEXT:    ret i64 [[X:%.*]]
27;
28entry:
29  %A = alloca [8 x i8]
30  %B = addrspacecast ptr %A to ptr addrspace(1)
31  store i64 %X, ptr addrspace(1) %B
32  %Z = load i64, ptr addrspace(1) %B
33  ret i64 %Z
34}
35
36define i64 @alloca_addrspacecast_gep(i64 %X) {
37; CHECK-LABEL: @alloca_addrspacecast_gep(
38; CHECK-NEXT:  entry:
39; CHECK-NEXT:    ret i64 [[X:%.*]]
40;
41entry:
42  %A.as0 = alloca [256 x i8], align 4
43
44  %gepA.as0 = getelementptr [256 x i8], ptr %A.as0, i16 0, i16 32
45  store i64 %X, ptr %gepA.as0, align 4
46
47  %A.as1 = addrspacecast ptr %A.as0 to ptr addrspace(1)
48  %gepA.as1 = getelementptr [256 x i8], ptr addrspace(1) %A.as1, i16 0, i16 32
49  %Z = load i64, ptr addrspace(1) %gepA.as1, align 4
50
51  ret i64 %Z
52}
53
54define i64 @alloca_gep_addrspacecast(i64 %X) {
55; CHECK-LABEL: @alloca_gep_addrspacecast(
56; CHECK-NEXT:  entry:
57; CHECK-NEXT:    ret i64 [[X:%.*]]
58;
59entry:
60  %A.as0 = alloca [256 x i8], align 4
61
62  %gepA.as0 = getelementptr [256 x i8], ptr %A.as0, i16 0, i16 32
63  store i64 %X, ptr %gepA.as0, align 4
64
65  %gepA.as1.bc = addrspacecast ptr %gepA.as0 to ptr addrspace(1)
66  %Z = load i64, ptr addrspace(1) %gepA.as1.bc, align 4
67  ret i64 %Z
68}
69
70define i64 @alloca_gep_addrspacecast_gep(i64 %X) {
71; CHECK-LABEL: @alloca_gep_addrspacecast_gep(
72; CHECK-NEXT:  entry:
73; CHECK-NEXT:    ret i64 [[X:%.*]]
74;
75entry:
76  %A.as0 = alloca [256 x i8], align 4
77
78  %gepA.as0 = getelementptr [256 x i8], ptr %A.as0, i16 0, i16 32
79  store i64 %X, ptr %gepA.as0, align 4
80
81
82  %gepB.as0 = getelementptr [256 x i8], ptr %A.as0, i16 0, i16 16
83  %gepB.as1 = addrspacecast ptr %gepB.as0 to ptr addrspace(1)
84  %gepC.as1 = getelementptr i8, ptr addrspace(1) %gepB.as1, i16 16
85  %Z = load i64, ptr addrspace(1) %gepC.as1, align 4
86
87  ret i64 %Z
88}
89
90define i64 @getAdjustedPtr_addrspacecast_gep(ptr %x) {
91; CHECK-LABEL: @getAdjustedPtr_addrspacecast_gep(
92; CHECK-NEXT:  entry:
93; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast ptr [[X:%.*]] to ptr addrspace(1)
94; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[CAST1]], align 1
95; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[CAST1]], i16 8
96; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[A_SROA_2_0_CAST1_SROA_IDX]], align 1
97; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
98;
99entry:
100  %a = alloca [32 x i8], align 8
101  %cast1 = addrspacecast ptr %x to ptr addrspace(1)
102  call void @llvm.memcpy.p0.p1.i32(ptr %a, ptr addrspace(1) %cast1, i32 16, i1 false)
103  %val = load i64, ptr %a
104  ret i64 %val
105}
106
107define i64 @getAdjustedPtr_gep_addrspacecast(ptr %x) {
108; CHECK-LABEL: @getAdjustedPtr_gep_addrspacecast(
109; CHECK-NEXT:  entry:
110; CHECK-NEXT:    [[GEP_X:%.*]] = getelementptr [32 x i8], ptr [[X:%.*]], i32 0, i32 16
111; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast ptr [[GEP_X]] to ptr addrspace(1)
112; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[CAST1]], align 1
113; CHECK-NEXT:    [[A_SROA_2_0_CAST1_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[CAST1]], i16 8
114; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[A_SROA_2_0_CAST1_SROA_IDX]], align 1
115; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
116;
117entry:
118  %a = alloca [32 x i8], align 8
119  %gep.x = getelementptr [32 x i8], ptr %x, i32 0, i32 16
120  %cast1 = addrspacecast ptr %gep.x to ptr addrspace(1)
121
122  call void @llvm.memcpy.p0.p1.i32(ptr %a, ptr addrspace(1) %cast1, i32 16, i1 false)
123  %val = load i64, ptr %a
124  ret i64 %val
125}
126
127define i64 @getAdjustedPtr_gep_addrspacecast_gep(ptr %x) {
128; CHECK-LABEL: @getAdjustedPtr_gep_addrspacecast_gep(
129; CHECK-NEXT:  entry:
130; CHECK-NEXT:    [[GEP0_X:%.*]] = getelementptr [32 x i8], ptr [[X:%.*]], i32 0, i32 8
131; CHECK-NEXT:    [[CAST1:%.*]] = addrspacecast ptr [[GEP0_X]] to ptr addrspace(1)
132; CHECK-NEXT:    [[GEP1_X:%.*]] = getelementptr i8, ptr addrspace(1) [[CAST1]], i32 8
133; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[GEP1_X]], align 1
134; CHECK-NEXT:    [[A_SROA_2_0_GEP1_X_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[GEP1_X]], i16 8
135; CHECK-NEXT:    [[A_SROA_2_0_COPYLOAD:%.*]] = load i64, ptr addrspace(1) [[A_SROA_2_0_GEP1_X_SROA_IDX]], align 1
136; CHECK-NEXT:    ret i64 [[A_SROA_0_0_COPYLOAD]]
137;
138entry:
139  %a = alloca [32 x i8], align 8
140  %gep0.x = getelementptr [32 x i8], ptr %x, i32 0, i32 8
141  %cast1 = addrspacecast ptr %gep0.x to ptr addrspace(1)
142  %gep1.x = getelementptr i8, ptr addrspace(1) %cast1, i32 8
143
144  call void @llvm.memcpy.p0.p1.i32(ptr %a, ptr addrspace(1) %gep1.x, i32 16, i1 false)
145  %val = load i64, ptr %a
146  ret i64 %val
147}
148
149; Don't change the address space of a volatile operation
150define i64 @alloca_addrspacecast_bitcast_volatile_store(i64 %X) {
151; CHECK-LABEL: @alloca_addrspacecast_bitcast_volatile_store(
152; CHECK-NEXT:  entry:
153; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i64, align 8
154; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr [[A_SROA_0]] to ptr addrspace(1)
155; CHECK-NEXT:    store volatile i64 [[X:%.*]], ptr addrspace(1) [[TMP0]], align 8
156; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_0_Z:%.*]] = load i64, ptr [[A_SROA_0]], align 8
157; CHECK-NEXT:    ret i64 [[A_SROA_0_0_A_SROA_0_0_Z]]
158;
159entry:
160  %A = alloca [8 x i8]
161  %A.cast = addrspacecast ptr %A to ptr addrspace(1)
162  store volatile i64 %X, ptr addrspace(1) %A.cast
163  %Z = load i64, ptr addrspace(1) %A.cast
164  ret i64 %Z
165}
166
167%struct = type { [256 x i8], i32 }
168
169define i65 @volatile_store_addrspacecast_slice(i65 %X, i16 %idx) {
170; CHECK-LABEL: @volatile_store_addrspacecast_slice(
171; CHECK-NEXT:  entry:
172; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca [9 x i8], align 4
173; CHECK-NEXT:    [[A_SROA_1:%.*]] = alloca [9 x i8], align 8
174; CHECK-NEXT:    [[A_SROA_1_0_GEPB_SROA_CAST:%.*]] = addrspacecast ptr [[A_SROA_1]] to ptr addrspace(1)
175; CHECK-NEXT:    store volatile i65 [[X:%.*]], ptr addrspace(1) [[A_SROA_1_0_GEPB_SROA_CAST]], align 8
176; CHECK-NEXT:    br label [[L2:%.*]]
177; CHECK:       L2:
178; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_20_Z:%.*]] = load i65, ptr [[A_SROA_0]], align 4
179; CHECK-NEXT:    ret i65 [[A_SROA_0_0_A_SROA_0_20_Z]]
180;
181entry:
182  %A = alloca %struct
183  %B = addrspacecast ptr %A to ptr addrspace(1)
184  %gepA = getelementptr %struct, ptr %A, i32 0, i32 0, i16 20
185  %gepB = getelementptr i65, ptr addrspace(1) %B, i16 6
186  store volatile i65 %X, ptr addrspace(1) %gepB, align 1
187  br label %L2
188
189L2:
190  %Z = load i65, ptr %gepA, align 1
191  ret i65 %Z
192}
193
194; Don't change the address space of a volatile operation
195define i64 @alloca_addrspacecast_bitcast_volatile_load(i64 %X) {
196; CHECK-LABEL: @alloca_addrspacecast_bitcast_volatile_load(
197; CHECK-NEXT:  entry:
198; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i64, align 8
199; CHECK-NEXT:    store i64 [[X:%.*]], ptr [[A_SROA_0]], align 8
200; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr [[A_SROA_0]] to ptr addrspace(1)
201; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_0_Z:%.*]] = load volatile i64, ptr addrspace(1) [[TMP0]], align 8
202; CHECK-NEXT:    ret i64 [[A_SROA_0_0_A_SROA_0_0_Z]]
203;
204entry:
205  %A = alloca [8 x i8]
206  %A.cast = addrspacecast ptr %A to ptr addrspace(1)
207  store i64 %X, ptr addrspace(1) %A.cast
208  %Z = load volatile i64, ptr addrspace(1) %A.cast
209  ret i64 %Z
210}
211
212declare void @llvm.memset.p1.i32(ptr addrspace(1) nocapture, i8, i32, i1) nounwind
213
214define i65 @volatile_load_addrspacecast_slice(i65 %X, i16 %idx) {
215; CHECK-LABEL: @volatile_load_addrspacecast_slice(
216; CHECK-NEXT:  entry:
217; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca [9 x i8], align 4
218; CHECK-NEXT:    [[A_SROA_1:%.*]] = alloca [9 x i8], align 8
219; CHECK-NEXT:    [[A_SROA_1_0_GEPB_SROA_CAST:%.*]] = addrspacecast ptr [[A_SROA_1]] to ptr addrspace(1)
220; CHECK-NEXT:    store i65 [[X:%.*]], ptr addrspace(1) [[A_SROA_1_0_GEPB_SROA_CAST]], align 8
221; CHECK-NEXT:    br label [[L2:%.*]]
222; CHECK:       L2:
223; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_20_Z:%.*]] = load volatile i65, ptr [[A_SROA_0]], align 4
224; CHECK-NEXT:    ret i65 [[A_SROA_0_0_A_SROA_0_20_Z]]
225;
226entry:
227  %A = alloca %struct
228  %B = addrspacecast ptr %A to ptr addrspace(1)
229  %gepA = getelementptr %struct, ptr %A, i32 0, i32 0, i16 20
230  %gepB = getelementptr i65, ptr addrspace(1) %B, i16 6
231  store i65 %X, ptr addrspace(1) %gepB, align 1
232  br label %L2
233
234L2:
235  %Z = load volatile i65, ptr %gepA, align 1
236  ret i65 %Z
237}
238
239; Don't change the address space of a volatile operation
240define i32 @volatile_memset() {
241; CHECK-LABEL: @volatile_memset(
242; CHECK-NEXT:  entry:
243; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
244; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr [[A_SROA_0]] to ptr addrspace(1)
245; CHECK-NEXT:    store volatile i32 707406378, ptr addrspace(1) [[TMP0]], align 4
246; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_0_VAL:%.*]] = load i32, ptr [[A_SROA_0]], align 4
247; CHECK-NEXT:    ret i32 [[A_SROA_0_0_A_SROA_0_0_VAL]]
248;
249entry:
250  %a = alloca [4 x i8]
251  %asc = addrspacecast ptr %a to ptr addrspace(1)
252  call void @llvm.memset.p1.i32(ptr addrspace(1) %asc, i8 42, i32 4, i1 true)
253  %val = load i32, ptr %a
254  ret i32 %val
255}
256
257; Don't change the address space of a volatile operation
258define void @volatile_memcpy(ptr %src, ptr %dst) {
259; CHECK-LABEL: @volatile_memcpy(
260; CHECK-NEXT:  entry:
261; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
262; CHECK-NEXT:    [[A_SROA_0_0_COPYLOAD:%.*]] = load volatile i32, ptr [[SRC:%.*]], align 1, !tbaa [[TBAA0:![0-9]+]]
263; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr [[A_SROA_0]] to ptr addrspace(1)
264; CHECK-NEXT:    store volatile i32 [[A_SROA_0_0_COPYLOAD]], ptr addrspace(1) [[TMP0]], align 4, !tbaa [[TBAA0]]
265; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast ptr [[A_SROA_0]] to ptr addrspace(1)
266; CHECK-NEXT:    [[A_SROA_0_0_A_SROA_0_0_COPYLOAD1:%.*]] = load volatile i32, ptr addrspace(1) [[TMP1]], align 4, !tbaa [[TBAA3:![0-9]+]]
267; CHECK-NEXT:    store volatile i32 [[A_SROA_0_0_A_SROA_0_0_COPYLOAD1]], ptr [[DST:%.*]], align 1, !tbaa [[TBAA3]]
268; CHECK-NEXT:    ret void
269;
270entry:
271  %a = alloca [4 x i8]
272  %asc = addrspacecast ptr %a to ptr addrspace(1)
273  call void @llvm.memcpy.p1.p0.i32(ptr addrspace(1) %asc, ptr %src, i32 4, i1 true), !tbaa !0
274  call void @llvm.memcpy.p0.p1.i32(ptr %dst, ptr addrspace(1) %asc, i32 4, i1 true), !tbaa !3
275  ret void
276}
277
278define void @select_addrspacecast(i1 %a, i1 %b) {
279; CHECK-LABEL: @select_addrspacecast(
280; CHECK-NEXT:    ret void
281;
282  %c = alloca i64, align 8
283  %p.0.c = select i1 %a, ptr %c, ptr %c
284  %asc = addrspacecast ptr %p.0.c to ptr addrspace(1)
285
286  %cond.in = select i1 %b, ptr addrspace(1) %asc, ptr addrspace(1) %asc
287  %cond = load i64, ptr addrspace(1) %cond.in, align 8
288  ret void
289}
290
291define void @select_addrspacecast_const_op(i1 %a, i1 %b) {
292; CHECK-PRESERVE-CFG-LABEL: @select_addrspacecast_const_op(
293; CHECK-PRESERVE-CFG-NEXT:    [[C:%.*]] = alloca i64, align 8
294; CHECK-PRESERVE-CFG-NEXT:    [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast ptr [[C]] to ptr addrspace(1)
295; CHECK-PRESERVE-CFG-NEXT:    [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr addrspace(1) [[C_0_ASC_SROA_CAST]], ptr addrspace(1) null
296; CHECK-PRESERVE-CFG-NEXT:    [[COND:%.*]] = load i64, ptr addrspace(1) [[COND_IN]], align 8
297; CHECK-PRESERVE-CFG-NEXT:    ret void
298;
299; CHECK-MODIFY-CFG-LABEL: @select_addrspacecast_const_op(
300; CHECK-MODIFY-CFG-NEXT:    br i1 [[B:%.*]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]]
301; CHECK-MODIFY-CFG:       .else:
302; CHECK-MODIFY-CFG-NEXT:    [[COND_ELSE_VAL:%.*]] = load i64, ptr addrspace(1) null, align 8
303; CHECK-MODIFY-CFG-NEXT:    br label [[DOTCONT]]
304; CHECK-MODIFY-CFG:       .cont:
305; CHECK-MODIFY-CFG-NEXT:    [[COND:%.*]] = phi i64 [ undef, [[TMP0:%.*]] ], [ [[COND_ELSE_VAL]], [[DOTELSE]] ]
306; CHECK-MODIFY-CFG-NEXT:    ret void
307;
308  %c = alloca i64, align 8
309  %p.0.c = select i1 %a, ptr %c, ptr %c
310  %asc = addrspacecast ptr %p.0.c to ptr addrspace(1)
311
312  %cond.in = select i1 %b, ptr addrspace(1) %asc, ptr addrspace(1) null
313  %cond = load i64, ptr addrspace(1) %cond.in, align 8
314  ret void
315}
316
317;; If this was external, we wouldn't be able to prove dereferenceability
318;; of the location.
319@gv = addrspace(1) global i64 zeroinitializer
320
321define void @select_addrspacecast_gv(i1 %a, i1 %b) {
322; CHECK-LABEL: @select_addrspacecast_gv(
323; CHECK-NEXT:    [[COND_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i64, ptr addrspace(1) @gv, align 8
324; CHECK-NEXT:    [[COND_SROA_SPECULATED:%.*]] = select i1 [[B:%.*]], i64 undef, i64 [[COND_SROA_SPECULATE_LOAD_FALSE]]
325; CHECK-NEXT:    ret void
326;
327  %c = alloca i64, align 8
328  %p.0.c = select i1 %a, ptr %c, ptr %c
329  %asc = addrspacecast ptr %p.0.c to ptr addrspace(1)
330
331  %cond.in = select i1 %b, ptr addrspace(1) %asc, ptr addrspace(1) @gv
332  %cond = load i64, ptr addrspace(1) %cond.in, align 8
333  ret void
334}
335
336define void @select_addrspacecast_gv_constexpr(i1 %a, i1 %b) {
337; CHECK-LABEL: @select_addrspacecast_gv_constexpr(
338; CHECK-NEXT:    [[COND_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i64, ptr addrspace(2) addrspacecast (ptr addrspace(1) @gv to ptr addrspace(2)), align 8
339; CHECK-NEXT:    [[COND_SROA_SPECULATED:%.*]] = select i1 [[B:%.*]], i64 undef, i64 [[COND_SROA_SPECULATE_LOAD_FALSE]]
340; CHECK-NEXT:    ret void
341;
342  %c = alloca i64, align 8
343  %p.0.c = select i1 %a, ptr %c, ptr %c
344  %asc = addrspacecast ptr %p.0.c to ptr addrspace(2)
345
346  %cond.in = select i1 %b, ptr addrspace(2) %asc, ptr addrspace(2) addrspacecast (ptr addrspace(1) @gv to ptr addrspace(2))
347  %cond = load i64, ptr addrspace(2) %cond.in, align 8
348  ret void
349}
350
351define i8 @select_addrspacecast_i8(i1 %c) {
352; CHECK-LABEL: @select_addrspacecast_i8(
353; CHECK-NEXT:    [[RET_SROA_SPECULATED:%.*]] = select i1 [[C:%.*]], i8 undef, i8 undef
354; CHECK-NEXT:    ret i8 [[RET_SROA_SPECULATED]]
355;
356  %a = alloca i8
357  %b = alloca i8
358
359  %a.ptr = addrspacecast ptr %a to ptr addrspace(1)
360  %b.ptr = addrspacecast ptr %b to ptr addrspace(1)
361
362  %ptr = select i1 %c, ptr addrspace(1) %a.ptr, ptr addrspace(1) %b.ptr
363  %ret = load i8, ptr addrspace(1) %ptr
364  ret i8 %ret
365}
366
367!0 = !{!1, !1, i64 0, i64 1}
368!1 = !{!2, i64 1, !"type_0"}
369!2 = !{!"root"}
370!3 = !{!4, !4, i64 0, i64 1}
371!4 = !{!2, i64 1, !"type_3"}
372