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