1; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s 2 3; Test loads and stores with custom alignment values. 4 5target triple = "wasm32-unknown-unknown" 6 7;===---------------------------------------------------------------------------- 8; Loads 9;===---------------------------------------------------------------------------- 10 11; CHECK-LABEL: ldi32_a1: 12; CHECK-NEXT: .functype ldi32_a1 (i32) -> (i32){{$}} 13; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 14; CHECK-NEXT: return $pop[[NUM]]{{$}} 15define i32 @ldi32_a1(ptr %p) { 16 %v = load i32, ptr %p, align 1 17 ret i32 %v 18} 19 20; CHECK-LABEL: ldi32_a2: 21; CHECK-NEXT: .functype ldi32_a2 (i32) -> (i32){{$}} 22; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} 23; CHECK-NEXT: return $pop[[NUM]]{{$}} 24define i32 @ldi32_a2(ptr %p) { 25 %v = load i32, ptr %p, align 2 26 ret i32 %v 27} 28 29; 4 is the default alignment for i32 so no attribute is needed. 30 31; CHECK-LABEL: ldi32_a4: 32; CHECK-NEXT: .functype ldi32_a4 (i32) -> (i32){{$}} 33; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 34; CHECK-NEXT: return $pop[[NUM]]{{$}} 35define i32 @ldi32_a4(ptr %p) { 36 %v = load i32, ptr %p, align 4 37 ret i32 %v 38} 39 40; The default alignment in LLVM is the same as the default alignment in wasm. 41 42; CHECK-LABEL: ldi32: 43; CHECK-NEXT: .functype ldi32 (i32) -> (i32){{$}} 44; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 45; CHECK-NEXT: return $pop[[NUM]]{{$}} 46define i32 @ldi32(ptr %p) { 47 %v = load i32, ptr %p 48 ret i32 %v 49} 50 51; 8 is greater than the default alignment so it is ignored. 52 53; CHECK-LABEL: ldi32_a8: 54; CHECK-NEXT: .functype ldi32_a8 (i32) -> (i32){{$}} 55; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 56; CHECK-NEXT: return $pop[[NUM]]{{$}} 57define i32 @ldi32_a8(ptr %p) { 58 %v = load i32, ptr %p, align 8 59 ret i32 %v 60} 61 62;===---------------------------------------------------------------------------- 63; Extending loads 64;===---------------------------------------------------------------------------- 65 66; CHECK-LABEL: ldi8_a1: 67; CHECK-NEXT: .functype ldi8_a1 (i32) -> (i32){{$}} 68; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 69; CHECK-NEXT: return $pop[[NUM]]{{$}} 70define i8 @ldi8_a1(ptr %p) { 71 %v = load i8, ptr %p, align 1 72 ret i8 %v 73} 74 75; CHECK-LABEL: ldi8_a2: 76; CHECK-NEXT: .functype ldi8_a2 (i32) -> (i32){{$}} 77; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 78; CHECK-NEXT: return $pop[[NUM]]{{$}} 79define i8 @ldi8_a2(ptr %p) { 80 %v = load i8, ptr %p, align 2 81 ret i8 %v 82} 83 84; CHECK-LABEL: ldi16_a1: 85; CHECK-NEXT: .functype ldi16_a1 (i32) -> (i32){{$}} 86; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 87; CHECK-NEXT: return $pop[[NUM]]{{$}} 88define i16 @ldi16_a1(ptr %p) { 89 %v = load i16, ptr %p, align 1 90 ret i16 %v 91} 92 93; CHECK-LABEL: ldi16_a2: 94; CHECK-NEXT: .functype ldi16_a2 (i32) -> (i32){{$}} 95; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 96; CHECK-NEXT: return $pop[[NUM]]{{$}} 97define i16 @ldi16_a2(ptr %p) { 98 %v = load i16, ptr %p, align 2 99 ret i16 %v 100} 101 102; CHECK-LABEL: ldi16_a4: 103; CHECK-NEXT: .functype ldi16_a4 (i32) -> (i32){{$}} 104; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 105; CHECK-NEXT: return $pop[[NUM]]{{$}} 106define i16 @ldi16_a4(ptr %p) { 107 %v = load i16, ptr %p, align 4 108 ret i16 %v 109} 110 111;===---------------------------------------------------------------------------- 112; Stores 113;===---------------------------------------------------------------------------- 114 115; CHECK-LABEL: sti32_a1: 116; CHECK-NEXT: .functype sti32_a1 (i32, i32) -> (){{$}} 117; CHECK-NEXT: i32.store 0($0):p2align=0, $1{{$}} 118; CHECK-NEXT: return{{$}} 119define void @sti32_a1(ptr %p, i32 %v) { 120 store i32 %v, ptr %p, align 1 121 ret void 122} 123 124; CHECK-LABEL: sti32_a2: 125; CHECK-NEXT: .functype sti32_a2 (i32, i32) -> (){{$}} 126; CHECK-NEXT: i32.store 0($0):p2align=1, $1{{$}} 127; CHECK-NEXT: return{{$}} 128define void @sti32_a2(ptr %p, i32 %v) { 129 store i32 %v, ptr %p, align 2 130 ret void 131} 132 133; 4 is the default alignment for i32 so no attribute is needed. 134 135; CHECK-LABEL: sti32_a4: 136; CHECK-NEXT: .functype sti32_a4 (i32, i32) -> (){{$}} 137; CHECK-NEXT: i32.store 0($0), $1{{$}} 138; CHECK-NEXT: return{{$}} 139define void @sti32_a4(ptr %p, i32 %v) { 140 store i32 %v, ptr %p, align 4 141 ret void 142} 143 144; The default alignment in LLVM is the same as the default alignment in wasm. 145 146; CHECK-LABEL: sti32: 147; CHECK-NEXT: .functype sti32 (i32, i32) -> (){{$}} 148; CHECK-NEXT: i32.store 0($0), $1{{$}} 149; CHECK-NEXT: return{{$}} 150define void @sti32(ptr %p, i32 %v) { 151 store i32 %v, ptr %p 152 ret void 153} 154 155; CHECK-LABEL: sti32_a8: 156; CHECK-NEXT: .functype sti32_a8 (i32, i32) -> (){{$}} 157; CHECK-NEXT: i32.store 0($0), $1{{$}} 158; CHECK-NEXT: return{{$}} 159define void @sti32_a8(ptr %p, i32 %v) { 160 store i32 %v, ptr %p, align 8 161 ret void 162} 163 164;===---------------------------------------------------------------------------- 165; Truncating stores 166;===---------------------------------------------------------------------------- 167 168; CHECK-LABEL: sti8_a1: 169; CHECK-NEXT: .functype sti8_a1 (i32, i32) -> (){{$}} 170; CHECK-NEXT: i32.store8 0($0), $1{{$}} 171; CHECK-NEXT: return{{$}} 172define void @sti8_a1(ptr %p, i8 %v) { 173 store i8 %v, ptr %p, align 1 174 ret void 175} 176 177; CHECK-LABEL: sti8_a2: 178; CHECK-NEXT: .functype sti8_a2 (i32, i32) -> (){{$}} 179; CHECK-NEXT: i32.store8 0($0), $1{{$}} 180; CHECK-NEXT: return{{$}} 181define void @sti8_a2(ptr %p, i8 %v) { 182 store i8 %v, ptr %p, align 2 183 ret void 184} 185 186; CHECK-LABEL: sti16_a1: 187; CHECK-NEXT: .functype sti16_a1 (i32, i32) -> (){{$}} 188; CHECK-NEXT: i32.store16 0($0):p2align=0, $1{{$}} 189; CHECK-NEXT: return{{$}} 190define void @sti16_a1(ptr %p, i16 %v) { 191 store i16 %v, ptr %p, align 1 192 ret void 193} 194 195; CHECK-LABEL: sti16_a2: 196; CHECK-NEXT: .functype sti16_a2 (i32, i32) -> (){{$}} 197; CHECK-NEXT: i32.store16 0($0), $1{{$}} 198; CHECK-NEXT: return{{$}} 199define void @sti16_a2(ptr %p, i16 %v) { 200 store i16 %v, ptr %p, align 2 201 ret void 202} 203 204; CHECK-LABEL: sti16_a4: 205; CHECK-NEXT: .functype sti16_a4 (i32, i32) -> (){{$}} 206; CHECK-NEXT: i32.store16 0($0), $1{{$}} 207; CHECK-NEXT: return{{$}} 208define void @sti16_a4(ptr %p, i16 %v) { 209 store i16 %v, ptr %p, align 4 210 ret void 211} 212 213;===---------------------------------------------------------------------------- 214; Atomic loads 215;===---------------------------------------------------------------------------- 216 217; Wasm atomics have the alignment field, but it must always have the type's 218; natural alignment. 219 220; CHECK-LABEL: ldi32_atomic_a4: 221; CHECK-NEXT: .functype ldi32_atomic_a4 (i32) -> (i32){{$}} 222; CHECK-NEXT: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 223; CHECK-NEXT: return $pop[[NUM]]{{$}} 224define i32 @ldi32_atomic_a4(ptr %p) { 225 %v = load atomic i32, ptr %p seq_cst, align 4 226 ret i32 %v 227} 228 229; 8 is greater than the default alignment so it is ignored. 230 231; CHECK-LABEL: ldi32_atomic_a8: 232; CHECK-NEXT: .functype ldi32_atomic_a8 (i32) -> (i32){{$}} 233; CHECK-NEXT: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 234; CHECK-NEXT: return $pop[[NUM]]{{$}} 235define i32 @ldi32_atomic_a8(ptr %p) { 236 %v = load atomic i32, ptr %p seq_cst, align 8 237 ret i32 %v 238} 239 240;===---------------------------------------------------------------------------- 241; Atomic stores 242;===---------------------------------------------------------------------------- 243 244; CHECK-LABEL: sti32_atomic_a4: 245; CHECK-NEXT: .functype sti32_atomic_a4 (i32, i32) -> (){{$}} 246; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 247; CHECK-NEXT: return{{$}} 248define void @sti32_atomic_a4(ptr %p, i32 %v) { 249 store atomic i32 %v, ptr %p seq_cst, align 4 250 ret void 251} 252 253; 8 is greater than the default alignment so it is ignored. 254 255; CHECK-LABEL: sti32_atomic_a8: 256; CHECK-NEXT: .functype sti32_atomic_a8 (i32, i32) -> (){{$}} 257; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 258; CHECK-NEXT: return{{$}} 259define void @sti32_atomic_a8(ptr %p, i32 %v) { 260 store atomic i32 %v, ptr %p seq_cst, align 8 261 ret void 262} 263