blob: bb1799ba267883e2fb1740cf258b88cde8e39193 [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
9; CHECK-LABEL: load_i32_no_offset:
10; CHECK: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
11; CHECK-NEXT: return $pop[[NUM]]{{$}}
12define i32 @load_i32_no_offset(i32 *%p) {
13 %v = load atomic i32, i32* %p seq_cst, align 4
14 ret i32 %v
15}
16
17; With an nuw add, we can fold an offset.
18
19; CHECK-LABEL: load_i32_with_folded_offset:
20; CHECK: i32.atomic.load $push0=, 24($0){{$}}
21define i32 @load_i32_with_folded_offset(i32* %p) {
22 %q = ptrtoint i32* %p to i32
23 %r = add nuw i32 %q, 24
24 %s = inttoptr i32 %r to i32*
25 %t = load atomic i32, i32* %s seq_cst, align 4
26 ret i32 %t
27}
28
29; With an inbounds gep, we can fold an offset.
30
31; CHECK-LABEL: load_i32_with_folded_gep_offset:
32; CHECK: i32.atomic.load $push0=, 24($0){{$}}
33define i32 @load_i32_with_folded_gep_offset(i32* %p) {
34 %s = getelementptr inbounds i32, i32* %p, i32 6
35 %t = load atomic i32, i32* %s seq_cst, align 4
36 ret i32 %t
37}
38
39; We can't fold a negative offset though, even with an inbounds gep.
40
41; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
42; CHECK: i32.const $push0=, -24{{$}}
43; CHECK: i32.add $push1=, $0, $pop0{{$}}
44; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
45define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {
46 %s = getelementptr inbounds i32, i32* %p, i32 -6
47 %t = load atomic i32, i32* %s seq_cst, align 4
48 ret i32 %t
49}
50
51; Without nuw, and even with nsw, we can't fold an offset.
52
53; CHECK-LABEL: load_i32_with_unfolded_offset:
54; CHECK: i32.const $push0=, 24{{$}}
55; CHECK: i32.add $push1=, $0, $pop0{{$}}
56; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
57define i32 @load_i32_with_unfolded_offset(i32* %p) {
58 %q = ptrtoint i32* %p to i32
59 %r = add nsw i32 %q, 24
60 %s = inttoptr i32 %r to i32*
61 %t = load atomic i32, i32* %s seq_cst, align 4
62 ret i32 %t
63}
64
65; Without inbounds, we can't fold a gep offset.
66
67; CHECK-LABEL: load_i32_with_unfolded_gep_offset:
68; CHECK: i32.const $push0=, 24{{$}}
69; CHECK: i32.add $push1=, $0, $pop0{{$}}
70; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
71define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {
72 %s = getelementptr i32, i32* %p, i32 6
73 %t = load atomic i32, i32* %s seq_cst, align 4
74 ret i32 %t
75}
76
77; CHECK-LABEL: load_i64_no_offset:
78; CHECK: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
79; CHECK-NEXT: return $pop[[NUM]]{{$}}
80define i64 @load_i64_no_offset(i64 *%p) {
81 %v = load atomic i64, i64* %p seq_cst, align 8
82 ret i64 %v
83}
84
85; Same as above but with i64.
86
87; CHECK-LABEL: load_i64_with_folded_offset:
88; CHECK: i64.atomic.load $push0=, 24($0){{$}}
89define i64 @load_i64_with_folded_offset(i64* %p) {
90 %q = ptrtoint i64* %p to i32
91 %r = add nuw i32 %q, 24
92 %s = inttoptr i32 %r to i64*
93 %t = load atomic i64, i64* %s seq_cst, align 8
94 ret i64 %t
95}
96
97; Same as above but with i64.
98
99; CHECK-LABEL: load_i64_with_folded_gep_offset:
100; CHECK: i64.atomic.load $push0=, 24($0){{$}}
101define i64 @load_i64_with_folded_gep_offset(i64* %p) {
102 %s = getelementptr inbounds i64, i64* %p, i32 3
103 %t = load atomic i64, i64* %s seq_cst, align 8
104 ret i64 %t
105}
106
107; Same as above but with i64.
108
109; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:
110; CHECK: i32.const $push0=, -24{{$}}
111; CHECK: i32.add $push1=, $0, $pop0{{$}}
112; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
113define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {
114 %s = getelementptr inbounds i64, i64* %p, i32 -3
115 %t = load atomic i64, i64* %s seq_cst, align 8
116 ret i64 %t
117}
118
119; Same as above but with i64.
120
121; CHECK-LABEL: load_i64_with_unfolded_offset:
122; CHECK: i32.const $push0=, 24{{$}}
123; CHECK: i32.add $push1=, $0, $pop0{{$}}
124; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
125define i64 @load_i64_with_unfolded_offset(i64* %p) {
126 %q = ptrtoint i64* %p to i32
127 %r = add nsw i32 %q, 24
128 %s = inttoptr i32 %r to i64*
129 %t = load atomic i64, i64* %s seq_cst, align 8
130 ret i64 %t
131}
132
133; Same as above but with i64.
134
135; CHECK-LABEL: load_i64_with_unfolded_gep_offset:
136; CHECK: i32.const $push0=, 24{{$}}
137; CHECK: i32.add $push1=, $0, $pop0{{$}}
138; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
139define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {
140 %s = getelementptr i64, i64* %p, i32 3
141 %t = load atomic i64, i64* %s seq_cst, align 8
142 ret i64 %t
143}
144
145; CHECK-LABEL: load_i32_with_folded_or_offset:
146; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
147; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
148define i32 @load_i32_with_folded_or_offset(i32 %x) {
149 %and = and i32 %x, -4
150 %t0 = inttoptr i32 %and to i8*
151 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
152 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8
153 %conv = sext i8 %t1 to i32
154 ret i32 %conv
155}
156
157; When loading from a fixed address, materialize a zero.
158
159; CHECK-LABEL: load_i32_from_numeric_address
160; CHECK: i32.const $push0=, 0{{$}}
161; CHECK: i32.atomic.load $push1=, 42($pop0){{$}}
162define i32 @load_i32_from_numeric_address() {
163 %s = inttoptr i32 42 to i32*
164 %t = load atomic i32, i32* %s seq_cst, align 4
165 ret i32 %t
166}
167
168
169; CHECK-LABEL: load_i32_from_global_address
170; CHECK: i32.const $push0=, 0{{$}}
171; CHECK: i32.atomic.load $push1=, gv($pop0){{$}}
172@gv = global i32 0
173define i32 @load_i32_from_global_address() {
174 %t = load atomic i32, i32* @gv seq_cst, align 4
175 ret i32 %t
176}
177
178; Fold an offset into a sign-extending load.
179
180; CHECK-LABEL: load_i8_s_with_folded_offset:
181; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
182; CHECK-NEXT: i32.extend8_s $push1=, $pop0
183define i32 @load_i8_s_with_folded_offset(i8* %p) {
184 %q = ptrtoint i8* %p to i32
185 %r = add nuw i32 %q, 24
186 %s = inttoptr i32 %r to i8*
187 %t = load atomic i8, i8* %s seq_cst, align 1
188 %u = sext i8 %t to i32
189 ret i32 %u
190}
191
192; Fold a gep offset into a sign-extending load.
193
194; CHECK-LABEL: load_i8_s_with_folded_gep_offset:
195; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
196; CHECK-NEXT: i32.extend8_s $push1=, $pop0
197define i32 @load_i8_s_with_folded_gep_offset(i8* %p) {
198 %s = getelementptr inbounds i8, i8* %p, i32 24
199 %t = load atomic i8, i8* %s seq_cst, align 1
200 %u = sext i8 %t to i32
201 ret i32 %u
202}
203
204; CHECK-LABEL: load_i16_s_i64_with_folded_gep_offset:
205; CHECK: i64.atomic.load16_u $push0=, 6($0){{$}}
206define i64 @load_i16_s_i64_with_folded_gep_offset(i16* %p) {
207 %s = getelementptr inbounds i16, i16* %p, i32 3
208 %t = load atomic i16, i16* %s seq_cst, align 2
209 %u = zext i16 %t to i64
210 ret i64 %u
211}
212
213; CHECK-LABEL: load_i64_with_folded_or_offset:
214; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
215; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
216define i64 @load_i64_with_folded_or_offset(i32 %x) {
217 %and = and i32 %x, -4
218 %t0 = inttoptr i32 %and to i8*
219 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
220 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8
221 %conv = sext i8 %t1 to i64
222 ret i64 %conv
223}
224
225
226; Fold an offset into a zero-extending load.
227
228; CHECK-LABEL: load_i16_u_with_folded_offset:
229; CHECK: i32.atomic.load16_u $push0=, 24($0){{$}}
230define i32 @load_i16_u_with_folded_offset(i8* %p) {
231 %q = ptrtoint i8* %p to i32
232 %r = add nuw i32 %q, 24
233 %s = inttoptr i32 %r to i16*
234 %t = load atomic i16, i16* %s seq_cst, align 2
235 %u = zext i16 %t to i32
236 ret i32 %u
237}
238
239; Fold a gep offset into a zero-extending load.
240
241; CHECK-LABEL: load_i8_u_with_folded_gep_offset:
242; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
243define i32 @load_i8_u_with_folded_gep_offset(i8* %p) {
244 %s = getelementptr inbounds i8, i8* %p, i32 24
245 %t = load atomic i8, i8* %s seq_cst, align 1
246 %u = zext i8 %t to i32
247 ret i32 %u
248}
249
250
251; When loading from a fixed address, materialize a zero.
252; As above but with extending load.
253
254; CHECK-LABEL: load_zext_i32_from_numeric_address
255; CHECK: i32.const $push0=, 0{{$}}
256; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}
257define i32 @load_zext_i32_from_numeric_address() {
258 %s = inttoptr i32 42 to i16*
259 %t = load atomic i16, i16* %s seq_cst, align 2
260 %u = zext i16 %t to i32
261 ret i32 %u
262}
263
264; CHECK-LABEL: load_sext_i32_from_global_address
265; CHECK: i32.const $push0=, 0{{$}}
266; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}
267; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}
268@gv8 = global i8 0
269define i32 @load_sext_i32_from_global_address() {
270 %t = load atomic i8, i8* @gv8 seq_cst, align 1
271 %u = sext i8 %t to i32
272 ret i32 %u
273}
274
275; Fold an offset into a sign-extending load.
276; As above but 32 extended to 64 bit.
277; CHECK-LABEL: load_i32_i64_s_with_folded_offset:
278; CHECK: i32.atomic.load $push0=, 24($0){{$}}
279; CHECK-NEXT: i64.extend_s/i32 $push1=, $pop0{{$}}
280define i64 @load_i32_i64_s_with_folded_offset(i32* %p) {
281 %q = ptrtoint i32* %p to i32
282 %r = add nuw i32 %q, 24
283 %s = inttoptr i32 %r to i32*
284 %t = load atomic i32, i32* %s seq_cst, align 4
285 %u = sext i32 %t to i64
286 ret i64 %u
287}
288
289; Fold a gep offset into a zero-extending load.
290; As above but 32 extended to 64 bit.
291; CHECK-LABEL: load_i32_i64_u_with_folded_gep_offset:
292; CHECK: i64.atomic.load32_u $push0=, 96($0){{$}}
293define i64 @load_i32_i64_u_with_folded_gep_offset(i32* %p) {
294 %s = getelementptr inbounds i32, i32* %p, i32 24
295 %t = load atomic i32, i32* %s seq_cst, align 4
296 %u = zext i32 %t to i64
297 ret i64 %u
298}
299
300; i8 return value should test anyext loads
301; CHECK-LABEL: ldi8_a1:
302; CHECK: i32.atomic.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
303; CHECK-NEXT: return $pop[[NUM]]{{$}}
304define i8 @ldi8_a1(i8 *%p) {
305 %v = load atomic i8, i8* %p seq_cst, align 1
306 ret i8 %v
307}