1; RUN: opt -S < %s -instcombine | FileCheck %s
2
3target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
4target triple = "x86_64-apple-macosx10.7.0"
5
6; Check transforms involving atomic operations
7
8define i32 @test1(i32* %p) {
9; CHECK-LABEL: define i32 @test1(
10; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4
11; CHECK: shl i32 %x, 1
12  %x = load atomic i32, i32* %p seq_cst, align 4
13  %y = load i32, i32* %p, align 4
14  %z = add i32 %x, %y
15  ret i32 %z
16}
17
18define i32 @test2(i32* %p) {
19; CHECK-LABEL: define i32 @test2(
20; CHECK: %x = load volatile i32, i32* %p, align 4
21; CHECK: %y = load volatile i32, i32* %p, align 4
22  %x = load volatile i32, i32* %p, align 4
23  %y = load volatile i32, i32* %p, align 4
24  %z = add i32 %x, %y
25  ret i32 %z
26}
27
28; The exact semantics of mixing volatile and non-volatile on the same
29; memory location are a bit unclear, but conservatively, we know we don't
30; want to remove the volatile.
31define i32 @test3(i32* %p) {
32; CHECK-LABEL: define i32 @test3(
33; CHECK: %x = load volatile i32, i32* %p, align 4
34  %x = load volatile i32, i32* %p, align 4
35  %y = load i32, i32* %p, align 4
36  %z = add i32 %x, %y
37  ret i32 %z
38}
39
40; Forwarding from a stronger ordered atomic is fine
41define i32 @test4(i32* %p) {
42; CHECK-LABEL: define i32 @test4(
43; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4
44; CHECK: shl i32 %x, 1
45  %x = load atomic i32, i32* %p seq_cst, align 4
46  %y = load atomic i32, i32* %p unordered, align 4
47  %z = add i32 %x, %y
48  ret i32 %z
49}
50
51; Forwarding from a non-atomic is not.  (The earlier load
52; could in priciple be promoted to atomic and then forwarded,
53; but we can't just  drop the atomic from the load.)
54define i32 @test5(i32* %p) {
55; CHECK-LABEL: define i32 @test5(
56; CHECK: %x = load atomic i32, i32* %p unordered, align 4
57  %x = load atomic i32, i32* %p unordered, align 4
58  %y = load i32, i32* %p, align 4
59  %z = add i32 %x, %y
60  ret i32 %z
61}
62
63; Forwarding atomic to atomic is fine
64define i32 @test6(i32* %p) {
65; CHECK-LABEL: define i32 @test6(
66; CHECK: %x = load atomic i32, i32* %p unordered, align 4
67; CHECK: shl i32 %x, 1
68  %x = load atomic i32, i32* %p unordered, align 4
69  %y = load atomic i32, i32* %p unordered, align 4
70  %z = add i32 %x, %y
71  ret i32 %z
72}
73
74; FIXME: we currently don't do anything for monotonic
75define i32 @test7(i32* %p) {
76; CHECK-LABEL: define i32 @test7(
77; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4
78; CHECK: %y = load atomic i32, i32* %p monotonic, align 4
79  %x = load atomic i32, i32* %p seq_cst, align 4
80  %y = load atomic i32, i32* %p monotonic, align 4
81  %z = add i32 %x, %y
82  ret i32 %z
83}
84
85; FIXME: We could forward in racy code
86define i32 @test8(i32* %p) {
87; CHECK-LABEL: define i32 @test8(
88; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4
89; CHECK: %y = load atomic i32, i32* %p acquire, align 4
90  %x = load atomic i32, i32* %p seq_cst, align 4
91  %y = load atomic i32, i32* %p acquire, align 4
92  %z = add i32 %x, %y
93  ret i32 %z
94}
95
96; An unordered access to null is still unreachable.  There's no
97; ordering imposed.
98define i32 @test9() {
99; CHECK-LABEL: define i32 @test9(
100; CHECK: store i32 undef, i32* null
101  %x = load atomic i32, i32* null unordered, align 4
102  ret i32 %x
103}
104
105; FIXME: Could also fold
106define i32 @test10() {
107; CHECK-LABEL: define i32 @test10(
108; CHECK: load atomic i32, i32* null monotonic
109  %x = load atomic i32, i32* null monotonic, align 4
110  ret i32 %x
111}
112
113; Would this be legal to fold?  Probably?
114define i32 @test11() {
115; CHECK-LABEL: define i32 @test11(
116; CHECK: load atomic i32, i32* null seq_cst
117  %x = load atomic i32, i32* null seq_cst, align 4
118  ret i32 %x
119}
120
121; An unordered access to null is still unreachable.  There's no
122; ordering imposed.
123define i32 @test12() {
124; CHECK-LABEL: define i32 @test12(
125; CHECK: store atomic i32 undef, i32* null
126  store atomic i32 0, i32* null unordered, align 4
127  ret i32 0
128}
129
130; FIXME: Could also fold
131define i32 @test13() {
132; CHECK-LABEL: define i32 @test13(
133; CHECK: store atomic i32 0, i32* null monotonic
134  store atomic i32 0, i32* null monotonic, align 4
135  ret i32 0
136}
137
138; Would this be legal to fold?  Probably?
139define i32 @test14() {
140; CHECK-LABEL: define i32 @test14(
141; CHECK: store atomic i32 0, i32* null seq_cst
142  store atomic i32 0, i32* null seq_cst, align 4
143  ret i32 0
144}
145
146@a = external global i32
147@b = external global i32
148
149define i32 @test15(i1 %cnd) {
150; CHECK-LABEL: define i32 @test15(
151; CHECK: load atomic i32, i32* @a unordered, align 4
152; CHECK: load atomic i32, i32* @b unordered, align 4
153  %addr = select i1 %cnd, i32* @a, i32* @b
154  %x = load atomic i32, i32* %addr unordered, align 4
155  ret i32 %x
156}
157
158; FIXME: This would be legal to transform
159define i32 @test16(i1 %cnd) {
160; CHECK-LABEL: define i32 @test16(
161; CHECK: load atomic i32, i32* %addr monotonic, align 4
162  %addr = select i1 %cnd, i32* @a, i32* @b
163  %x = load atomic i32, i32* %addr monotonic, align 4
164  ret i32 %x
165}
166
167; FIXME: This would be legal to transform
168define i32 @test17(i1 %cnd) {
169; CHECK-LABEL: define i32 @test17(
170; CHECK: load atomic i32, i32* %addr seq_cst, align 4
171  %addr = select i1 %cnd, i32* @a, i32* @b
172  %x = load atomic i32, i32* %addr seq_cst, align 4
173  ret i32 %x
174}
175
176define i32 @test22(i1 %cnd) {
177; CHECK-LABEL: define i32 @test22(
178; CHECK: [[PHI:%.*]] = phi i32
179; CHECK: store atomic i32 [[PHI]], i32* @a unordered, align 4
180  br i1 %cnd, label %block1, label %block2
181
182block1:
183  store atomic i32 1, i32* @a unordered, align 4
184  br label %merge
185block2:
186  store atomic i32 2, i32* @a unordered, align 4
187  br label %merge
188
189merge:
190  ret i32 0
191}
192
193; TODO: probably also legal here
194define i32 @test23(i1 %cnd) {
195; CHECK-LABEL: define i32 @test23(
196; CHECK: br i1 %cnd, label %block1, label %block2
197  br i1 %cnd, label %block1, label %block2
198
199block1:
200  store atomic i32 1, i32* @a monotonic, align 4
201  br label %merge
202block2:
203  store atomic i32 2, i32* @a monotonic, align 4
204  br label %merge
205
206merge:
207  ret i32 0
208}
209
210declare void @clobber()
211
212define i32 @test18(float* %p) {
213; CHECK-LABEL: define i32 @test18(
214; CHECK: load atomic i32, i32* [[A:%.*]] unordered, align 4
215; CHECK: store atomic i32 [[B:%.*]], i32* [[C:%.*]] unordered, align 4
216  %x = load atomic float, float* %p unordered, align 4
217  call void @clobber() ;; keep the load around
218  store atomic float %x, float* %p unordered, align 4
219  ret i32 0
220}
221
222; TODO: probably also legal in this case
223define i32 @test19(float* %p) {
224; CHECK-LABEL: define i32 @test19(
225; CHECK: load atomic float, float* %p seq_cst, align 4
226; CHECK: store atomic float %x, float* %p seq_cst, align 4
227  %x = load atomic float, float* %p seq_cst, align 4
228  call void @clobber() ;; keep the load around
229  store atomic float %x, float* %p seq_cst, align 4
230  ret i32 0
231}
232
233define i32 @test20(i32** %p, i8* %v) {
234; CHECK-LABEL: define i32 @test20(
235; CHECK: store atomic i8* %v, i8** [[D:%.*]] unordered, align 4
236  %cast = bitcast i8* %v to i32*
237  store atomic i32* %cast, i32** %p unordered, align 4
238  ret i32 0
239}
240
241define i32 @test21(i32** %p, i8* %v) {
242; CHECK-LABEL: define i32 @test21(
243; CHECK: store atomic i32* %cast, i32** %p monotonic, align 4
244  %cast = bitcast i8* %v to i32*
245  store atomic i32* %cast, i32** %p monotonic, align 4
246  ret i32 0
247}
248
249define void @pr27490a(i8** %p1, i8** %p2) {
250; CHECK-LABEL: define void @pr27490
251; CHECK: %1 = bitcast i8** %p1 to i64*
252; CHECK: %l1 = load i64, i64* %1, align 8
253; CHECK: %2 = bitcast i8** %p2 to i64*
254; CHECK: store volatile i64 %l1, i64* %2, align 8
255  %l = load i8*, i8** %p1
256  store volatile i8* %l, i8** %p2
257  ret void
258}
259
260define void @pr27490b(i8** %p1, i8** %p2) {
261; CHECK-LABEL: define void @pr27490
262; CHECK: %1 = bitcast i8** %p1 to i64*
263; CHECK: %l1 = load i64, i64* %1, align 8
264; CHECK: %2 = bitcast i8** %p2 to i64*
265; CHECK: store atomic i64 %l1, i64* %2 seq_cst, align 8
266  %l = load i8*, i8** %p1
267  store atomic i8* %l, i8** %p2 seq_cst, align 8
268  ret void
269}
270