blob: 75074dc994b8385f204ce1909f1fbb12a23faca9 [file] [log] [blame]
Derek Schuff885dc592017-10-05 21:18:42 +00001; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
Dan Gohman5d2b9352018-01-19 17:16:24 +00002; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s
Derek Schuff885dc592017-10-05 21:18:42 +00003
4; Test that atomic loads are assembled properly.
5
6target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
Sam Clegga5908002018-05-10 17:49:11 +00007target triple = "wasm32-unknown-unknown"
Derek Schuff885dc592017-10-05 21:18:42 +00008
Heejin Ahnd31bc982018-07-09 20:18:21 +00009;===----------------------------------------------------------------------------
10; Atomic loads: 32-bit
11;===----------------------------------------------------------------------------
12
Heejin Ahn402b4902018-07-02 21:22:59 +000013; Basic load.
14
Derek Schuff885dc592017-10-05 21:18:42 +000015; CHECK-LABEL: load_i32_no_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +000016; CHECK: i32.atomic.load $push0=, 0($0){{$}}
17; CHECK-NEXT: return $pop0{{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000018define i32 @load_i32_no_offset(i32 *%p) {
19 %v = load atomic i32, i32* %p seq_cst, align 4
20 ret i32 %v
21}
22
23; With an nuw add, we can fold an offset.
24
25; CHECK-LABEL: load_i32_with_folded_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +000026; CHECK: i32.atomic.load $push0=, 24($0){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000027define i32 @load_i32_with_folded_offset(i32* %p) {
28 %q = ptrtoint i32* %p to i32
29 %r = add nuw i32 %q, 24
30 %s = inttoptr i32 %r to i32*
31 %t = load atomic i32, i32* %s seq_cst, align 4
32 ret i32 %t
33}
34
35; With an inbounds gep, we can fold an offset.
36
37; CHECK-LABEL: load_i32_with_folded_gep_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +000038; CHECK: i32.atomic.load $push0=, 24($0){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000039define i32 @load_i32_with_folded_gep_offset(i32* %p) {
40 %s = getelementptr inbounds i32, i32* %p, i32 6
41 %t = load atomic i32, i32* %s seq_cst, align 4
42 ret i32 %t
43}
44
45; We can't fold a negative offset though, even with an inbounds gep.
46
47; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
48; CHECK: i32.const $push0=, -24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +000049; CHECK: i32.add $push1=, $0, $pop0{{$}}
50; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000051define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {
52 %s = getelementptr inbounds i32, i32* %p, i32 -6
53 %t = load atomic i32, i32* %s seq_cst, align 4
54 ret i32 %t
55}
56
57; Without nuw, and even with nsw, we can't fold an offset.
58
59; CHECK-LABEL: load_i32_with_unfolded_offset:
60; CHECK: i32.const $push0=, 24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +000061; CHECK: i32.add $push1=, $0, $pop0{{$}}
62; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000063define i32 @load_i32_with_unfolded_offset(i32* %p) {
64 %q = ptrtoint i32* %p to i32
65 %r = add nsw i32 %q, 24
66 %s = inttoptr i32 %r to i32*
67 %t = load atomic i32, i32* %s seq_cst, align 4
68 ret i32 %t
69}
70
71; Without inbounds, we can't fold a gep offset.
72
73; CHECK-LABEL: load_i32_with_unfolded_gep_offset:
74; CHECK: i32.const $push0=, 24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +000075; CHECK: i32.add $push1=, $0, $pop0{{$}}
76; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +000077define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {
78 %s = getelementptr i32, i32* %p, i32 6
79 %t = load atomic i32, i32* %s seq_cst, align 4
80 ret i32 %t
81}
82
Heejin Ahnd31bc982018-07-09 20:18:21 +000083; When loading from a fixed address, materialize a zero.
84
85; CHECK-LABEL: load_i32_from_numeric_address
86; CHECK: i32.const $push0=, 0{{$}}
87; CHECK: i32.atomic.load $push1=, 42($pop0){{$}}
88define i32 @load_i32_from_numeric_address() {
89 %s = inttoptr i32 42 to i32*
90 %t = load atomic i32, i32* %s seq_cst, align 4
91 ret i32 %t
92}
93
94; CHECK-LABEL: load_i32_from_global_address
95; CHECK: i32.const $push0=, 0{{$}}
96; CHECK: i32.atomic.load $push1=, gv($pop0){{$}}
97@gv = global i32 0
98define i32 @load_i32_from_global_address() {
99 %t = load atomic i32, i32* @gv seq_cst, align 4
100 ret i32 %t
101}
102
103;===----------------------------------------------------------------------------
104; Atomic loads: 64-bit
105;===----------------------------------------------------------------------------
106
107; Basic load.
108
Derek Schuff885dc592017-10-05 21:18:42 +0000109; CHECK-LABEL: load_i64_no_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000110; CHECK: i64.atomic.load $push0=, 0($0){{$}}
111; CHECK-NEXT: return $pop0{{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000112define i64 @load_i64_no_offset(i64 *%p) {
113 %v = load atomic i64, i64* %p seq_cst, align 8
114 ret i64 %v
115}
116
Heejin Ahnd31bc982018-07-09 20:18:21 +0000117; With an nuw add, we can fold an offset.
Derek Schuff885dc592017-10-05 21:18:42 +0000118
119; CHECK-LABEL: load_i64_with_folded_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000120; CHECK: i64.atomic.load $push0=, 24($0){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000121define i64 @load_i64_with_folded_offset(i64* %p) {
122 %q = ptrtoint i64* %p to i32
123 %r = add nuw i32 %q, 24
124 %s = inttoptr i32 %r to i64*
125 %t = load atomic i64, i64* %s seq_cst, align 8
126 ret i64 %t
127}
128
Heejin Ahnd31bc982018-07-09 20:18:21 +0000129; With an inbounds gep, we can fold an offset.
Derek Schuff885dc592017-10-05 21:18:42 +0000130
131; CHECK-LABEL: load_i64_with_folded_gep_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000132; CHECK: i64.atomic.load $push0=, 24($0){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000133define i64 @load_i64_with_folded_gep_offset(i64* %p) {
134 %s = getelementptr inbounds i64, i64* %p, i32 3
135 %t = load atomic i64, i64* %s seq_cst, align 8
136 ret i64 %t
137}
138
Heejin Ahnd31bc982018-07-09 20:18:21 +0000139; We can't fold a negative offset though, even with an inbounds gep.
Derek Schuff885dc592017-10-05 21:18:42 +0000140
141; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:
142; CHECK: i32.const $push0=, -24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +0000143; CHECK: i32.add $push1=, $0, $pop0{{$}}
144; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000145define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {
146 %s = getelementptr inbounds i64, i64* %p, i32 -3
147 %t = load atomic i64, i64* %s seq_cst, align 8
148 ret i64 %t
149}
150
Heejin Ahnd31bc982018-07-09 20:18:21 +0000151; Without nuw, and even with nsw, we can't fold an offset.
Derek Schuff885dc592017-10-05 21:18:42 +0000152
153; CHECK-LABEL: load_i64_with_unfolded_offset:
154; CHECK: i32.const $push0=, 24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +0000155; CHECK: i32.add $push1=, $0, $pop0{{$}}
156; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000157define i64 @load_i64_with_unfolded_offset(i64* %p) {
158 %q = ptrtoint i64* %p to i32
159 %r = add nsw i32 %q, 24
160 %s = inttoptr i32 %r to i64*
161 %t = load atomic i64, i64* %s seq_cst, align 8
162 ret i64 %t
163}
164
Heejin Ahnd31bc982018-07-09 20:18:21 +0000165; Without inbounds, we can't fold a gep offset.
Derek Schuff885dc592017-10-05 21:18:42 +0000166
167; CHECK-LABEL: load_i64_with_unfolded_gep_offset:
168; CHECK: i32.const $push0=, 24{{$}}
Heejin Ahnd31bc982018-07-09 20:18:21 +0000169; CHECK: i32.add $push1=, $0, $pop0{{$}}
170; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
Derek Schuff885dc592017-10-05 21:18:42 +0000171define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {
172 %s = getelementptr i64, i64* %p, i32 3
173 %t = load atomic i64, i64* %s seq_cst, align 8
174 ret i64 %t
175}
176
Heejin Ahnd31bc982018-07-09 20:18:21 +0000177;===----------------------------------------------------------------------------
178; Atomic stores: 32-bit
179;===----------------------------------------------------------------------------
Derek Schuff885dc592017-10-05 21:18:42 +0000180
Heejin Ahnd31bc982018-07-09 20:18:21 +0000181; Basic store.
Heejin Ahn402b4902018-07-02 21:22:59 +0000182
183; CHECK-LABEL: store_i32_no_offset:
184; CHECK-NEXT: .param i32, i32{{$}}
185; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
186; CHECK-NEXT: return{{$}}
187define void @store_i32_no_offset(i32 *%p, i32 %v) {
188 store atomic i32 %v, i32* %p seq_cst, align 4
189 ret void
190}
191
Heejin Ahnd31bc982018-07-09 20:18:21 +0000192; With an nuw add, we can fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000193
194; CHECK-LABEL: store_i32_with_folded_offset:
195; CHECK: i32.atomic.store 24($0), $pop0{{$}}
196define void @store_i32_with_folded_offset(i32* %p) {
197 %q = ptrtoint i32* %p to i32
198 %r = add nuw i32 %q, 24
199 %s = inttoptr i32 %r to i32*
200 store atomic i32 0, i32* %s seq_cst, align 4
201 ret void
202}
203
Heejin Ahnd31bc982018-07-09 20:18:21 +0000204; With an inbounds gep, we can fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000205
206; CHECK-LABEL: store_i32_with_folded_gep_offset:
207; CHECK: i32.atomic.store 24($0), $pop0{{$}}
208define void @store_i32_with_folded_gep_offset(i32* %p) {
209 %s = getelementptr inbounds i32, i32* %p, i32 6
210 store atomic i32 0, i32* %s seq_cst, align 4
211 ret void
212}
213
Heejin Ahnd31bc982018-07-09 20:18:21 +0000214; We can't fold a negative offset though, even with an inbounds gep.
Heejin Ahn402b4902018-07-02 21:22:59 +0000215
216; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000217; CHECK: i32.const $push0=, -24{{$}}
218; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000219; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
220define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
221 %s = getelementptr inbounds i32, i32* %p, i32 -6
222 store atomic i32 0, i32* %s seq_cst, align 4
223 ret void
224}
225
Heejin Ahnd31bc982018-07-09 20:18:21 +0000226; Without nuw, and even with nsw, we can't fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000227
228; CHECK-LABEL: store_i32_with_unfolded_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000229; CHECK: i32.const $push0=, 24{{$}}
230; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000231; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
232define void @store_i32_with_unfolded_offset(i32* %p) {
233 %q = ptrtoint i32* %p to i32
234 %r = add nsw i32 %q, 24
235 %s = inttoptr i32 %r to i32*
236 store atomic i32 0, i32* %s seq_cst, align 4
237 ret void
238}
239
Heejin Ahnd31bc982018-07-09 20:18:21 +0000240; Without inbounds, we can't fold a gep offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000241
242; CHECK-LABEL: store_i32_with_unfolded_gep_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000243; CHECK: i32.const $push0=, 24{{$}}
244; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000245; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
246define void @store_i32_with_unfolded_gep_offset(i32* %p) {
247 %s = getelementptr i32, i32* %p, i32 6
248 store atomic i32 0, i32* %s seq_cst, align 4
249 ret void
250}
251
Heejin Ahnd31bc982018-07-09 20:18:21 +0000252; When storing from a fixed address, materialize a zero.
253
254; CHECK-LABEL: store_i32_to_numeric_address:
255; CHECK-NEXT: i32.const $push0=, 0{{$}}
256; CHECK-NEXT: i32.const $push1=, 0{{$}}
257; CHECK-NEXT: i32.atomic.store 42($pop0), $pop1{{$}}
258define void @store_i32_to_numeric_address() {
259 %s = inttoptr i32 42 to i32*
260 store atomic i32 0, i32* %s seq_cst, align 4
261 ret void
262}
263
264; CHECK-LABEL: store_i32_to_global_address:
265; CHECK: i32.const $push0=, 0{{$}}
266; CHECK: i32.const $push1=, 0{{$}}
267; CHECK: i32.atomic.store gv($pop0), $pop1{{$}}
268define void @store_i32_to_global_address() {
269 store atomic i32 0, i32* @gv seq_cst, align 4
270 ret void
271}
272
273;===----------------------------------------------------------------------------
274; Atomic stores: 64-bit
275;===----------------------------------------------------------------------------
276
277; Basic store.
Heejin Ahn402b4902018-07-02 21:22:59 +0000278
279; CHECK-LABEL: store_i64_no_offset:
280; CHECK-NEXT: .param i32, i64{{$}}
281; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
282; CHECK-NEXT: return{{$}}
283define void @store_i64_no_offset(i64 *%p, i64 %v) {
284 store atomic i64 %v, i64* %p seq_cst, align 8
285 ret void
286}
287
Heejin Ahnd31bc982018-07-09 20:18:21 +0000288; With an nuw add, we can fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000289
290; CHECK-LABEL: store_i64_with_folded_offset:
291; CHECK: i64.atomic.store 24($0), $pop0{{$}}
292define void @store_i64_with_folded_offset(i64* %p) {
293 %q = ptrtoint i64* %p to i32
294 %r = add nuw i32 %q, 24
295 %s = inttoptr i32 %r to i64*
296 store atomic i64 0, i64* %s seq_cst, align 8
297 ret void
298}
299
Heejin Ahnd31bc982018-07-09 20:18:21 +0000300; With an inbounds gep, we can fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000301
302; CHECK-LABEL: store_i64_with_folded_gep_offset:
303; CHECK: i64.atomic.store 24($0), $pop0{{$}}
304define void @store_i64_with_folded_gep_offset(i64* %p) {
305 %s = getelementptr inbounds i64, i64* %p, i32 3
306 store atomic i64 0, i64* %s seq_cst, align 8
307 ret void
308}
309
Heejin Ahnd31bc982018-07-09 20:18:21 +0000310; We can't fold a negative offset though, even with an inbounds gep.
Heejin Ahn402b4902018-07-02 21:22:59 +0000311
312; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000313; CHECK: i32.const $push0=, -24{{$}}
314; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000315; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
316define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
317 %s = getelementptr inbounds i64, i64* %p, i32 -3
318 store atomic i64 0, i64* %s seq_cst, align 8
319 ret void
320}
321
Heejin Ahnd31bc982018-07-09 20:18:21 +0000322; Without nuw, and even with nsw, we can't fold an offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000323
324; CHECK-LABEL: store_i64_with_unfolded_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000325; CHECK: i32.const $push0=, 24{{$}}
326; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000327; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
328define void @store_i64_with_unfolded_offset(i64* %p) {
329 %q = ptrtoint i64* %p to i32
330 %r = add nsw i32 %q, 24
331 %s = inttoptr i32 %r to i64*
332 store atomic i64 0, i64* %s seq_cst, align 8
333 ret void
334}
335
Heejin Ahnd31bc982018-07-09 20:18:21 +0000336; Without inbounds, we can't fold a gep offset.
Heejin Ahn402b4902018-07-02 21:22:59 +0000337
338; CHECK-LABEL: store_i64_with_unfolded_gep_offset:
Heejin Ahnd31bc982018-07-09 20:18:21 +0000339; CHECK: i32.const $push0=, 24{{$}}
340; CHECK: i32.add $push1=, $0, $pop0{{$}}
Heejin Ahn402b4902018-07-02 21:22:59 +0000341; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
342define void @store_i64_with_unfolded_gep_offset(i64* %p) {
343 %s = getelementptr i64, i64* %p, i32 3
344 store atomic i64 0, i64* %s seq_cst, align 8
345 ret void
346}
347
Heejin Ahnd31bc982018-07-09 20:18:21 +0000348;===----------------------------------------------------------------------------
349; Atomic sign-extending loads
350;===----------------------------------------------------------------------------
Heejin Ahn402b4902018-07-02 21:22:59 +0000351
Derek Schuff885dc592017-10-05 21:18:42 +0000352; Fold an offset into a sign-extending load.
353
Heejin Ahnd31bc982018-07-09 20:18:21 +0000354; CHECK-LABEL: load_i8_i32_s_with_folded_offset:
Derek Schuff885dc592017-10-05 21:18:42 +0000355; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
356; CHECK-NEXT: i32.extend8_s $push1=, $pop0
Heejin Ahnd31bc982018-07-09 20:18:21 +0000357define i32 @load_i8_i32_s_with_folded_offset(i8* %p) {
Derek Schuff885dc592017-10-05 21:18:42 +0000358 %q = ptrtoint i8* %p to i32
359 %r = add nuw i32 %q, 24
360 %s = inttoptr i32 %r to i8*
361 %t = load atomic i8, i8* %s seq_cst, align 1
362 %u = sext i8 %t to i32
363 ret i32 %u
364}
365
Heejin Ahnd31bc982018-07-09 20:18:21 +0000366; 32->64 sext load gets selected as i32.atomic.load, i64_extend_s/i32
Derek Schuff885dc592017-10-05 21:18:42 +0000367; CHECK-LABEL: load_i32_i64_s_with_folded_offset:
368; CHECK: i32.atomic.load $push0=, 24($0){{$}}
369; CHECK-NEXT: i64.extend_s/i32 $push1=, $pop0{{$}}
370define i64 @load_i32_i64_s_with_folded_offset(i32* %p) {
371 %q = ptrtoint i32* %p to i32
372 %r = add nuw i32 %q, 24
373 %s = inttoptr i32 %r to i32*
374 %t = load atomic i32, i32* %s seq_cst, align 4
375 %u = sext i32 %t to i64
376 ret i64 %u
377}
378
Heejin Ahnd31bc982018-07-09 20:18:21 +0000379; Fold a gep offset into a sign-extending load.
380
381; CHECK-LABEL: load_i8_i32_s_with_folded_gep_offset:
382; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
383; CHECK-NEXT: i32.extend8_s $push1=, $pop0
384define i32 @load_i8_i32_s_with_folded_gep_offset(i8* %p) {
385 %s = getelementptr inbounds i8, i8* %p, i32 24
386 %t = load atomic i8, i8* %s seq_cst, align 1
387 %u = sext i8 %t to i32
388 ret i32 %u
389}
390
391; CHECK-LABEL: load_i16_i32_s_with_folded_gep_offset:
392; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}
393; CHECK-NEXT: i32.extend16_s $push1=, $pop0
394define i32 @load_i16_i32_s_with_folded_gep_offset(i16* %p) {
395 %s = getelementptr inbounds i16, i16* %p, i32 24
396 %t = load atomic i16, i16* %s seq_cst, align 2
397 %u = sext i16 %t to i32
398 ret i32 %u
399}
400
401; CHECK-LABEL: load_i16_i64_s_with_folded_gep_offset:
402; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}
403; CHECK-NEXT: i64.extend16_s $push1=, $pop0
404define i64 @load_i16_i64_s_with_folded_gep_offset(i16* %p) {
405 %s = getelementptr inbounds i16, i16* %p, i32 24
406 %t = load atomic i16, i16* %s seq_cst, align 2
407 %u = sext i16 %t to i64
408 ret i64 %u
409}
410
411; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
412; an 'add' if the or'ed bits are known to be zero.
413
414; CHECK-LABEL: load_i8_i32_s_with_folded_or_offset:
415; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
416; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
417define i32 @load_i8_i32_s_with_folded_or_offset(i32 %x) {
418 %and = and i32 %x, -4
419 %t0 = inttoptr i32 %and to i8*
420 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
421 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
422 %conv = sext i8 %t1 to i32
423 ret i32 %conv
424}
425
426; CHECK-LABEL: load_i8_i64_s_with_folded_or_offset:
427; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
428; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
429define i64 @load_i8_i64_s_with_folded_or_offset(i32 %x) {
430 %and = and i32 %x, -4
431 %t0 = inttoptr i32 %and to i8*
432 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
433 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
434 %conv = sext i8 %t1 to i64
435 ret i64 %conv
436}
437
438; When loading from a fixed address, materialize a zero.
439
440; CHECK-LABEL: load_i16_i32_s_from_numeric_address
441; CHECK: i32.const $push0=, 0{{$}}
442; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}
443; CHECK-NEXT: i32.extend16_s $push2=, $pop1
444define i32 @load_i16_i32_s_from_numeric_address() {
445 %s = inttoptr i32 42 to i16*
446 %t = load atomic i16, i16* %s seq_cst, align 2
447 %u = sext i16 %t to i32
448 ret i32 %u
449}
450
451; CHECK-LABEL: load_i8_i32_s_from_global_address
452; CHECK: i32.const $push0=, 0{{$}}
453; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}
454; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}
455@gv8 = global i8 0
456define i32 @load_i8_i32_s_from_global_address() {
457 %t = load atomic i8, i8* @gv8 seq_cst, align 1
458 %u = sext i8 %t to i32
459 ret i32 %u
460}
461
462;===----------------------------------------------------------------------------
463; Atomic zero-extending loads
464;===----------------------------------------------------------------------------
465
466; Fold an offset into a zero-extending load.
467
468; CHECK-LABEL: load_i8_i32_z_with_folded_offset:
469; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
470define i32 @load_i8_i32_z_with_folded_offset(i8* %p) {
471 %q = ptrtoint i8* %p to i32
472 %r = add nuw i32 %q, 24
473 %s = inttoptr i32 %r to i8*
474 %t = load atomic i8, i8* %s seq_cst, align 1
475 %u = zext i8 %t to i32
476 ret i32 %u
477}
478
479; CHECK-LABEL: load_i32_i64_z_with_folded_offset:
480; CHECK: i64.atomic.load32_u $push0=, 24($0){{$}}
481define i64 @load_i32_i64_z_with_folded_offset(i32* %p) {
482 %q = ptrtoint i32* %p to i32
483 %r = add nuw i32 %q, 24
484 %s = inttoptr i32 %r to i32*
Derek Schuff885dc592017-10-05 21:18:42 +0000485 %t = load atomic i32, i32* %s seq_cst, align 4
486 %u = zext i32 %t to i64
487 ret i64 %u
488}
489
Heejin Ahnd31bc982018-07-09 20:18:21 +0000490; Fold a gep offset into a zero-extending load.
491
492; CHECK-LABEL: load_i8_i32_z_with_folded_gep_offset:
493; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
494define i32 @load_i8_i32_z_with_folded_gep_offset(i8* %p) {
495 %s = getelementptr inbounds i8, i8* %p, i32 24
496 %t = load atomic i8, i8* %s seq_cst, align 1
497 %u = zext i8 %t to i32
498 ret i32 %u
499}
500
501; CHECK-LABEL: load_i16_i32_z_with_folded_gep_offset:
502; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}
503define i32 @load_i16_i32_z_with_folded_gep_offset(i16* %p) {
504 %s = getelementptr inbounds i16, i16* %p, i32 24
505 %t = load atomic i16, i16* %s seq_cst, align 2
506 %u = zext i16 %t to i32
507 ret i32 %u
508}
509
510; CHECK-LABEL: load_i16_i64_z_with_folded_gep_offset:
511; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}
512define i64 @load_i16_i64_z_with_folded_gep_offset(i16* %p) {
513 %s = getelementptr inbounds i16, i16* %p, i64 24
514 %t = load atomic i16, i16* %s seq_cst, align 2
515 %u = zext i16 %t to i64
516 ret i64 %u
517}
518
519; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
520; an 'add' if the or'ed bits are known to be zero.
521
522; CHECK-LABEL: load_i8_i32_z_with_folded_or_offset:
523; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
524define i32 @load_i8_i32_z_with_folded_or_offset(i32 %x) {
525 %and = and i32 %x, -4
526 %t0 = inttoptr i32 %and to i8*
527 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
528 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
529 %conv = zext i8 %t1 to i32
530 ret i32 %conv
531}
532
533; CHECK-LABEL: load_i8_i64_z_with_folded_or_offset:
534; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
535define i64 @load_i8_i64_z_with_folded_or_offset(i32 %x) {
536 %and = and i32 %x, -4
537 %t0 = inttoptr i32 %and to i8*
538 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
539 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
540 %conv = zext i8 %t1 to i64
541 ret i64 %conv
542}
543
544; When loading from a fixed address, materialize a zero.
545
546; CHECK-LABEL: load_i16_i32_z_from_numeric_address
547; CHECK: i32.const $push0=, 0{{$}}
548; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}
549define i32 @load_i16_i32_z_from_numeric_address() {
550 %s = inttoptr i32 42 to i16*
551 %t = load atomic i16, i16* %s seq_cst, align 2
552 %u = zext i16 %t to i32
553 ret i32 %u
554}
555
556; CHECK-LABEL: load_i8_i32_z_from_global_address
557; CHECK: i32.const $push0=, 0{{$}}
558; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}
559define i32 @load_i8_i32_z_from_global_address() {
560 %t = load atomic i8, i8* @gv8 seq_cst, align 1
561 %u = zext i8 %t to i32
562 ret i32 %u
563}
564
Derek Schuff885dc592017-10-05 21:18:42 +0000565; i8 return value should test anyext loads
Heejin Ahnd31bc982018-07-09 20:18:21 +0000566
567; CHECK-LABEL: load_i8_i32_retvalue:
568; CHECK: i32.atomic.load8_u $push0=, 0($0){{$}}
569; CHECK-NEXT: return $pop0{{$}}
570define i8 @load_i8_i32_retvalue(i8 *%p) {
Derek Schuff885dc592017-10-05 21:18:42 +0000571 %v = load atomic i8, i8* %p seq_cst, align 1
572 ret i8 %v
573}
Heejin Ahn402b4902018-07-02 21:22:59 +0000574
Heejin Ahnd31bc982018-07-09 20:18:21 +0000575;===----------------------------------------------------------------------------
576; Atomic truncating stores
577;===----------------------------------------------------------------------------
578
Heejin Ahn402b4902018-07-02 21:22:59 +0000579; Fold an offset into a truncating store.
580
Heejin Ahnd31bc982018-07-09 20:18:21 +0000581; CHECK-LABEL: store_i8_i32_with_folded_offset:
582; CHECK: i32.atomic.store8 24($0), $1{{$}}
583define void @store_i8_i32_with_folded_offset(i8* %p, i32 %v) {
Heejin Ahn402b4902018-07-02 21:22:59 +0000584 %q = ptrtoint i8* %p to i32
585 %r = add nuw i32 %q, 24
586 %s = inttoptr i32 %r to i8*
Heejin Ahnd31bc982018-07-09 20:18:21 +0000587 %t = trunc i32 %v to i8
Heejin Ahn402b4902018-07-02 21:22:59 +0000588 store atomic i8 %t, i8* %s seq_cst, align 1
589 ret void
590}
591
Heejin Ahn402b4902018-07-02 21:22:59 +0000592; CHECK-LABEL: store_i32_i64_with_folded_offset:
593; CHECK: i64.atomic.store32 24($0), $1{{$}}
594define void @store_i32_i64_with_folded_offset(i32* %p, i64 %v) {
595 %q = ptrtoint i32* %p to i32
596 %r = add nuw i32 %q, 24
597 %s = inttoptr i32 %r to i32*
598 %t = trunc i64 %v to i32
599 store atomic i32 %t, i32* %s seq_cst, align 4
600 ret void
601}
602
603; Fold a gep offset into a truncating store.
604
Heejin Ahnd31bc982018-07-09 20:18:21 +0000605; CHECK-LABEL: store_i8_i32_with_folded_gep_offset:
606; CHECK: i32.atomic.store8 24($0), $1{{$}}
607define void @store_i8_i32_with_folded_gep_offset(i8* %p, i32 %v) {
Heejin Ahn402b4902018-07-02 21:22:59 +0000608 %s = getelementptr inbounds i8, i8* %p, i32 24
Heejin Ahnd31bc982018-07-09 20:18:21 +0000609 %t = trunc i32 %v to i8
610 store atomic i8 %t, i8* %s seq_cst, align 1
Heejin Ahn402b4902018-07-02 21:22:59 +0000611 ret void
612}
613
Heejin Ahnd31bc982018-07-09 20:18:21 +0000614; CHECK-LABEL: store_i16_i32_with_folded_gep_offset:
615; CHECK: i32.atomic.store16 48($0), $1{{$}}
616define void @store_i16_i32_with_folded_gep_offset(i16* %p, i32 %v) {
Heejin Ahn402b4902018-07-02 21:22:59 +0000617 %s = getelementptr inbounds i16, i16* %p, i32 24
Heejin Ahnd31bc982018-07-09 20:18:21 +0000618 %t = trunc i32 %v to i16
619 store atomic i16 %t, i16* %s seq_cst, align 2
Heejin Ahn402b4902018-07-02 21:22:59 +0000620 ret void
621}
622
623; CHECK-LABEL: store_i16_i64_with_folded_gep_offset:
624; CHECK: i64.atomic.store16 48($0), $1{{$}}
625define void @store_i16_i64_with_folded_gep_offset(i16* %p, i64 %v) {
626 %s = getelementptr inbounds i16, i16* %p, i32 24
627 %t = trunc i64 %v to i16
628 store atomic i16 %t, i16* %s seq_cst, align 2
629 ret void
630}
631
Heejin Ahnd31bc982018-07-09 20:18:21 +0000632; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
633; an 'add' if the or'ed bits are known to be zero.
Heejin Ahn402b4902018-07-02 21:22:59 +0000634
Heejin Ahnd31bc982018-07-09 20:18:21 +0000635; CHECK-LABEL: store_i8_i32_with_folded_or_offset:
636; CHECK: i32.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}
637define void @store_i8_i32_with_folded_or_offset(i32 %x, i32 %v) {
Heejin Ahn402b4902018-07-02 21:22:59 +0000638 %and = and i32 %x, -4
639 %p = inttoptr i32 %and to i8*
640 %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
Heejin Ahnd31bc982018-07-09 20:18:21 +0000641 %t = trunc i32 %v to i8
642 store atomic i8 %t, i8* %arrayidx seq_cst, align 1
Heejin Ahn402b4902018-07-02 21:22:59 +0000643 ret void
644}
645
646; CHECK-LABEL: store_i8_i64_with_folded_or_offset:
647; CHECK: i64.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}
648define void @store_i8_i64_with_folded_or_offset(i32 %x, i64 %v) {
649 %and = and i32 %x, -4
650 %p = inttoptr i32 %and to i8*
651 %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
652 %t = trunc i64 %v to i8
653 store atomic i8 %t, i8* %arrayidx seq_cst, align 1
654 ret void
655}