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