xref: /llvm-project/llvm/test/Transforms/EarlyCSE/atomics.ll (revision ac696ac4530fb3df626195e94e83649bf7114754)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -S -passes=early-cse -earlycse-debug-hash | FileCheck %s
3; RUN: opt < %s -S -passes='early-cse<memssa>' | FileCheck %s
4
5define i32 @test12(i1 %B, ptr %P1, ptr %P2) {
6; CHECK-LABEL: @test12(
7; CHECK-NEXT:    [[LOAD0:%.*]] = load i32, ptr [[P1:%.*]], align 4
8; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i32, ptr [[P2:%.*]] seq_cst, align 4
9; CHECK-NEXT:    [[LOAD1:%.*]] = load i32, ptr [[P1]], align 4
10; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[B:%.*]], i32 [[LOAD0]], i32 [[LOAD1]]
11; CHECK-NEXT:    ret i32 [[SEL]]
12;
13  %load0 = load i32, ptr %P1
14  %1 = load atomic i32, ptr %P2 seq_cst, align 4
15  %load1 = load i32, ptr %P1
16  %sel = select i1 %B, i32 %load0, i32 %load1
17  ret i32 %sel
18}
19
20; atomic to non-atomic forwarding is legal
21define i32 @test13(i1 %B, ptr %P1) {
22; CHECK-LABEL: @test13(
23; CHECK-NEXT:    [[A:%.*]] = load atomic i32, ptr [[P1:%.*]] seq_cst, align 4
24; CHECK-NEXT:    ret i32 0
25;
26  %a = load atomic i32, ptr %P1 seq_cst, align 4
27  %b = load i32, ptr %P1
28  %res = sub i32 %a, %b
29  ret i32 %res
30}
31
32; atomic to unordered atomic forwarding is legal
33define i32 @test14(i1 %B, ptr %P1) {
34; CHECK-LABEL: @test14(
35; CHECK-NEXT:    [[A:%.*]] = load atomic i32, ptr [[P1:%.*]] seq_cst, align 4
36; CHECK-NEXT:    ret i32 0
37;
38  %a = load atomic i32, ptr %P1 seq_cst, align 4
39  %b = load atomic i32, ptr %P1 unordered, align 4
40  %res = sub i32 %a, %b
41  ret i32 %res
42}
43
44; implementation restriction: can't forward to stonger
45; than unordered
46define i32 @test15(i1 %B, ptr %P1, ptr %P2) {
47; CHECK-LABEL: @test15(
48; CHECK-NEXT:    [[A:%.*]] = load atomic i32, ptr [[P1:%.*]] seq_cst, align 4
49; CHECK-NEXT:    [[B:%.*]] = load atomic i32, ptr [[P1]] seq_cst, align 4
50; CHECK-NEXT:    [[RES:%.*]] = sub i32 [[A]], [[B]]
51; CHECK-NEXT:    ret i32 [[RES]]
52;
53  %a = load atomic i32, ptr %P1 seq_cst, align 4
54  %b = load atomic i32, ptr %P1 seq_cst, align 4
55  %res = sub i32 %a, %b
56  ret i32 %res
57}
58
59; forwarding non-atomic to atomic is wrong! (However,
60; it would be legal to use the later value in place of the
61; former in this particular example.  We just don't
62; do that right now.)
63define i32 @test16(i1 %B, ptr %P1, ptr %P2) {
64; CHECK-LABEL: @test16(
65; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P1:%.*]], align 4
66; CHECK-NEXT:    [[B:%.*]] = load atomic i32, ptr [[P1]] unordered, align 4
67; CHECK-NEXT:    [[RES:%.*]] = sub i32 [[A]], [[B]]
68; CHECK-NEXT:    ret i32 [[RES]]
69;
70  %a = load i32, ptr %P1, align 4
71  %b = load atomic i32, ptr %P1 unordered, align 4
72  %res = sub i32 %a, %b
73  ret i32 %res
74}
75
76; Can't DSE across a full fence
77define void @fence_seq_cst_store(i1 %B, ptr %P1, ptr %P2) {
78; CHECK-LABEL: @fence_seq_cst_store(
79; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
80; CHECK-NEXT:    store atomic i32 0, ptr [[P2:%.*]] seq_cst, align 4
81; CHECK-NEXT:    store i32 0, ptr [[P1]], align 4
82; CHECK-NEXT:    ret void
83;
84  store i32 0, ptr %P1, align 4
85  store atomic i32 0, ptr %P2 seq_cst, align 4
86  store i32 0, ptr %P1, align 4
87  ret void
88}
89
90; Can't DSE across a full fence
91define void @fence_seq_cst(i1 %B, ptr %P1, ptr %P2) {
92; CHECK-LABEL: @fence_seq_cst(
93; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
94; CHECK-NEXT:    fence seq_cst
95; CHECK-NEXT:    store i32 0, ptr [[P1]], align 4
96; CHECK-NEXT:    ret void
97;
98  store i32 0, ptr %P1, align 4
99  fence seq_cst
100  store i32 0, ptr %P1, align 4
101  ret void
102}
103
104; Can't DSE across a full fence
105define void @fence_asm_sideeffect(i1 %B, ptr %P1, ptr %P2) {
106; CHECK-LABEL: @fence_asm_sideeffect(
107; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
108; CHECK-NEXT:    call void asm sideeffect "", ""()
109; CHECK-NEXT:    store i32 0, ptr [[P1]], align 4
110; CHECK-NEXT:    ret void
111;
112  store i32 0, ptr %P1, align 4
113  call void asm sideeffect "", ""()
114  store i32 0, ptr %P1, align 4
115  ret void
116}
117
118; Can't DSE across a full fence
119define void @fence_asm_memory(i1 %B, ptr %P1, ptr %P2) {
120; CHECK-LABEL: @fence_asm_memory(
121; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
122; CHECK-NEXT:    call void asm "", "~{memory}"()
123; CHECK-NEXT:    store i32 0, ptr [[P1]], align 4
124; CHECK-NEXT:    ret void
125;
126  store i32 0, ptr %P1, align 4
127  call void asm "", "~{memory}"()
128  store i32 0, ptr %P1, align 4
129  ret void
130}
131
132; Can't remove a volatile load
133define i32 @volatile_load(i1 %B, ptr %P1, ptr %P2) {
134; CHECK-LABEL: @volatile_load(
135; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P1:%.*]], align 4
136; CHECK-NEXT:    [[B:%.*]] = load volatile i32, ptr [[P1]], align 4
137; CHECK-NEXT:    [[RES:%.*]] = sub i32 [[A]], [[B]]
138; CHECK-NEXT:    ret i32 [[RES]]
139;
140  %a = load i32, ptr %P1, align 4
141  %b = load volatile i32, ptr %P1, align 4
142  %res = sub i32 %a, %b
143  ret i32 %res
144}
145
146; Can't remove redundant volatile loads
147define i32 @redundant_volatile_load(i1 %B, ptr %P1, ptr %P2) {
148; CHECK-LABEL: @redundant_volatile_load(
149; CHECK-NEXT:    [[A:%.*]] = load volatile i32, ptr [[P1:%.*]], align 4
150; CHECK-NEXT:    [[B:%.*]] = load volatile i32, ptr [[P1]], align 4
151; CHECK-NEXT:    [[RES:%.*]] = sub i32 [[A]], [[B]]
152; CHECK-NEXT:    ret i32 [[RES]]
153;
154  %a = load volatile i32, ptr %P1, align 4
155  %b = load volatile i32, ptr %P1, align 4
156  %res = sub i32 %a, %b
157  ret i32 %res
158}
159
160; Can't DSE a volatile store
161define void @volatile_store(i1 %B, ptr %P1, ptr %P2) {
162; CHECK-LABEL: @volatile_store(
163; CHECK-NEXT:    store volatile i32 0, ptr [[P1:%.*]], align 4
164; CHECK-NEXT:    store i32 3, ptr [[P1]], align 4
165; CHECK-NEXT:    ret void
166;
167  store volatile i32 0, ptr %P1, align 4
168  store i32 3, ptr %P1, align 4
169  ret void
170}
171
172; Can't DSE a redundant volatile store
173define void @redundant_volatile_store(i1 %B, ptr %P1, ptr %P2) {
174; CHECK-LABEL: @redundant_volatile_store(
175; CHECK-NEXT:    store volatile i32 0, ptr [[P1:%.*]], align 4
176; CHECK-NEXT:    store volatile i32 0, ptr [[P1]], align 4
177; CHECK-NEXT:    ret void
178;
179  store volatile i32 0, ptr %P1, align 4
180  store volatile i32 0, ptr %P1, align 4
181  ret void
182}
183
184; Can value forward from volatiles
185define i32 @test20(i1 %B, ptr %P1, ptr %P2) {
186; CHECK-LABEL: @test20(
187; CHECK-NEXT:    [[A:%.*]] = load volatile i32, ptr [[P1:%.*]], align 4
188; CHECK-NEXT:    ret i32 0
189;
190  %a = load volatile i32, ptr %P1, align 4
191  %b = load i32, ptr %P1, align 4
192  %res = sub i32 %a, %b
193  ret i32 %res
194}
195
196; Can DSE a non-volatile store in favor of a volatile one
197; currently a missed optimization
198define void @test21(i1 %B, ptr %P1, ptr %P2) {
199; CHECK-LABEL: @test21(
200; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
201; CHECK-NEXT:    store volatile i32 3, ptr [[P1]], align 4
202; CHECK-NEXT:    ret void
203;
204  store i32 0, ptr %P1, align 4
205  store volatile i32 3, ptr %P1, align 4
206  ret void
207}
208
209; Can DSE a normal store in favor of a unordered one
210define void @test22(i1 %B, ptr %P1, ptr %P2) {
211; CHECK-LABEL: @test22(
212; CHECK-NEXT:    store atomic i32 3, ptr [[P1:%.*]] unordered, align 4
213; CHECK-NEXT:    ret void
214;
215  store i32 0, ptr %P1, align 4
216  store atomic i32 3, ptr %P1 unordered, align 4
217  ret void
218}
219
220; Can also DSE a unordered store in favor of a normal one
221define void @test23(i1 %B, ptr %P1, ptr %P2) {
222; CHECK-LABEL: @test23(
223; CHECK-NEXT:    store i32 0, ptr [[P1:%.*]], align 4
224; CHECK-NEXT:    ret void
225;
226  store atomic i32 3, ptr %P1 unordered, align 4
227  store i32 0, ptr %P1, align 4
228  ret void
229}
230
231; As an implementation limitation, can't remove ordered stores
232; Note that we could remove the earlier store if we could
233; represent the required ordering.
234define void @test24(i1 %B, ptr %P1, ptr %P2) {
235; CHECK-LABEL: @test24(
236; CHECK-NEXT:    store atomic i32 3, ptr [[P1:%.*]] release, align 4
237; CHECK-NEXT:    store i32 0, ptr [[P1]], align 4
238; CHECK-NEXT:    ret void
239;
240  store atomic i32 3, ptr %P1 release, align 4
241  store i32 0, ptr %P1, align 4
242  ret void
243}
244
245; Can't remove volatile stores - each is independently observable and
246; the count of such stores is an observable program side effect.
247define void @test25(i1 %B, ptr %P1, ptr %P2) {
248; CHECK-LABEL: @test25(
249; CHECK-NEXT:    store volatile i32 3, ptr [[P1:%.*]], align 4
250; CHECK-NEXT:    store volatile i32 0, ptr [[P1]], align 4
251; CHECK-NEXT:    ret void
252;
253  store volatile i32 3, ptr %P1, align 4
254  store volatile i32 0, ptr %P1, align 4
255  ret void
256}
257
258; Can DSE a unordered store in favor of a unordered one
259define void @test26(i1 %B, ptr %P1, ptr %P2) {
260; CHECK-LABEL: @test26(
261; CHECK-NEXT:    store atomic i32 3, ptr [[P1:%.*]] unordered, align 4
262; CHECK-NEXT:    ret void
263;
264  store atomic i32 0, ptr %P1 unordered, align 4
265  store atomic i32 3, ptr %P1 unordered, align 4
266  ret void
267}
268
269; Can DSE a unordered store in favor of a ordered one,
270; but current don't due to implementation limits
271define void @test27(i1 %B, ptr %P1, ptr %P2) {
272; CHECK-LABEL: @test27(
273; CHECK-NEXT:    store atomic i32 0, ptr [[P1:%.*]] unordered, align 4
274; CHECK-NEXT:    store atomic i32 3, ptr [[P1]] release, align 4
275; CHECK-NEXT:    ret void
276;
277  store atomic i32 0, ptr %P1 unordered, align 4
278  store atomic i32 3, ptr %P1 release, align 4
279  ret void
280}
281
282; Can DSE an unordered atomic store in favor of an
283; ordered one, but current don't due to implementation limits
284define void @test28(i1 %B, ptr %P1, ptr %P2) {
285; CHECK-LABEL: @test28(
286; CHECK-NEXT:    store atomic i32 0, ptr [[P1:%.*]] unordered, align 4
287; CHECK-NEXT:    store atomic i32 3, ptr [[P1]] release, align 4
288; CHECK-NEXT:    ret void
289;
290  store atomic i32 0, ptr %P1 unordered, align 4
291  store atomic i32 3, ptr %P1 release, align 4
292  ret void
293}
294
295; As an implementation limitation, can't remove ordered stores
296; see also: @test24
297define void @test29(i1 %B, ptr %P1, ptr %P2) {
298; CHECK-LABEL: @test29(
299; CHECK-NEXT:    store atomic i32 3, ptr [[P1:%.*]] release, align 4
300; CHECK-NEXT:    store atomic i32 0, ptr [[P1]] unordered, align 4
301; CHECK-NEXT:    ret void
302;
303  store atomic i32 3, ptr %P1 release, align 4
304  store atomic i32 0, ptr %P1 unordered, align 4
305  ret void
306}
307