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