xref: /llvm-project/llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll (revision fed817a8b25e178cd701fefcdfe80c447d2ab212)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=dse -enable-dse-initializes-attr-improvement -S | FileCheck %s
3
4declare void @p1_write_only(ptr nocapture noundef writeonly initializes((0, 2)) dead_on_unwind)
5declare void @p1_write_then_read(ptr nocapture noundef initializes((0, 2)) dead_on_unwind)
6declare void @p1_clobber(ptr nocapture noundef)
7declare void @p2_same_range(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2)) dead_on_unwind)
8declare void @p2_no_init(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef dead_on_unwind)
9declare void @p2_no_dead_on_unwind(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2)))
10declare void @p2_no_dead_on_unwind_but_nounwind(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2))) nounwind
11
12; Function Attrs: mustprogress nounwind uwtable
13define i16 @p1_write_only_caller() {
14; CHECK-LABEL: @p1_write_only_caller(
15; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
16; CHECK-NEXT:    call void @p1_write_only(ptr [[PTR]])
17; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
18; CHECK-NEXT:    ret i16 [[L]]
19;
20  %ptr = alloca i16
21  store i16 0, ptr %ptr
22  call void @p1_write_only(ptr %ptr)
23  %l = load i16, ptr %ptr
24  ret i16 %l
25}
26
27; Function Attrs: mustprogress nounwind uwtable
28define i16 @p1_write_then_read_caller() {
29; CHECK-LABEL: @p1_write_then_read_caller(
30; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
31; CHECK-NEXT:    call void @p1_write_then_read(ptr [[PTR]])
32; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
33; CHECK-NEXT:    ret i16 [[L]]
34;
35  %ptr = alloca i16
36  store i16 0, ptr %ptr
37  call void @p1_write_then_read(ptr %ptr)
38  %l = load i16, ptr %ptr
39  ret i16 %l
40}
41
42declare void @fn_capture(ptr)
43define i16 @p1_write_then_read_caller_escape() {
44; CHECK-LABEL: @p1_write_then_read_caller_escape(
45; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
46; CHECK-NEXT:    store i16 0, ptr [[PTR]], align 2
47; CHECK-NEXT:    call void @fn_capture(ptr [[PTR]])
48; CHECK-NEXT:    call void @p1_write_then_read(ptr [[PTR]])
49; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
50; CHECK-NEXT:    ret i16 [[L]]
51;
52  %ptr = alloca i16
53  store i16 0, ptr %ptr
54  call void @fn_capture(ptr %ptr)
55  call void @p1_write_then_read(ptr %ptr)
56  %l = load i16, ptr %ptr
57  ret i16 %l
58}
59
60
61; Function Attrs: mustprogress nounwind uwtable
62define i16 @p1_write_then_read_caller_with_clobber() {
63; CHECK-LABEL: @p1_write_then_read_caller_with_clobber(
64; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
65; CHECK-NEXT:    store i16 0, ptr [[PTR]], align 2
66; CHECK-NEXT:    call void @p1_clobber(ptr [[PTR]])
67; CHECK-NEXT:    call void @p1_write_then_read(ptr [[PTR]])
68; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
69; CHECK-NEXT:    ret i16 [[L]]
70;
71  %ptr = alloca i16
72  store i16 0, ptr %ptr
73  call void @p1_clobber(ptr %ptr)
74  call void @p1_write_then_read(ptr %ptr)
75  %l = load i16, ptr %ptr
76  ret i16 %l
77}
78
79declare void @p1_write_then_read_raw(ptr nocapture noundef initializes((0, 2)))
80define i16 @p1_initializes_invoke() personality ptr undef {
81; CHECK-LABEL: @p1_initializes_invoke(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
84; CHECK-NEXT:    store i16 0, ptr [[PTR]], align 2
85; CHECK-NEXT:    invoke void @p1_write_then_read_raw(ptr [[PTR]])
86; CHECK-NEXT:            to label [[BB1:%.*]] unwind label [[BB2:%.*]]
87; CHECK:       bb1:
88; CHECK-NEXT:    ret i16 0
89; CHECK:       bb2:
90; CHECK-NEXT:    [[TMP:%.*]] = landingpad { ptr, i32 }
91; CHECK-NEXT:            cleanup
92; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
93; CHECK-NEXT:    ret i16 [[L]]
94;
95entry:
96  %ptr = alloca i16
97  store i16 0, ptr %ptr
98  invoke void @p1_write_then_read_raw(ptr %ptr) to label %bb1 unwind label %bb2
99bb1:
100  ret i16 0
101bb2:
102  %tmp = landingpad { ptr, i32 }
103  cleanup
104  %l = load i16, ptr %ptr
105  ret i16 %l
106}
107
108; Function Attrs: mustprogress nounwind uwtable
109define i16 @p2_same_range_noalias_caller() {
110; CHECK-LABEL: @p2_same_range_noalias_caller(
111; CHECK-NEXT:    [[PTR1:%.*]] = alloca i16, align 2
112; CHECK-NEXT:    [[PTR2:%.*]] = alloca i16, align 2
113; CHECK-NEXT:    call void @p2_same_range(ptr [[PTR1]], ptr [[PTR2]])
114; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR1]], align 2
115; CHECK-NEXT:    ret i16 [[L]]
116;
117  %ptr1 = alloca i16
118  %ptr2 = alloca i16
119  store i16 0, ptr %ptr1
120  store i16 0, ptr %ptr2
121  call void @p2_same_range(ptr %ptr1, ptr %ptr2)
122  %l = load i16, ptr %ptr1
123  ret i16 %l
124}
125
126; Function Attrs: mustprogress nounwind uwtable
127define i16 @p2_same_range_must_alias_caller() {
128; CHECK-LABEL: @p2_same_range_must_alias_caller(
129; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
130; CHECK-NEXT:    call void @p2_same_range(ptr [[PTR]], ptr [[PTR]])
131; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
132; CHECK-NEXT:    ret i16 [[L]]
133;
134  %ptr = alloca i16
135  store i16 0, ptr %ptr
136  call void @p2_same_range(ptr %ptr, ptr %ptr)
137  %l = load i16, ptr %ptr
138  ret i16 %l
139}
140
141; Function Attrs: mustprogress nounwind uwtable
142define i16 @p2_same_range_may_or_partial_alias_caller1(ptr %base, i1 %x) {
143; CHECK-LABEL: @p2_same_range_may_or_partial_alias_caller1(
144; CHECK-NEXT:    [[BASEPLUS:%.*]] = getelementptr i8, ptr [[BASE:%.*]], i64 1
145; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[BASEPLUS]], ptr [[BASE]]
146; CHECK-NEXT:    store i32 0, ptr [[BASE]], align 4
147; CHECK-NEXT:    call void @p2_same_range(ptr [[BASE]], ptr [[SEL]])
148; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[BASE]], align 2
149; CHECK-NEXT:    ret i16 [[L]]
150;
151  %baseplus = getelementptr i8, ptr %base, i64 1
152  %sel = select i1 %x, ptr %baseplus, ptr %base
153  store i32 0, ptr %base
154  call void @p2_same_range(ptr %base, ptr %sel)
155  %l = load i16, ptr %base
156  ret i16 %l
157}
158
159; Function Attrs: mustprogress nounwind uwtable
160define i16 @p2_same_range_may_or_partial_alias_caller2(ptr %base1, ptr %base2) {
161; CHECK-LABEL: @p2_same_range_may_or_partial_alias_caller2(
162; CHECK-NEXT:    store i32 0, ptr [[BASE1:%.*]], align 4
163; CHECK-NEXT:    call void @p2_same_range(ptr [[BASE1]], ptr [[BASE2:%.*]])
164; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[BASE1]], align 2
165; CHECK-NEXT:    ret i16 [[L]]
166;
167  store i32 0, ptr %base1
168  call void @p2_same_range(ptr %base1, ptr %base2)
169  %l = load i16, ptr %base1
170  ret i16 %l
171}
172
173; Function Attrs: mustprogress nounwind uwtable
174define i16 @p2_no_init_alias_caller() {
175; CHECK-LABEL: @p2_no_init_alias_caller(
176; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
177; CHECK-NEXT:    store i16 0, ptr [[PTR]], align 2
178; CHECK-NEXT:    call void @p2_no_init(ptr [[PTR]], ptr [[PTR]])
179; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
180; CHECK-NEXT:    ret i16 [[L]]
181;
182  %ptr = alloca i16
183  store i16 0, ptr %ptr
184  call void @p2_no_init(ptr %ptr, ptr %ptr)
185  %l = load i16, ptr %ptr
186  ret i16 %l
187}
188
189; Althrough the 2nd parameter of `p2_no_dead_on_unwind` doesn't have
190; the 'dead_on_unwind' attribute, it's invisble to caller on unwind.
191; DSE still uses the 'initializes' attribute and kill the dead store.
192; Function Attrs: mustprogress nounwind uwtable
193define i16 @p2_no_dead_on_unwind_but_invisible_to_caller_alias_caller() {
194; CHECK-LABEL: @p2_no_dead_on_unwind_but_invisible_to_caller_alias_caller(
195; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
196; CHECK-NEXT:    call void @p2_no_dead_on_unwind(ptr [[PTR]], ptr [[PTR]])
197; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
198; CHECK-NEXT:    ret i16 [[L]]
199;
200  %ptr = alloca i16
201  store i16 0, ptr %ptr
202  call void @p2_no_dead_on_unwind(ptr %ptr, ptr %ptr)
203  %l = load i16, ptr %ptr
204  ret i16 %l
205}
206
207; Function Attrs: mustprogress nounwind uwtable
208define i16 @p2_no_dead_on_unwind_alias_caller(ptr %ptr) {
209; CHECK-LABEL: @p2_no_dead_on_unwind_alias_caller(
210; CHECK-NEXT:    store i16 0, ptr [[PTR:%.*]], align 2
211; CHECK-NEXT:    call void @p2_no_dead_on_unwind(ptr [[PTR]], ptr [[PTR]])
212; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
213; CHECK-NEXT:    ret i16 [[L]]
214;
215  store i16 0, ptr %ptr
216  call void @p2_no_dead_on_unwind(ptr %ptr, ptr %ptr)
217  %l = load i16, ptr %ptr
218  ret i16 %l
219}
220
221; Function Attrs: mustprogress nounwind uwtable
222define i16 @p2_no_dead_on_unwind_but_nounwind_alias_caller() {
223; CHECK-LABEL: @p2_no_dead_on_unwind_but_nounwind_alias_caller(
224; CHECK-NEXT:    [[PTR:%.*]] = alloca i16, align 2
225; CHECK-NEXT:    call void @p2_no_dead_on_unwind_but_nounwind(ptr [[PTR]], ptr [[PTR]])
226; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
227; CHECK-NEXT:    ret i16 [[L]]
228;
229  %ptr = alloca i16
230  store i16 0, ptr %ptr
231  call void @p2_no_dead_on_unwind_but_nounwind(ptr %ptr, ptr %ptr)
232  %l = load i16, ptr %ptr
233  ret i16 %l
234}
235
236declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
237declare void @large_p1(ptr nocapture noundef initializes((0, 200))) nounwind
238declare void @large_p2(ptr nocapture noundef initializes((0, 200)), ptr nocapture noundef initializes((0, 100))) nounwind
239
240; Function Attrs: mustprogress nounwind uwtable
241define i16 @large_p1_caller() {
242; CHECK-LABEL: @large_p1_caller(
243; CHECK-NEXT:    [[PTR:%.*]] = alloca [300 x i8], align 1
244; CHECK-NEXT:    [[TMP:%.*]] = getelementptr i8, ptr [[PTR]], i64 100
245; CHECK-NEXT:    call void @large_p1(ptr [[TMP]])
246; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[TMP]], align 2
247; CHECK-NEXT:    ret i16 [[L]]
248;
249  %ptr = alloca [300 x i8]
250  %tmp = getelementptr i8, ptr %ptr, i64 100
251  call void @llvm.memset.p0.i64(ptr %tmp, i8 42, i64 100, i1 false)
252  call void @large_p1(ptr %tmp)
253  %l = load i16, ptr %tmp
254  ret i16 %l
255}
256
257; Function Attrs: mustprogress nounwind uwtable
258define i16 @large_p2_nonalias_caller() {
259; CHECK-LABEL: @large_p2_nonalias_caller(
260; CHECK-NEXT:    [[PTR1:%.*]] = alloca [200 x i8], align 1
261; CHECK-NEXT:    [[PTR2:%.*]] = alloca [100 x i8], align 1
262; CHECK-NEXT:    call void @large_p2(ptr [[PTR1]], ptr [[PTR2]])
263; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR1]], align 2
264; CHECK-NEXT:    ret i16 [[L]]
265;
266  %ptr1 = alloca [200 x i8]
267  %ptr2 = alloca [100 x i8]
268  call void @llvm.memset.p0.i64(ptr %ptr1, i8 42, i64 200, i1 false)
269  call void @llvm.memset.p0.i64(ptr %ptr2, i8 42, i64 100, i1 false)
270  call void @large_p2(ptr %ptr1, ptr %ptr2)
271  %l = load i16, ptr %ptr1
272  ret i16 %l
273}
274
275
276; Function Attrs: mustprogress nounwind uwtable
277define i16 @large_p2_must_alias_caller() {
278; CHECK-LABEL: @large_p2_must_alias_caller(
279; CHECK-NEXT:    [[PTR:%.*]] = alloca [300 x i8], align 1
280; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 100
281; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[TMP1]], i8 42, i64 200, i1 false)
282; CHECK-NEXT:    call void @large_p2(ptr [[PTR]], ptr [[PTR]])
283; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[PTR]], align 2
284; CHECK-NEXT:    ret i16 [[L]]
285;
286  %ptr = alloca [300 x i8]
287  call void @llvm.memset.p0.i64(ptr %ptr, i8 42, i64 300, i1 false)
288  call void @large_p2(ptr %ptr, ptr %ptr)
289  %l = load i16, ptr %ptr
290  ret i16 %l
291}
292
293; Function Attrs: mustprogress nounwind uwtable
294define i16 @large_p2_may_or_partial_alias_caller1(ptr %base) {
295; CHECK-LABEL: @large_p2_may_or_partial_alias_caller1(
296; CHECK-NEXT:    [[BASEPLUS:%.*]] = getelementptr i8, ptr [[BASE:%.*]], i64 100
297; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[BASE]], i8 42, i64 300, i1 false)
298; CHECK-NEXT:    call void @large_p2(ptr [[BASE]], ptr [[BASEPLUS]])
299; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[BASE]], align 2
300; CHECK-NEXT:    ret i16 [[L]]
301;
302  %baseplus = getelementptr i8, ptr %base, i64 100
303  call void @llvm.memset.p0.i64(ptr %base, i8 42, i64 300, i1 false)
304  call void @large_p2(ptr %base, ptr %baseplus)
305  %l = load i16, ptr %base
306  ret i16 %l
307}
308
309; Function Attrs: mustprogress nounwind uwtable
310define i16 @large_p2_may_or_partial_alias_caller2(ptr %base1, ptr %base2) {
311; CHECK-LABEL: @large_p2_may_or_partial_alias_caller2(
312; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[BASE1:%.*]], i8 42, i64 300, i1 false)
313; CHECK-NEXT:    call void @large_p2(ptr [[BASE1]], ptr [[BASE2:%.*]])
314; CHECK-NEXT:    [[L:%.*]] = load i16, ptr [[BASE1]], align 2
315; CHECK-NEXT:    ret i16 [[L]]
316;
317  call void @llvm.memset.p0.i64(ptr %base1, i8 42, i64 300, i1 false)
318  call void @large_p2(ptr %base1, ptr %base2)
319  %l = load i16, ptr %base1
320  ret i16 %l
321}
322
323@g = global i16 123, align 2
324
325declare void @read_global(ptr nocapture noundef initializes((0, 2))) nounwind
326  memory(read, argmem: write, inaccessiblemem: none) nounwind
327
328define i16 @global_var_alias() {
329; CHECK-LABEL: @global_var_alias(
330; CHECK-NEXT:    store i16 0, ptr @g, align 4
331; CHECK-NEXT:    call void @read_global(ptr @g)
332; CHECK-NEXT:    [[L:%.*]] = load i16, ptr @g, align 2
333; CHECK-NEXT:    ret i16 [[L]]
334;
335  store i16 0, ptr @g, align 4
336  call void @read_global(ptr @g)
337  %l = load i16, ptr @g
338  ret i16 %l
339}
340
341