Skip to content

Commit eedffc9

Browse files
committed
[SROA] Escaping readonly nocapture tests. NFC
1 parent 712ef7d commit eedffc9

File tree

2 files changed

+327
-4
lines changed

2 files changed

+327
-4
lines changed

llvm/test/Transforms/SROA/non-capturing-call-readonly.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,12 +364,12 @@ define i32 @alloca_used_in_maybe_throwing_call(ptr %data, i64 %n) personality pt
364364
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
365365
; CHECK: exit:
366366
; CHECK-NEXT: [[I0:%.*]] = invoke i32 @user_of_alloca(ptr [[RETVAL]])
367-
; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[UW:%.*]]
367+
; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[UW:%.*]]
368368
; CHECK: cont:
369369
; CHECK-NEXT: br label [[END:%.*]]
370370
; CHECK: uw:
371371
; CHECK-NEXT: [[I1:%.*]] = landingpad { ptr, i32 }
372-
; CHECK-NEXT: catch ptr null
372+
; CHECK-NEXT: catch ptr null
373373
; CHECK-NEXT: br label [[END]]
374374
; CHECK: end:
375375
; CHECK-NEXT: [[I2:%.*]] = load i32, ptr [[RETVAL]], align 4
@@ -424,10 +424,10 @@ define i32 @alloca_used_in_maybe_throwing_call_with_same_dests(ptr %data, i64 %n
424424
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
425425
; CHECK: exit:
426426
; CHECK-NEXT: [[I0:%.*]] = invoke i32 @user_of_alloca(ptr [[RETVAL]])
427-
; CHECK-NEXT: to label [[END:%.*]] unwind label [[UW:%.*]]
427+
; CHECK-NEXT: to label [[END:%.*]] unwind label [[UW:%.*]]
428428
; CHECK: uw:
429429
; CHECK-NEXT: [[I1:%.*]] = landingpad { ptr, i32 }
430-
; CHECK-NEXT: catch ptr null
430+
; CHECK-NEXT: catch ptr null
431431
; CHECK-NEXT: br label [[END]]
432432
; CHECK: end:
433433
; CHECK-NEXT: [[I2:%.*]] = load i32, ptr [[RETVAL]], align 4
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes=sroa -S | FileCheck %s
3+
4+
declare void @callee(ptr nocapture readonly %p)
5+
6+
define i32 @simple() {
7+
; CHECK-LABEL: @simple(
8+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
9+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
10+
; CHECK-NEXT: call void @callee(ptr [[A]])
11+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
12+
; CHECK-NEXT: ret i32 [[L1]]
13+
;
14+
%a = alloca i32
15+
store i32 0, ptr %a
16+
call void @callee(ptr %a)
17+
%l1 = load i32, ptr %a
18+
ret i32 %l1
19+
}
20+
21+
define i32 @smallbig() {
22+
; CHECK-LABEL: @smallbig(
23+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
24+
; CHECK-NEXT: store i8 0, ptr [[A]], align 1
25+
; CHECK-NEXT: call void @callee(ptr [[A]])
26+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
27+
; CHECK-NEXT: ret i32 [[L1]]
28+
;
29+
%a = alloca i32
30+
store i8 0, ptr %a
31+
call void @callee(ptr %a)
32+
%l1 = load i32, ptr %a
33+
ret i32 %l1
34+
}
35+
36+
define i32 @twoalloc() {
37+
; CHECK-LABEL: @twoalloc(
38+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
39+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
40+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
41+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
42+
; CHECK-NEXT: call void @callee(ptr [[A]])
43+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
44+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
45+
; CHECK-NEXT: ret i32 [[L2]]
46+
;
47+
%a = alloca {i32, i32}
48+
store i32 0, ptr %a
49+
%b = getelementptr i32, ptr %a, i32 1
50+
store i32 1, ptr %b
51+
call void @callee(ptr %a)
52+
%l1 = load i32, ptr %a
53+
%l2 = load i32, ptr %b
54+
ret i32 %l2
55+
}
56+
57+
define i32 @twostore() {
58+
; CHECK-LABEL: @twostore(
59+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
60+
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
61+
; CHECK-NEXT: call void @callee(ptr [[A]])
62+
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
63+
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[A]], align 4
64+
; CHECK-NEXT: ret i32 [[L]]
65+
;
66+
%a = alloca i32
67+
store i32 1, ptr %a
68+
call void @callee(ptr %a)
69+
store i32 2, ptr %a
70+
%l = load i32, ptr %a
71+
ret i32 %l
72+
}
73+
74+
define float @differenttype() {
75+
; CHECK-LABEL: @differenttype(
76+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
77+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
78+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
79+
; CHECK-NEXT: call void @callee(ptr [[A]])
80+
; CHECK-NEXT: [[L2:%.*]] = load float, ptr [[B]], align 4
81+
; CHECK-NEXT: ret float [[L2]]
82+
;
83+
%a = alloca {i32, i32}
84+
%b = getelementptr i32, ptr %a, i32 1
85+
store i32 1, ptr %b
86+
call void @callee(ptr %a)
87+
%l2 = load float, ptr %b
88+
ret float %l2
89+
}
90+
91+
define i32 @twoalloc_store64(i64 %x) {
92+
; CHECK-LABEL: @twoalloc_store64(
93+
; CHECK-NEXT: [[A:%.*]] = alloca i64, align 8
94+
; CHECK-NEXT: store i64 [[X:%.*]], ptr [[A]], align 4
95+
; CHECK-NEXT: call void @callee(ptr [[A]])
96+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
97+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
98+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
99+
; CHECK-NEXT: ret i32 [[L2]]
100+
;
101+
%a = alloca i64
102+
store i64 %x, ptr %a
103+
call void @callee(ptr %a)
104+
%l1 = load i32, ptr %a
105+
%b = getelementptr i32, ptr %a, i32 1
106+
%l2 = load i32, ptr %b
107+
ret i32 %l2
108+
}
109+
110+
define i32 @twocalls() {
111+
; CHECK-LABEL: @twocalls(
112+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
113+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
114+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
115+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
116+
; CHECK-NEXT: call void @callee(ptr [[A]])
117+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
118+
; CHECK-NEXT: call void @callee(ptr [[A]])
119+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
120+
; CHECK-NEXT: ret i32 [[L2]]
121+
;
122+
%a = alloca {i32, i32}
123+
store i32 0, ptr %a
124+
%b = getelementptr i32, ptr %a, i32 1
125+
store i32 1, ptr %b
126+
call void @callee(ptr %a)
127+
%l1 = load i32, ptr %a
128+
call void @callee(ptr %a)
129+
%l2 = load i32, ptr %b
130+
ret i32 %l2
131+
}
132+
133+
define i32 @volatile() {
134+
; CHECK-LABEL: @volatile(
135+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
136+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
137+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
138+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
139+
; CHECK-NEXT: call void @callee(ptr [[A]])
140+
; CHECK-NEXT: [[L1:%.*]] = load volatile i32, ptr [[A]], align 4
141+
; CHECK-NEXT: [[L2:%.*]] = load volatile i32, ptr [[B]], align 4
142+
; CHECK-NEXT: ret i32 [[L2]]
143+
;
144+
%a = alloca {i32, i32}
145+
store i32 0, ptr %a
146+
%b = getelementptr i32, ptr %a, i32 1
147+
store i32 1, ptr %b
148+
call void @callee(ptr %a)
149+
%l1 = load volatile i32, ptr %a
150+
%l2 = load volatile i32, ptr %b
151+
ret i32 %l2
152+
}
153+
154+
define i32 @notdominating() {
155+
; CHECK-LABEL: @notdominating(
156+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
157+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
158+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
159+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
160+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
161+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
162+
; CHECK-NEXT: call void @callee(ptr [[A]])
163+
; CHECK-NEXT: ret i32 [[L2]]
164+
;
165+
%a = alloca {i32, i32}
166+
%b = getelementptr i32, ptr %a, i32 1
167+
%l1 = load i32, ptr %a
168+
%l2 = load i32, ptr %b
169+
store i32 0, ptr %a
170+
store i32 1, ptr %b
171+
call void @callee(ptr %a)
172+
ret i32 %l2
173+
}
174+
175+
declare void @callee_notreadonly(ptr %p)
176+
define i32 @notreadonly() {
177+
; CHECK-LABEL: @notreadonly(
178+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
179+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
180+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
181+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
182+
; CHECK-NEXT: call void @callee_notreadonly(ptr [[A]])
183+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
184+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
185+
; CHECK-NEXT: ret i32 [[L2]]
186+
;
187+
%a = alloca {i32, i32}
188+
store i32 0, ptr %a
189+
%b = getelementptr i32, ptr %a, i32 1
190+
store i32 1, ptr %b
191+
call void @callee_notreadonly(ptr %a)
192+
%l1 = load i32, ptr %a
193+
%l2 = load i32, ptr %b
194+
ret i32 %l2
195+
}
196+
197+
declare void @callee_multiuse(ptr nocapture readonly %p, ptr nocapture readonly %q)
198+
define i32 @multiuse() {
199+
; CHECK-LABEL: @multiuse(
200+
; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8
201+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
202+
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
203+
; CHECK-NEXT: store i32 1, ptr [[B]], align 4
204+
; CHECK-NEXT: call void @callee_multiuse(ptr [[A]], ptr [[A]])
205+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
206+
; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4
207+
; CHECK-NEXT: ret i32 [[L2]]
208+
;
209+
%a = alloca {i32, i32}
210+
store i32 0, ptr %a
211+
%b = getelementptr i32, ptr %a, i32 1
212+
store i32 1, ptr %b
213+
call void @callee_multiuse(ptr %a, ptr %a)
214+
%l1 = load i32, ptr %a
215+
%l2 = load i32, ptr %b
216+
ret i32 %l2
217+
}
218+
219+
define i32 @memcpyed(ptr %src) {
220+
; CHECK-LABEL: @memcpyed(
221+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
222+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
223+
; CHECK-NEXT: call void @callee(ptr [[A]])
224+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 4, i1 false)
225+
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4
226+
; CHECK-NEXT: ret i32 [[L1]]
227+
;
228+
%a = alloca i32
229+
store i32 0, ptr %a
230+
call void @callee(ptr %a)
231+
call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 4, i1 false)
232+
%l1 = load i32, ptr %a
233+
ret i32 %l1
234+
}
235+
236+
define ptr @memcpyedsplit(ptr %src) {
237+
; CHECK-LABEL: @memcpyedsplit(
238+
; CHECK-NEXT: [[A:%.*]] = alloca { i64, i64 }, align 8
239+
; CHECK-NEXT: store i8 1, ptr [[A]], align 1
240+
; CHECK-NEXT: [[B:%.*]] = getelementptr i64, ptr [[A]], i32 1
241+
; CHECK-NEXT: store ptr null, ptr [[B]], align 8
242+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 16, i1 false)
243+
; CHECK-NEXT: call void @callee(ptr [[A]])
244+
; CHECK-NEXT: [[L1:%.*]] = load ptr, ptr [[B]], align 8
245+
; CHECK-NEXT: ret ptr [[L1]]
246+
;
247+
%a = alloca { i64, i64 }
248+
store i8 1, ptr %a
249+
%b = getelementptr i64, ptr %a, i32 1
250+
store ptr null, ptr %b
251+
call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 16, i1 false)
252+
call void @callee(ptr %a)
253+
%l1 = load ptr, ptr %b
254+
ret ptr %l1
255+
}
256+
257+
; This struct contains padding bits. The load should not be replaced by poison.
258+
%struct.LoadImmediateInfo = type { i32 }
259+
define void @incompletestruct(i1 %b, i1 %c) {
260+
; CHECK-LABEL: @incompletestruct(
261+
; CHECK-NEXT: entry:
262+
; CHECK-NEXT: [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4
263+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[LII]])
264+
; CHECK-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[LII]], align 4
265+
; CHECK-NEXT: [[BF_CLEAR4:%.*]] = and i32 [[BF_LOAD]], -262144
266+
; CHECK-NEXT: [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072
267+
; CHECK-NEXT: [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]
268+
; CHECK-NEXT: store i32 [[BF_SET12]], ptr [[LII]], align 4
269+
; CHECK-NEXT: call void @callee(ptr [[LII]])
270+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[LII]])
271+
; CHECK-NEXT: ret void
272+
;
273+
entry:
274+
%LII = alloca %struct.LoadImmediateInfo, align 4
275+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %LII)
276+
%bf.load = load i32, ptr %LII, align 4
277+
%bf.clear4 = and i32 %bf.load, -262144
278+
%bf.set5 = select i1 %b, i32 196608, i32 131072
279+
%bf.set12 = or disjoint i32 %bf.set5, %bf.clear4
280+
store i32 %bf.set12, ptr %LII, align 4
281+
call void @callee(ptr %LII)
282+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %LII)
283+
ret void
284+
}
285+
286+
define void @incompletestruct_bb(i1 %b, i1 %c) {
287+
; CHECK-LABEL: @incompletestruct_bb(
288+
; CHECK-NEXT: entry:
289+
; CHECK-NEXT: [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4
290+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
291+
; CHECK: if.then:
292+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[LII]])
293+
; CHECK-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[LII]], align 4
294+
; CHECK-NEXT: [[BF_CLEAR4:%.*]] = and i32 [[BF_LOAD]], -262144
295+
; CHECK-NEXT: [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072
296+
; CHECK-NEXT: [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]
297+
; CHECK-NEXT: store i32 [[BF_SET12]], ptr [[LII]], align 4
298+
; CHECK-NEXT: call void @callee(ptr [[LII]])
299+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[LII]])
300+
; CHECK-NEXT: br label [[IF_END]]
301+
; CHECK: if.end:
302+
; CHECK-NEXT: ret void
303+
;
304+
entry:
305+
%LII = alloca %struct.LoadImmediateInfo, align 4
306+
br i1 %c, label %if.then, label %if.end
307+
308+
if.then: ; preds = %entry
309+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %LII)
310+
%bf.load = load i32, ptr %LII, align 4
311+
%bf.clear4 = and i32 %bf.load, -262144
312+
%bf.set5 = select i1 %b, i32 196608, i32 131072
313+
%bf.set12 = or disjoint i32 %bf.set5, %bf.clear4
314+
store i32 %bf.set12, ptr %LII, align 4
315+
call void @callee(ptr %LII)
316+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %LII)
317+
br label %if.end
318+
319+
if.end: ; preds = %if.then, %entry
320+
ret void
321+
}
322+
323+
declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)

0 commit comments

Comments
 (0)