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