blob: b82d6ba1660c4680eeb238fb1c3deefb8c2111a6 [file] [log] [blame]
Dan Gohman4b9d7912015-12-15 22:01:29 +00001; RUN: llc < %s -asm-verbose=false | FileCheck %s
2
3; Test constant load and store address offsets.
4
Dan Gohman0c6f5ac2016-01-07 03:19:23 +00005target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
Dan Gohman4b9d7912015-12-15 22:01:29 +00006target triple = "wasm32-unknown-unknown"
7
8; With an nuw add, we can fold an offset.
9
10; CHECK-LABEL: load_i32_with_folded_offset:
11; CHECK: i32.load $push0=, 24($0){{$}}
12define i32 @load_i32_with_folded_offset(i32* %p) {
13 %q = ptrtoint i32* %p to i32
14 %r = add nuw i32 %q, 24
15 %s = inttoptr i32 %r to i32*
16 %t = load i32, i32* %s
17 ret i32 %t
18}
19
Dan Gohman797f639e2016-01-06 00:43:06 +000020; With an inbounds gep, we can fold an offset.
21
22; CHECK-LABEL: load_i32_with_folded_gep_offset:
23; CHECK: i32.load $push0=, 24($0){{$}}
24define i32 @load_i32_with_folded_gep_offset(i32* %p) {
25 %s = getelementptr inbounds i32, i32* %p, i32 6
26 %t = load i32, i32* %s
27 ret i32 %t
28}
29
30; We can't fold a negative offset though, even with an inbounds gep.
31
32; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
33; CHECK: i32.const $push0=, -24{{$}}
34; CHECK: i32.add $push1=, $0, $pop0{{$}}
35; CHECK: i32.load $push2=, 0($pop1){{$}}
36define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {
37 %s = getelementptr inbounds i32, i32* %p, i32 -6
38 %t = load i32, i32* %s
39 ret i32 %t
40}
41
Dan Gohman4b9d7912015-12-15 22:01:29 +000042; Without nuw, and even with nsw, we can't fold an offset.
43
44; CHECK-LABEL: load_i32_with_unfolded_offset:
45; CHECK: i32.const $push0=, 24{{$}}
46; CHECK: i32.add $push1=, $0, $pop0{{$}}
47; CHECK: i32.load $push2=, 0($pop1){{$}}
48define i32 @load_i32_with_unfolded_offset(i32* %p) {
49 %q = ptrtoint i32* %p to i32
50 %r = add nsw i32 %q, 24
51 %s = inttoptr i32 %r to i32*
52 %t = load i32, i32* %s
53 ret i32 %t
54}
55
Dan Gohman797f639e2016-01-06 00:43:06 +000056; Without inbounds, we can't fold a gep offset.
57
58; CHECK-LABEL: load_i32_with_unfolded_gep_offset:
59; CHECK: i32.const $push0=, 24{{$}}
60; CHECK: i32.add $push1=, $0, $pop0{{$}}
61; CHECK: i32.load $push2=, 0($pop1){{$}}
62define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {
63 %s = getelementptr i32, i32* %p, i32 6
64 %t = load i32, i32* %s
65 ret i32 %t
66}
67
Dan Gohman4b9d7912015-12-15 22:01:29 +000068; Same as above but with i64.
69
70; CHECK-LABEL: load_i64_with_folded_offset:
71; CHECK: i64.load $push0=, 24($0){{$}}
72define i64 @load_i64_with_folded_offset(i64* %p) {
73 %q = ptrtoint i64* %p to i32
74 %r = add nuw i32 %q, 24
75 %s = inttoptr i32 %r to i64*
76 %t = load i64, i64* %s
77 ret i64 %t
78}
79
80; Same as above but with i64.
81
Dan Gohman797f639e2016-01-06 00:43:06 +000082; CHECK-LABEL: load_i64_with_folded_gep_offset:
83; CHECK: i64.load $push0=, 24($0){{$}}
84define i64 @load_i64_with_folded_gep_offset(i64* %p) {
85 %s = getelementptr inbounds i64, i64* %p, i32 3
86 %t = load i64, i64* %s
87 ret i64 %t
88}
89
90; Same as above but with i64.
91
92; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:
93; CHECK: i32.const $push0=, -24{{$}}
94; CHECK: i32.add $push1=, $0, $pop0{{$}}
95; CHECK: i64.load $push2=, 0($pop1){{$}}
96define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {
97 %s = getelementptr inbounds i64, i64* %p, i32 -3
98 %t = load i64, i64* %s
99 ret i64 %t
100}
101
102; Same as above but with i64.
103
Dan Gohman4b9d7912015-12-15 22:01:29 +0000104; CHECK-LABEL: load_i64_with_unfolded_offset:
105; CHECK: i32.const $push0=, 24{{$}}
106; CHECK: i32.add $push1=, $0, $pop0{{$}}
107; CHECK: i64.load $push2=, 0($pop1){{$}}
108define i64 @load_i64_with_unfolded_offset(i64* %p) {
109 %q = ptrtoint i64* %p to i32
110 %r = add nsw i32 %q, 24
111 %s = inttoptr i32 %r to i64*
112 %t = load i64, i64* %s
113 ret i64 %t
114}
115
Dan Gohman797f639e2016-01-06 00:43:06 +0000116; Same as above but with i64.
117
118; CHECK-LABEL: load_i64_with_unfolded_gep_offset:
119; CHECK: i32.const $push0=, 24{{$}}
120; CHECK: i32.add $push1=, $0, $pop0{{$}}
121; CHECK: i64.load $push2=, 0($pop1){{$}}
122define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {
123 %s = getelementptr i64, i64* %p, i32 3
124 %t = load i64, i64* %s
125 ret i64 %t
126}
127
Dan Gohman3b09d272016-02-22 20:04:02 +0000128; CHECK-LABEL: load_i32_with_folded_or_offset:
129; CHECK: i32.load8_s $push{{[0-9]+}}=, 2($pop{{[0-9]+}}){{$}}
130define i32 @load_i32_with_folded_or_offset(i32 %x) {
131 %and = and i32 %x, -4
132 %t0 = inttoptr i32 %and to i8*
133 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
134 %t1 = load i8, i8* %arrayidx, align 1
135 %conv = sext i8 %t1 to i32
136 ret i32 %conv
137}
138
Dan Gohman4b9d7912015-12-15 22:01:29 +0000139; Same as above but with store.
140
141; CHECK-LABEL: store_i32_with_folded_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000142; CHECK: i32.store $drop=, 24($0), $pop0{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000143define void @store_i32_with_folded_offset(i32* %p) {
144 %q = ptrtoint i32* %p to i32
145 %r = add nuw i32 %q, 24
146 %s = inttoptr i32 %r to i32*
147 store i32 0, i32* %s
148 ret void
149}
150
151; Same as above but with store.
152
Dan Gohman797f639e2016-01-06 00:43:06 +0000153; CHECK-LABEL: store_i32_with_folded_gep_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000154; CHECK: i32.store $drop=, 24($0), $pop0{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000155define void @store_i32_with_folded_gep_offset(i32* %p) {
156 %s = getelementptr inbounds i32, i32* %p, i32 6
157 store i32 0, i32* %s
158 ret void
159}
160
161; Same as above but with store.
162
163; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:
164; CHECK: i32.const $push0=, -24{{$}}
165; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000166; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000167define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
168 %s = getelementptr inbounds i32, i32* %p, i32 -6
169 store i32 0, i32* %s
170 ret void
171}
172
173; Same as above but with store.
174
Dan Gohman4b9d7912015-12-15 22:01:29 +0000175; CHECK-LABEL: store_i32_with_unfolded_offset:
176; CHECK: i32.const $push0=, 24{{$}}
177; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000178; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000179define void @store_i32_with_unfolded_offset(i32* %p) {
180 %q = ptrtoint i32* %p to i32
181 %r = add nsw i32 %q, 24
182 %s = inttoptr i32 %r to i32*
183 store i32 0, i32* %s
184 ret void
185}
186
Dan Gohman797f639e2016-01-06 00:43:06 +0000187; Same as above but with store.
188
189; CHECK-LABEL: store_i32_with_unfolded_gep_offset:
190; CHECK: i32.const $push0=, 24{{$}}
191; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000192; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000193define void @store_i32_with_unfolded_gep_offset(i32* %p) {
194 %s = getelementptr i32, i32* %p, i32 6
195 store i32 0, i32* %s
196 ret void
197}
198
Dan Gohman4b9d7912015-12-15 22:01:29 +0000199; Same as above but with store with i64.
200
201; CHECK-LABEL: store_i64_with_folded_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000202; CHECK: i64.store $drop=, 24($0), $pop0{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000203define void @store_i64_with_folded_offset(i64* %p) {
204 %q = ptrtoint i64* %p to i32
205 %r = add nuw i32 %q, 24
206 %s = inttoptr i32 %r to i64*
207 store i64 0, i64* %s
208 ret void
209}
210
211; Same as above but with store with i64.
212
Dan Gohman797f639e2016-01-06 00:43:06 +0000213; CHECK-LABEL: store_i64_with_folded_gep_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000214; CHECK: i64.store $drop=, 24($0), $pop0{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000215define void @store_i64_with_folded_gep_offset(i64* %p) {
216 %s = getelementptr inbounds i64, i64* %p, i32 3
217 store i64 0, i64* %s
218 ret void
219}
220
221; Same as above but with store with i64.
222
223; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:
224; CHECK: i32.const $push0=, -24{{$}}
225; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000226; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000227define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
228 %s = getelementptr inbounds i64, i64* %p, i32 -3
229 store i64 0, i64* %s
230 ret void
231}
232
233; Same as above but with store with i64.
234
Dan Gohman4b9d7912015-12-15 22:01:29 +0000235; CHECK-LABEL: store_i64_with_unfolded_offset:
236; CHECK: i32.const $push0=, 24{{$}}
237; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000238; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000239define void @store_i64_with_unfolded_offset(i64* %p) {
240 %q = ptrtoint i64* %p to i32
241 %r = add nsw i32 %q, 24
242 %s = inttoptr i32 %r to i64*
243 store i64 0, i64* %s
244 ret void
245}
246
Dan Gohman797f639e2016-01-06 00:43:06 +0000247; Same as above but with store with i64.
248
249; CHECK-LABEL: store_i64_with_unfolded_gep_offset:
250; CHECK: i32.const $push0=, 24{{$}}
251; CHECK: i32.add $push1=, $0, $pop0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000252; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000253define void @store_i64_with_unfolded_gep_offset(i64* %p) {
254 %s = getelementptr i64, i64* %p, i32 3
255 store i64 0, i64* %s
256 ret void
257}
258
Dan Gohman3b09d272016-02-22 20:04:02 +0000259; CHECK-LABEL: store_i32_with_folded_or_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000260; CHECK: i32.store8 $drop=, 2($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
Dan Gohman3b09d272016-02-22 20:04:02 +0000261define void @store_i32_with_folded_or_offset(i32 %x) {
262 %and = and i32 %x, -4
263 %t0 = inttoptr i32 %and to i8*
264 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
265 store i8 0, i8* %arrayidx, align 1
266 ret void
267}
268
Dan Gohman4b9d7912015-12-15 22:01:29 +0000269; When loading from a fixed address, materialize a zero.
270
271; CHECK-LABEL: load_i32_from_numeric_address
272; CHECK: i32.const $push0=, 0{{$}}
273; CHECK: i32.load $push1=, 42($pop0){{$}}
274define i32 @load_i32_from_numeric_address() {
275 %s = inttoptr i32 42 to i32*
276 %t = load i32, i32* %s
277 ret i32 %t
278}
279
280; CHECK-LABEL: load_i32_from_global_address
281; CHECK: i32.const $push0=, 0{{$}}
282; CHECK: i32.load $push1=, gv($pop0){{$}}
283@gv = global i32 0
284define i32 @load_i32_from_global_address() {
285 %t = load i32, i32* @gv
286 ret i32 %t
287}
288
289; CHECK-LABEL: store_i32_to_numeric_address:
Dan Gohmanb6fd39a2016-01-19 16:59:23 +0000290; CHECK-NEXT: i32.const $push0=, 0{{$}}
291; CHECK-NEXT: i32.const $push1=, 0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000292; CHECK-NEXT: i32.store $drop=, 42($pop0), $pop1{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000293define void @store_i32_to_numeric_address() {
294 %s = inttoptr i32 42 to i32*
295 store i32 0, i32* %s
296 ret void
297}
298
299; CHECK-LABEL: store_i32_to_global_address:
Dan Gohmanb6fd39a2016-01-19 16:59:23 +0000300; CHECK: i32.const $push0=, 0{{$}}
301; CHECK: i32.const $push1=, 0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000302; CHECK: i32.store $drop=, gv($pop0), $pop1{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000303define void @store_i32_to_global_address() {
304 store i32 0, i32* @gv
305 ret void
306}
307
308; Fold an offset into a sign-extending load.
309
310; CHECK-LABEL: load_i8_s_with_folded_offset:
311; CHECK: i32.load8_s $push0=, 24($0){{$}}
312define i32 @load_i8_s_with_folded_offset(i8* %p) {
313 %q = ptrtoint i8* %p to i32
314 %r = add nuw i32 %q, 24
315 %s = inttoptr i32 %r to i8*
316 %t = load i8, i8* %s
317 %u = sext i8 %t to i32
318 ret i32 %u
319}
320
Dan Gohman797f639e2016-01-06 00:43:06 +0000321; Fold a gep offset into a sign-extending load.
322
323; CHECK-LABEL: load_i8_s_with_folded_gep_offset:
324; CHECK: i32.load8_s $push0=, 24($0){{$}}
325define i32 @load_i8_s_with_folded_gep_offset(i8* %p) {
326 %s = getelementptr inbounds i8, i8* %p, i32 24
327 %t = load i8, i8* %s
328 %u = sext i8 %t to i32
329 ret i32 %u
330}
331
Dan Gohman4b9d7912015-12-15 22:01:29 +0000332; Fold an offset into a zero-extending load.
333
334; CHECK-LABEL: load_i8_u_with_folded_offset:
335; CHECK: i32.load8_u $push0=, 24($0){{$}}
336define i32 @load_i8_u_with_folded_offset(i8* %p) {
337 %q = ptrtoint i8* %p to i32
338 %r = add nuw i32 %q, 24
339 %s = inttoptr i32 %r to i8*
340 %t = load i8, i8* %s
341 %u = zext i8 %t to i32
342 ret i32 %u
343}
344
Dan Gohman797f639e2016-01-06 00:43:06 +0000345; Fold a gep offset into a zero-extending load.
346
347; CHECK-LABEL: load_i8_u_with_folded_gep_offset:
348; CHECK: i32.load8_u $push0=, 24($0){{$}}
349define i32 @load_i8_u_with_folded_gep_offset(i8* %p) {
350 %s = getelementptr inbounds i8, i8* %p, i32 24
351 %t = load i8, i8* %s
352 %u = zext i8 %t to i32
353 ret i32 %u
354}
355
Dan Gohman4b9d7912015-12-15 22:01:29 +0000356; Fold an offset into a truncating store.
357
358; CHECK-LABEL: store_i8_with_folded_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000359; CHECK: i32.store8 $drop=, 24($0), $pop0{{$}}
Dan Gohman4b9d7912015-12-15 22:01:29 +0000360define void @store_i8_with_folded_offset(i8* %p) {
361 %q = ptrtoint i8* %p to i32
362 %r = add nuw i32 %q, 24
363 %s = inttoptr i32 %r to i8*
364 store i8 0, i8* %s
365 ret void
366}
Dan Gohman797f639e2016-01-06 00:43:06 +0000367
368; Fold a gep offset into a truncating store.
369
370; CHECK-LABEL: store_i8_with_folded_gep_offset:
Dan Gohman71008092016-05-17 23:19:03 +0000371; CHECK: i32.store8 $drop=, 24($0), $pop0{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000372define void @store_i8_with_folded_gep_offset(i8* %p) {
373 %s = getelementptr inbounds i8, i8* %p, i32 24
374 store i8 0, i8* %s
375 ret void
376}
377
378; Fold the offsets when lowering aggregate loads and stores.
379
380; CHECK-LABEL: aggregate_load_store:
381; CHECK: i32.load $2=, 0($0){{$}}
382; CHECK: i32.load $3=, 4($0){{$}}
383; CHECK: i32.load $4=, 8($0){{$}}
384; CHECK: i32.load $push0=, 12($0){{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000385; CHECK: i32.store $drop=, 12($1), $pop0{{$}}
386; CHECK: i32.store $drop=, 8($1), $4{{$}}
387; CHECK: i32.store $drop=, 4($1), $3{{$}}
388; CHECK: i32.store $drop=, 0($1), $2{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000389define void @aggregate_load_store({i32,i32,i32,i32}* %p, {i32,i32,i32,i32}* %q) {
390 ; volatile so that things stay in order for the tests above
391 %t = load volatile {i32,i32,i32,i32}, {i32, i32,i32,i32}* %p
392 store volatile {i32,i32,i32,i32} %t, {i32, i32,i32,i32}* %q
393 ret void
394}
395
Dan Gohmanbb372242016-01-26 03:39:31 +0000396; Fold the offsets when lowering aggregate return values. The stores get
397; merged into i64 stores.
Dan Gohman797f639e2016-01-06 00:43:06 +0000398
399; CHECK-LABEL: aggregate_return:
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000400; CHECK: i64.const $push[[L0:[0-9]+]]=, 0{{$}}
Dan Gohmanc9623db2016-08-18 17:51:27 +0000401; CHECK: i64.store $drop=, 8($0):p2align=2, $pop[[L0]]{{$}}
402; CHECK: i64.const $push[[L1:[0-9]+]]=, 0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000403; CHECK: i64.store $drop=, 0($0):p2align=2, $pop[[L1]]{{$}}
Dan Gohman797f639e2016-01-06 00:43:06 +0000404define {i32,i32,i32,i32} @aggregate_return() {
405 ret {i32,i32,i32,i32} zeroinitializer
406}
Dan Gohmanbb372242016-01-26 03:39:31 +0000407
408; Fold the offsets when lowering aggregate return values. The stores are not
409; merged.
410
411; CHECK-LABEL: aggregate_return_without_merge:
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000412; CHECK: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
Dan Gohmanc9623db2016-08-18 17:51:27 +0000413; CHECK: i32.store8 $drop=, 14($0), $pop[[L0]]{{$}}
414; CHECK: i32.const $push[[L1:[0-9]+]]=, 0{{$}}
415; CHECK: i32.store16 $drop=, 12($0), $pop[[L1]]{{$}}
416; CHECK: i32.const $push[[L2:[0-9]+]]=, 0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000417; CHECK: i32.store $drop=, 8($0), $pop[[L2]]{{$}}
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000418; CHECK: i64.const $push[[L3:[0-9]+]]=, 0{{$}}
Dan Gohman71008092016-05-17 23:19:03 +0000419; CHECK: i64.store $drop=, 0($0), $pop[[L3]]{{$}}
Dan Gohmanbb372242016-01-26 03:39:31 +0000420define {i64,i32,i16,i8} @aggregate_return_without_merge() {
421 ret {i64,i32,i16,i8} zeroinitializer
422}