1; RUN: llc < %s -asm-verbose=false | FileCheck %s
2
3; Test constant load and store address offsets.
4
5target datalayout = "e-p:32:32-i64:64-n32:64-S128"
6target 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
20; Without nuw, and even with nsw, we can't fold an offset.
21
22; CHECK-LABEL: load_i32_with_unfolded_offset:
23; CHECK: i32.const $push0=, 24{{$}}
24; CHECK: i32.add   $push1=, $0, $pop0{{$}}
25; CHECK: i32.load  $push2=, 0($pop1){{$}}
26define i32 @load_i32_with_unfolded_offset(i32* %p) {
27  %q = ptrtoint i32* %p to i32
28  %r = add nsw i32 %q, 24
29  %s = inttoptr i32 %r to i32*
30  %t = load i32, i32* %s
31  ret i32 %t
32}
33
34; Same as above but with i64.
35
36; CHECK-LABEL: load_i64_with_folded_offset:
37; CHECK: i64.load  $push0=, 24($0){{$}}
38define i64 @load_i64_with_folded_offset(i64* %p) {
39  %q = ptrtoint i64* %p to i32
40  %r = add nuw i32 %q, 24
41  %s = inttoptr i32 %r to i64*
42  %t = load i64, i64* %s
43  ret i64 %t
44}
45
46; Same as above but with i64.
47
48; CHECK-LABEL: load_i64_with_unfolded_offset:
49; CHECK: i32.const $push0=, 24{{$}}
50; CHECK: i32.add   $push1=, $0, $pop0{{$}}
51; CHECK: i64.load  $push2=, 0($pop1){{$}}
52define i64 @load_i64_with_unfolded_offset(i64* %p) {
53  %q = ptrtoint i64* %p to i32
54  %r = add nsw i32 %q, 24
55  %s = inttoptr i32 %r to i64*
56  %t = load i64, i64* %s
57  ret i64 %t
58}
59
60; Same as above but with store.
61
62; CHECK-LABEL: store_i32_with_folded_offset:
63; CHECK: i32.store $discard=, 24($0), $pop0{{$}}
64define void @store_i32_with_folded_offset(i32* %p) {
65  %q = ptrtoint i32* %p to i32
66  %r = add nuw i32 %q, 24
67  %s = inttoptr i32 %r to i32*
68  store i32 0, i32* %s
69  ret void
70}
71
72; Same as above but with store.
73
74; CHECK-LABEL: store_i32_with_unfolded_offset:
75; CHECK: i32.const $push0=, 24{{$}}
76; CHECK: i32.add   $push1=, $0, $pop0{{$}}
77; CHECK: i32.store $discard=, 0($pop1), $pop2{{$}}
78define void @store_i32_with_unfolded_offset(i32* %p) {
79  %q = ptrtoint i32* %p to i32
80  %r = add nsw i32 %q, 24
81  %s = inttoptr i32 %r to i32*
82  store i32 0, i32* %s
83  ret void
84}
85
86; Same as above but with store with i64.
87
88; CHECK-LABEL: store_i64_with_folded_offset:
89; CHECK: i64.store $discard=, 24($0), $pop0{{$}}
90define void @store_i64_with_folded_offset(i64* %p) {
91  %q = ptrtoint i64* %p to i32
92  %r = add nuw i32 %q, 24
93  %s = inttoptr i32 %r to i64*
94  store i64 0, i64* %s
95  ret void
96}
97
98; Same as above but with store with i64.
99
100; CHECK-LABEL: store_i64_with_unfolded_offset:
101; CHECK: i32.const $push0=, 24{{$}}
102; CHECK: i32.add   $push1=, $0, $pop0{{$}}
103; CHECK: i64.store $discard=, 0($pop1), $pop2{{$}}
104define void @store_i64_with_unfolded_offset(i64* %p) {
105  %q = ptrtoint i64* %p to i32
106  %r = add nsw i32 %q, 24
107  %s = inttoptr i32 %r to i64*
108  store i64 0, i64* %s
109  ret void
110}
111
112; When loading from a fixed address, materialize a zero.
113
114; CHECK-LABEL: load_i32_from_numeric_address
115; CHECK: i32.const $push0=, 0{{$}}
116; CHECK: i32.load  $push1=, 42($pop0){{$}}
117define i32 @load_i32_from_numeric_address() {
118  %s = inttoptr i32 42 to i32*
119  %t = load i32, i32* %s
120  ret i32 %t
121}
122
123; CHECK-LABEL: load_i32_from_global_address
124; CHECK: i32.const $push0=, 0{{$}}
125; CHECK: i32.load  $push1=, gv($pop0){{$}}
126@gv = global i32 0
127define i32 @load_i32_from_global_address() {
128  %t = load i32, i32* @gv
129  ret i32 %t
130}
131
132; CHECK-LABEL: store_i32_to_numeric_address:
133; CHECK: i32.const $0=, 0{{$}}
134; CHECK: i32.store $discard=, 42($0), $0{{$}}
135define void @store_i32_to_numeric_address() {
136  %s = inttoptr i32 42 to i32*
137  store i32 0, i32* %s
138  ret void
139}
140
141; CHECK-LABEL: store_i32_to_global_address:
142; CHECK: i32.const $0=, 0{{$}}
143; CHECK: i32.store $discard=, gv($0), $0{{$}}
144define void @store_i32_to_global_address() {
145  store i32 0, i32* @gv
146  ret void
147}
148
149; Fold an offset into a sign-extending load.
150
151; CHECK-LABEL: load_i8_s_with_folded_offset:
152; CHECK: i32.load8_s $push0=, 24($0){{$}}
153define i32 @load_i8_s_with_folded_offset(i8* %p) {
154  %q = ptrtoint i8* %p to i32
155  %r = add nuw i32 %q, 24
156  %s = inttoptr i32 %r to i8*
157  %t = load i8, i8* %s
158  %u = sext i8 %t to i32
159  ret i32 %u
160}
161
162; Fold an offset into a zero-extending load.
163
164; CHECK-LABEL: load_i8_u_with_folded_offset:
165; CHECK: i32.load8_u $push0=, 24($0){{$}}
166define i32 @load_i8_u_with_folded_offset(i8* %p) {
167  %q = ptrtoint i8* %p to i32
168  %r = add nuw i32 %q, 24
169  %s = inttoptr i32 %r to i8*
170  %t = load i8, i8* %s
171  %u = zext i8 %t to i32
172  ret i32 %u
173}
174
175; Fold an offset into a truncating store.
176
177; CHECK-LABEL: store_i8_with_folded_offset:
178; CHECK: i32.store8 $discard=, 24($0), $pop0{{$}}
179define void @store_i8_with_folded_offset(i8* %p) {
180  %q = ptrtoint i8* %p to i32
181  %r = add nuw i32 %q, 24
182  %s = inttoptr i32 %r to i8*
183  store i8 0, i8* %s
184  ret void
185}
186