[WebAssembly] Implement instruction selection for constant offsets in addresses.
[oota-llvm.git] / test / CodeGen / WebAssembly / offset.ll
1 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
2
3 ; Test constant load and store address offsets.
4
5 target datalayout = "e-p:32:32-i64:64-n32:64-S128"
6 target 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){{$}}
12 define 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){{$}}
26 define 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){{$}}
38 define 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){{$}}
52 define 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{{$}}
64 define 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{{$}}
78 define 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{{$}}
90 define 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{{$}}
104 define 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){{$}}
117 define 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
127 define 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{{$}}
135 define 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{{$}}
144 define 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){{$}}
153 define 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){{$}}
166 define 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{{$}}
179 define 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 }