xref: /llvm-project/llvm/test/Transforms/InstCombine/store.ll (revision c00f49cf12ff2916a372176f2154a83eb80f1692)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4; FIXME: This is technically incorrect because it might overwrite a poison
5; value. Stop folding it once #52930 is resolved.
6define void @store_of_undef(ptr %P) {
7; CHECK-LABEL: @store_of_undef(
8; CHECK-NEXT:    ret void
9;
10  store i32 undef, ptr %P
11  ret void
12}
13
14define void @store_of_poison(ptr %P) {
15; CHECK-LABEL: @store_of_poison(
16; CHECK-NEXT:    ret void
17;
18  store i32 poison, ptr %P
19  ret void
20}
21
22define void @store_into_undef(ptr %P) {
23; CHECK-LABEL: @store_into_undef(
24; CHECK-NEXT:    store i32 123, ptr undef, align 4
25; CHECK-NEXT:    ret void
26;
27  store i32 123, ptr undef
28  ret void
29}
30
31define void @store_into_null(ptr %P) {
32; CHECK-LABEL: @store_into_null(
33; CHECK-NEXT:    store i32 poison, ptr null, align 4
34; CHECK-NEXT:    ret void
35;
36  store i32 124, ptr null
37  ret void
38}
39
40define void @test2(ptr %P) {
41; CHECK-LABEL: @test2(
42; CHECK-NEXT:    ret void
43;
44  %X = load i32, ptr %P
45  %Y = add i32 %X, 0
46  store i32 %Y, ptr %P
47  ret void
48}
49
50define void @store_at_gep_off_null_inbounds(i64 %offset) {
51; CHECK-LABEL: @store_at_gep_off_null_inbounds(
52; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds i32, ptr null, i64 [[OFFSET:%.*]]
53; CHECK-NEXT:    store i32 poison, ptr [[PTR]], align 4
54; CHECK-NEXT:    ret void
55;
56  %ptr = getelementptr inbounds i32, ptr null, i64 %offset
57  store i32 24, ptr %ptr
58  ret void
59}
60
61define void @store_at_gep_off_null_not_inbounds(i64 %offset) {
62; CHECK-LABEL: @store_at_gep_off_null_not_inbounds(
63; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr null, i64 [[OFFSET:%.*]]
64; CHECK-NEXT:    store i32 poison, ptr [[PTR]], align 4
65; CHECK-NEXT:    ret void
66;
67  %ptr = getelementptr i32, ptr null, i64 %offset
68  store i32 24, ptr %ptr
69  ret void
70}
71
72define void @store_at_gep_off_no_null_opt(i64 %offset) #0 {
73; CHECK-LABEL: @store_at_gep_off_no_null_opt(
74; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds i32, ptr null, i64 [[OFFSET:%.*]]
75; CHECK-NEXT:    store i32 24, ptr [[PTR]], align 4
76; CHECK-NEXT:    ret void
77;
78  %ptr = getelementptr inbounds i32, ptr null, i64 %offset
79  store i32 24, ptr %ptr
80  ret void
81}
82
83attributes #0 = { null_pointer_is_valid }
84
85;; Simple sinking tests
86
87; "if then else"
88define i32 @test3(i1 %C) {
89; CHECK-LABEL: @test3(
90; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[COND2:%.*]]
91; CHECK:       Cond:
92; CHECK-NEXT:    br label [[CONT:%.*]]
93; CHECK:       Cond2:
94; CHECK-NEXT:    br label [[CONT]]
95; CHECK:       Cont:
96; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ 47, [[COND2]] ], [ -987654321, [[COND]] ]
97; CHECK-NEXT:    ret i32 [[STOREMERGE]]
98;
99  %A = alloca i32
100  br i1 %C, label %Cond, label %Cond2
101
102Cond:
103  store i32 -987654321, ptr %A
104  br label %Cont
105
106Cond2:
107  store i32 47, ptr %A
108  br label %Cont
109
110Cont:
111  %V = load i32, ptr %A
112  ret i32 %V
113}
114
115; "if then"
116define i32 @test4(i1 %C) {
117; CHECK-LABEL: @test4(
118; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[CONT:%.*]]
119; CHECK:       Cond:
120; CHECK-NEXT:    br label [[CONT]]
121; CHECK:       Cont:
122; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -987654321, [[COND]] ], [ 47, [[TMP0:%.*]] ]
123; CHECK-NEXT:    ret i32 [[STOREMERGE]]
124;
125  %A = alloca i32
126  store i32 47, ptr %A
127  br i1 %C, label %Cond, label %Cont
128
129Cond:
130  store i32 -987654321, ptr %A
131  br label %Cont
132
133Cont:
134  %V = load i32, ptr %A
135  ret i32 %V
136}
137
138; "if then"
139define void @test5(i1 %C, ptr %P) {
140; CHECK-LABEL: @test5(
141; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[CONT:%.*]]
142; CHECK:       Cond:
143; CHECK-NEXT:    br label [[CONT]]
144; CHECK:       Cont:
145; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -987654321, [[COND]] ], [ 47, [[TMP0:%.*]] ]
146; CHECK-NEXT:    store i32 [[STOREMERGE]], ptr [[P:%.*]], align 1
147; CHECK-NEXT:    ret void
148;
149  store i32 47, ptr %P, align 1
150  br i1 %C, label %Cond, label %Cont
151
152Cond:
153  store i32 -987654321, ptr %P, align 1
154  br label %Cont
155
156Cont:
157  ret void
158}
159
160
161; PR14753 - merging two stores should preserve the TBAA tag.
162define void @test6(i32 %n, ptr %a, ptr %gi) nounwind uwtable ssp {
163; CHECK-LABEL: @test6(
164; CHECK-NEXT:  entry:
165; CHECK-NEXT:    br label [[FOR_COND:%.*]]
166; CHECK:       for.cond:
167; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ 42, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
168; CHECK-NEXT:    store i32 [[STOREMERGE]], ptr [[GI:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]]
169; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[STOREMERGE]], [[N:%.*]]
170; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
171; CHECK:       for.body:
172; CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[STOREMERGE]] to i64
173; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr [[A:%.*]], i64 [[IDXPROM]]
174; CHECK-NEXT:    store float 0.000000e+00, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4:![0-9]+]]
175; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[GI]], align 4, !tbaa [[TBAA0]]
176; CHECK-NEXT:    [[INC]] = add nsw i32 [[TMP0]], 1
177; CHECK-NEXT:    br label [[FOR_COND]]
178; CHECK:       for.end:
179; CHECK-NEXT:    ret void
180;
181entry:
182  store i32 42, ptr %gi, align 4, !tbaa !0
183  br label %for.cond
184
185for.cond:
186  %storemerge = phi i32 [ 0, %entry ], [ %inc, %for.body ]
187  %0 = load i32, ptr %gi, align 4, !tbaa !0
188  %cmp = icmp slt i32 %0, %n
189  br i1 %cmp, label %for.body, label %for.end
190
191for.body:
192  %idxprom = sext i32 %0 to i64
193  %arrayidx = getelementptr inbounds float, ptr %a, i64 %idxprom
194  store float 0.000000e+00, ptr %arrayidx, align 4, !tbaa !3
195  %1 = load i32, ptr %gi, align 4, !tbaa !0
196  %inc = add nsw i32 %1, 1
197  store i32 %inc, ptr %gi, align 4, !tbaa !0
198  br label %for.cond
199
200for.end:
201  ret void
202}
203
204define void @dse1(ptr %p) {
205; CHECK-LABEL: @dse1(
206; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
207; CHECK-NEXT:    ret void
208;
209  store i32 0, ptr %p
210  store i32 0, ptr %p
211  ret void
212}
213
214; Slightly subtle: if we're mixing atomic and non-atomic access to the
215; same location, then the contents of the location are undefined if there's
216; an actual race.  As such, we're free to pick either store under the
217; assumption that we're not racing with any other thread.
218define void @dse2(ptr %p) {
219; CHECK-LABEL: @dse2(
220; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
221; CHECK-NEXT:    ret void
222;
223  store atomic i32 0, ptr %p unordered, align 4
224  store i32 0, ptr %p
225  ret void
226}
227
228define void @dse3(ptr %p) {
229; CHECK-LABEL: @dse3(
230; CHECK-NEXT:    store atomic i32 0, ptr [[P:%.*]] unordered, align 4
231; CHECK-NEXT:    ret void
232;
233  store i32 0, ptr %p
234  store atomic i32 0, ptr %p unordered, align 4
235  ret void
236}
237
238define void @dse4(ptr %p) {
239; CHECK-LABEL: @dse4(
240; CHECK-NEXT:    store atomic i32 0, ptr [[P:%.*]] unordered, align 4
241; CHECK-NEXT:    ret void
242;
243  store atomic i32 0, ptr %p unordered, align 4
244  store atomic i32 0, ptr %p unordered, align 4
245  ret void
246}
247
248; Implementation limit - could remove unordered store here, but
249; currently don't.
250define void @dse5(ptr %p) {
251; CHECK-LABEL: @dse5(
252; CHECK-NEXT:    store atomic i32 0, ptr [[P:%.*]] unordered, align 4
253; CHECK-NEXT:    store atomic i32 0, ptr [[P]] seq_cst, align 4
254; CHECK-NEXT:    ret void
255;
256  store atomic i32 0, ptr %p unordered, align 4
257  store atomic i32 0, ptr %p seq_cst, align 4
258  ret void
259}
260
261define void @write_back1(ptr %p) {
262; CHECK-LABEL: @write_back1(
263; CHECK-NEXT:    ret void
264;
265  %v = load i32, ptr %p
266  store i32 %v, ptr %p
267  ret void
268}
269
270define void @write_back2(ptr %p) {
271; CHECK-LABEL: @write_back2(
272; CHECK-NEXT:    ret void
273;
274  %v = load atomic i32, ptr %p unordered, align 4
275  store i32 %v, ptr %p
276  ret void
277}
278
279define void @write_back3(ptr %p) {
280; CHECK-LABEL: @write_back3(
281; CHECK-NEXT:    ret void
282;
283  %v = load i32, ptr %p
284  store atomic i32 %v, ptr %p unordered, align 4
285  ret void
286}
287
288define void @write_back4(ptr %p) {
289; CHECK-LABEL: @write_back4(
290; CHECK-NEXT:    ret void
291;
292  %v = load atomic i32, ptr %p unordered, align 4
293  store atomic i32 %v, ptr %p unordered, align 4
294  ret void
295}
296
297; Can't remove store due to ordering side effect
298define void @write_back5(ptr %p) {
299; CHECK-LABEL: @write_back5(
300; CHECK-NEXT:    [[V:%.*]] = load atomic i32, ptr [[P:%.*]] unordered, align 4
301; CHECK-NEXT:    store atomic i32 [[V]], ptr [[P]] seq_cst, align 4
302; CHECK-NEXT:    ret void
303;
304  %v = load atomic i32, ptr %p unordered, align 4
305  store atomic i32 %v, ptr %p seq_cst, align 4
306  ret void
307}
308
309define void @write_back6(ptr %p) {
310; CHECK-LABEL: @write_back6(
311; CHECK-NEXT:    [[V:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4
312; CHECK-NEXT:    ret void
313;
314  %v = load atomic i32, ptr %p seq_cst, align 4
315  store atomic i32 %v, ptr %p unordered, align 4
316  ret void
317}
318
319define void @write_back7(ptr %p) {
320; CHECK-LABEL: @write_back7(
321; CHECK-NEXT:    [[V:%.*]] = load atomic volatile i32, ptr [[P:%.*]] seq_cst, align 4
322; CHECK-NEXT:    ret void
323;
324  %v = load atomic volatile i32, ptr %p seq_cst, align 4
325  store atomic i32 %v, ptr %p unordered, align 4
326  ret void
327}
328
329@Unknown = external constant i32
330
331define void @store_to_constant() {
332; CHECK-LABEL: @store_to_constant(
333; CHECK-NEXT:    ret void
334;
335  store i32 0, ptr @Unknown
336  ret void
337}
338
339; Delete stores to readonly noalias pointers.
340define void @store_to_readonly_noalias(ptr readonly noalias %0) {
341; CHECK-LABEL: @store_to_readonly_noalias(
342; CHECK-NEXT:    ret void
343;
344  store i32 3, ptr %0, align 4
345  ret void
346}
347
348!0 = !{!4, !4, i64 0}
349!1 = !{!"omnipotent char", !2}
350!2 = !{!"Simple C/C++ TBAA"}
351!3 = !{!"float", !1}
352!4 = !{!"int", !1}
353