1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s 2 3 ; Test loads and stores with custom alignment values. 4 5 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6 target triple = "wasm32-unknown-unknown" 7 8 ; CHECK-LABEL: ldi64_a1: 9 ; CHECK-NEXT: .param i32{{$}} 10 ; CHECK-NEXT: .result i64{{$}} 11 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 12 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 13 define i64 @ldi64_a1(i64 *%p) { 14 %v = load i64, i64* %p, align 1 15 ret i64 %v 16 } 17 18 ; CHECK-LABEL: ldi64_a2: 19 ; CHECK-NEXT: .param i32{{$}} 20 ; CHECK-NEXT: .result i64{{$}} 21 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} 22 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 23 define i64 @ldi64_a2(i64 *%p) { 24 %v = load i64, i64* %p, align 2 25 ret i64 %v 26 } 27 28 ; CHECK-LABEL: ldi64_a4: 29 ; CHECK-NEXT: .param i32{{$}} 30 ; CHECK-NEXT: .result i64{{$}} 31 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}} 32 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 33 define i64 @ldi64_a4(i64 *%p) { 34 %v = load i64, i64* %p, align 4 35 ret i64 %v 36 } 37 38 ; 8 is the default alignment for i64 so no attribute is needed. 39 40 ; CHECK-LABEL: ldi64_a8: 41 ; CHECK-NEXT: .param i32{{$}} 42 ; CHECK-NEXT: .result i64{{$}} 43 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 44 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 45 define i64 @ldi64_a8(i64 *%p) { 46 %v = load i64, i64* %p, align 8 47 ret i64 %v 48 } 49 50 ; The default alignment in LLVM is the same as the defualt alignment in wasm. 51 52 ; CHECK-LABEL: ldi64: 53 ; CHECK-NEXT: .param i32{{$}} 54 ; CHECK-NEXT: .result i64{{$}} 55 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 56 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 57 define i64 @ldi64(i64 *%p) { 58 %v = load i64, i64* %p 59 ret i64 %v 60 } 61 62 ; 16 is greater than the default alignment so it is ignored. 63 64 ; CHECK-LABEL: ldi64_a16: 65 ; CHECK-NEXT: .param i32{{$}} 66 ; CHECK-NEXT: .result i64{{$}} 67 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 68 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 69 define i64 @ldi64_a16(i64 *%p) { 70 %v = load i64, i64* %p, align 16 71 ret i64 %v 72 } 73 74 ; Extending loads. 75 76 ; CHECK-LABEL: ldi8_a1: 77 ; CHECK-NEXT: .param i32{{$}} 78 ; CHECK-NEXT: .result i64{{$}} 79 ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 80 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 81 define i64 @ldi8_a1(i8 *%p) { 82 %v = load i8, i8* %p, align 1 83 %w = zext i8 %v to i64 84 ret i64 %w 85 } 86 87 ; CHECK-LABEL: ldi8_a2: 88 ; CHECK-NEXT: .param i32{{$}} 89 ; CHECK-NEXT: .result i64{{$}} 90 ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 91 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 92 define i64 @ldi8_a2(i8 *%p) { 93 %v = load i8, i8* %p, align 2 94 %w = zext i8 %v to i64 95 ret i64 %w 96 } 97 98 ; CHECK-LABEL: ldi16_a1: 99 ; CHECK-NEXT: .param i32{{$}} 100 ; CHECK-NEXT: .result i64{{$}} 101 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 102 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 103 define i64 @ldi16_a1(i16 *%p) { 104 %v = load i16, i16* %p, align 1 105 %w = zext i16 %v to i64 106 ret i64 %w 107 } 108 109 ; CHECK-LABEL: ldi16_a2: 110 ; CHECK-NEXT: .param i32{{$}} 111 ; CHECK-NEXT: .result i64{{$}} 112 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 113 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 114 define i64 @ldi16_a2(i16 *%p) { 115 %v = load i16, i16* %p, align 2 116 %w = zext i16 %v to i64 117 ret i64 %w 118 } 119 120 ; CHECK-LABEL: ldi16_a4: 121 ; CHECK-NEXT: .param i32{{$}} 122 ; CHECK-NEXT: .result i64{{$}} 123 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 124 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 125 define i64 @ldi16_a4(i16 *%p) { 126 %v = load i16, i16* %p, align 4 127 %w = zext i16 %v to i64 128 ret i64 %w 129 } 130 131 ; CHECK-LABEL: ldi32_a1: 132 ; CHECK-NEXT: .param i32{{$}} 133 ; CHECK-NEXT: .result i64{{$}} 134 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 135 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 136 define i64 @ldi32_a1(i32 *%p) { 137 %v = load i32, i32* %p, align 1 138 %w = zext i32 %v to i64 139 ret i64 %w 140 } 141 142 ; CHECK-LABEL: ldi32_a2: 143 ; CHECK-NEXT: .param i32{{$}} 144 ; CHECK-NEXT: .result i64{{$}} 145 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} 146 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 147 define i64 @ldi32_a2(i32 *%p) { 148 %v = load i32, i32* %p, align 2 149 %w = zext i32 %v to i64 150 ret i64 %w 151 } 152 153 ; CHECK-LABEL: ldi32_a4: 154 ; CHECK-NEXT: .param i32{{$}} 155 ; CHECK-NEXT: .result i64{{$}} 156 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 157 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 158 define i64 @ldi32_a4(i32 *%p) { 159 %v = load i32, i32* %p, align 4 160 %w = zext i32 %v to i64 161 ret i64 %w 162 } 163 164 ; CHECK-LABEL: ldi32_a8: 165 ; CHECK-NEXT: .param i32{{$}} 166 ; CHECK-NEXT: .result i64{{$}} 167 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 168 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 169 define i64 @ldi32_a8(i32 *%p) { 170 %v = load i32, i32* %p, align 8 171 %w = zext i32 %v to i64 172 ret i64 %w 173 } 174 175 ; Stores. 176 177 ; CHECK-LABEL: sti64_a1: 178 ; CHECK-NEXT: .param i32, i64{{$}} 179 ; CHECK-NEXT: i64.store $drop=, 0($0):p2align=0, $1{{$}} 180 ; CHECK-NEXT: return{{$}} 181 define void @sti64_a1(i64 *%p, i64 %v) { 182 store i64 %v, i64* %p, align 1 183 ret void 184 } 185 186 ; CHECK-LABEL: sti64_a2: 187 ; CHECK-NEXT: .param i32, i64{{$}} 188 ; CHECK-NEXT: i64.store $drop=, 0($0):p2align=1, $1{{$}} 189 ; CHECK-NEXT: return{{$}} 190 define void @sti64_a2(i64 *%p, i64 %v) { 191 store i64 %v, i64* %p, align 2 192 ret void 193 } 194 195 ; CHECK-LABEL: sti64_a4: 196 ; CHECK-NEXT: .param i32, i64{{$}} 197 ; CHECK-NEXT: i64.store $drop=, 0($0):p2align=2, $1{{$}} 198 ; CHECK-NEXT: return{{$}} 199 define void @sti64_a4(i64 *%p, i64 %v) { 200 store i64 %v, i64* %p, align 4 201 ret void 202 } 203 204 ; 8 is the default alignment for i32 so no attribute is needed. 205 206 ; CHECK-LABEL: sti64_a8: 207 ; CHECK-NEXT: .param i32, i64{{$}} 208 ; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}} 209 ; CHECK-NEXT: return{{$}} 210 define void @sti64_a8(i64 *%p, i64 %v) { 211 store i64 %v, i64* %p, align 8 212 ret void 213 } 214 215 ; The default alignment in LLVM is the same as the defualt alignment in wasm. 216 217 ; CHECK-LABEL: sti64: 218 ; CHECK-NEXT: .param i32, i64{{$}} 219 ; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}} 220 ; CHECK-NEXT: return{{$}} 221 define void @sti64(i64 *%p, i64 %v) { 222 store i64 %v, i64* %p 223 ret void 224 } 225 226 ; CHECK-LABEL: sti64_a16: 227 ; CHECK-NEXT: .param i32, i64{{$}} 228 ; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}} 229 ; CHECK-NEXT: return{{$}} 230 define void @sti64_a16(i64 *%p, i64 %v) { 231 store i64 %v, i64* %p, align 16 232 ret void 233 } 234 235 ; Truncating stores. 236 237 ; CHECK-LABEL: sti8_a1: 238 ; CHECK-NEXT: .param i32, i64{{$}} 239 ; CHECK-NEXT: i64.store8 $drop=, 0($0), $1{{$}} 240 ; CHECK-NEXT: return{{$}} 241 define void @sti8_a1(i8 *%p, i64 %w) { 242 %v = trunc i64 %w to i8 243 store i8 %v, i8* %p, align 1 244 ret void 245 } 246 247 ; CHECK-LABEL: sti8_a2: 248 ; CHECK-NEXT: .param i32, i64{{$}} 249 ; CHECK-NEXT: i64.store8 $drop=, 0($0), $1{{$}} 250 ; CHECK-NEXT: return{{$}} 251 define void @sti8_a2(i8 *%p, i64 %w) { 252 %v = trunc i64 %w to i8 253 store i8 %v, i8* %p, align 2 254 ret void 255 } 256 257 ; CHECK-LABEL: sti16_a1: 258 ; CHECK-NEXT: .param i32, i64{{$}} 259 ; CHECK-NEXT: i64.store16 $drop=, 0($0):p2align=0, $1{{$}} 260 ; CHECK-NEXT: return{{$}} 261 define void @sti16_a1(i16 *%p, i64 %w) { 262 %v = trunc i64 %w to i16 263 store i16 %v, i16* %p, align 1 264 ret void 265 } 266 267 ; CHECK-LABEL: sti16_a2: 268 ; CHECK-NEXT: .param i32, i64{{$}} 269 ; CHECK-NEXT: i64.store16 $drop=, 0($0), $1{{$}} 270 ; CHECK-NEXT: return{{$}} 271 define void @sti16_a2(i16 *%p, i64 %w) { 272 %v = trunc i64 %w to i16 273 store i16 %v, i16* %p, align 2 274 ret void 275 } 276 277 ; CHECK-LABEL: sti16_a4: 278 ; CHECK-NEXT: .param i32, i64{{$}} 279 ; CHECK-NEXT: i64.store16 $drop=, 0($0), $1{{$}} 280 ; CHECK-NEXT: return{{$}} 281 define void @sti16_a4(i16 *%p, i64 %w) { 282 %v = trunc i64 %w to i16 283 store i16 %v, i16* %p, align 4 284 ret void 285 } 286 287 ; CHECK-LABEL: sti32_a1: 288 ; CHECK-NEXT: .param i32, i64{{$}} 289 ; CHECK-NEXT: i64.store32 $drop=, 0($0):p2align=0, $1{{$}} 290 ; CHECK-NEXT: return{{$}} 291 define void @sti32_a1(i32 *%p, i64 %w) { 292 %v = trunc i64 %w to i32 293 store i32 %v, i32* %p, align 1 294 ret void 295 } 296 297 ; CHECK-LABEL: sti32_a2: 298 ; CHECK-NEXT: .param i32, i64{{$}} 299 ; CHECK-NEXT: i64.store32 $drop=, 0($0):p2align=1, $1{{$}} 300 ; CHECK-NEXT: return{{$}} 301 define void @sti32_a2(i32 *%p, i64 %w) { 302 %v = trunc i64 %w to i32 303 store i32 %v, i32* %p, align 2 304 ret void 305 } 306 307 ; CHECK-LABEL: sti32_a4: 308 ; CHECK-NEXT: .param i32, i64{{$}} 309 ; CHECK-NEXT: i64.store32 $drop=, 0($0), $1{{$}} 310 ; CHECK-NEXT: return{{$}} 311 define void @sti32_a4(i32 *%p, i64 %w) { 312 %v = trunc i64 %w to i32 313 store i32 %v, i32* %p, align 4 314 ret void 315 } 316 317 ; CHECK-LABEL: sti32_a8: 318 ; CHECK-NEXT: .param i32, i64{{$}} 319 ; CHECK-NEXT: i64.store32 $drop=, 0($0), $1{{$}} 320 ; CHECK-NEXT: return{{$}} 321 define void @sti32_a8(i32 *%p, i64 %w) { 322 %v = trunc i64 %w to i32 323 store i32 %v, i32* %p, align 8 324 ret void 325 } 326