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: ldi32_a1: 9 ; CHECK-NEXT: .param i32{{$}} 10 ; CHECK-NEXT: .result i32{{$}} 11 ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 12 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 13 define i32 @ldi32_a1(i32 *%p) { 14 %v = load i32, i32* %p, align 1 15 ret i32 %v 16 } 17 18 ; CHECK-LABEL: ldi32_a2: 19 ; CHECK-NEXT: .param i32{{$}} 20 ; CHECK-NEXT: .result i32{{$}} 21 ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} 22 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 23 define i32 @ldi32_a2(i32 *%p) { 24 %v = load i32, i32* %p, align 2 25 ret i32 %v 26 } 27 28 ; 4 is the default alignment for i32 so no attribute is needed. 29 30 ; CHECK-LABEL: ldi32_a4: 31 ; CHECK-NEXT: .param i32{{$}} 32 ; CHECK-NEXT: .result i32{{$}} 33 ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 34 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 35 define i32 @ldi32_a4(i32 *%p) { 36 %v = load i32, i32* %p, align 4 37 ret i32 %v 38 } 39 40 ; The default alignment in LLVM is the same as the defualt alignment in wasm. 41 42 ; CHECK-LABEL: ldi32: 43 ; CHECK-NEXT: .param i32{{$}} 44 ; CHECK-NEXT: .result i32{{$}} 45 ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 46 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 47 define 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: .param i32{{$}} 56 ; CHECK-NEXT: .result i32{{$}} 57 ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 58 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 59 define i32 @ldi32_a8(i32 *%p) { 60 %v = load i32, i32* %p, align 8 61 ret i32 %v 62 } 63 64 ; Extending loads. 65 66 ; CHECK-LABEL: ldi8_a1: 67 ; CHECK-NEXT: .param i32{{$}} 68 ; CHECK-NEXT: .result i32{{$}} 69 ; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 70 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 71 define 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: .param i32{{$}} 78 ; CHECK-NEXT: .result i32{{$}} 79 ; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 80 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 81 define i8 @ldi8_a2(i8 *%p) { 82 %v = load i8, i8* %p, align 2 83 ret i8 %v 84 } 85 86 ; CHECK-LABEL: ldi16_a1: 87 ; CHECK-NEXT: .param i32{{$}} 88 ; CHECK-NEXT: .result i32{{$}} 89 ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} 90 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 91 define i16 @ldi16_a1(i16 *%p) { 92 %v = load i16, i16* %p, align 1 93 ret i16 %v 94 } 95 96 ; CHECK-LABEL: ldi16_a2: 97 ; CHECK-NEXT: .param i32{{$}} 98 ; CHECK-NEXT: .result i32{{$}} 99 ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 100 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 101 define i16 @ldi16_a2(i16 *%p) { 102 %v = load i16, i16* %p, align 2 103 ret i16 %v 104 } 105 106 ; CHECK-LABEL: ldi16_a4: 107 ; CHECK-NEXT: .param i32{{$}} 108 ; CHECK-NEXT: .result i32{{$}} 109 ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 110 ; CHECK-NEXT: return $pop[[NUM]]{{$}} 111 define i16 @ldi16_a4(i16 *%p) { 112 %v = load i16, i16* %p, align 4 113 ret i16 %v 114 } 115 116 ; Stores. 117 118 ; CHECK-LABEL: sti32_a1: 119 ; CHECK-NEXT: .param i32, i32{{$}} 120 ; CHECK-NEXT: i32.store $drop=, 0($0):p2align=0, $1{{$}} 121 ; CHECK-NEXT: return{{$}} 122 define void @sti32_a1(i32 *%p, i32 %v) { 123 store i32 %v, i32* %p, align 1 124 ret void 125 } 126 127 ; CHECK-LABEL: sti32_a2: 128 ; CHECK-NEXT: .param i32, i32{{$}} 129 ; CHECK-NEXT: i32.store $drop=, 0($0):p2align=1, $1{{$}} 130 ; CHECK-NEXT: return{{$}} 131 define void @sti32_a2(i32 *%p, i32 %v) { 132 store i32 %v, i32* %p, align 2 133 ret void 134 } 135 136 ; 4 is the default alignment for i32 so no attribute is needed. 137 138 ; CHECK-LABEL: sti32_a4: 139 ; CHECK-NEXT: .param i32, i32{{$}} 140 ; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}} 141 ; CHECK-NEXT: return{{$}} 142 define void @sti32_a4(i32 *%p, i32 %v) { 143 store i32 %v, i32* %p, align 4 144 ret void 145 } 146 147 ; The default alignment in LLVM is the same as the defualt alignment in wasm. 148 149 ; CHECK-LABEL: sti32: 150 ; CHECK-NEXT: .param i32, i32{{$}} 151 ; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}} 152 ; CHECK-NEXT: return{{$}} 153 define void @sti32(i32 *%p, i32 %v) { 154 store i32 %v, i32* %p 155 ret void 156 } 157 158 ; CHECK-LABEL: sti32_a8: 159 ; CHECK-NEXT: .param i32, i32{{$}} 160 ; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}} 161 ; CHECK-NEXT: return{{$}} 162 define void @sti32_a8(i32 *%p, i32 %v) { 163 store i32 %v, i32* %p, align 8 164 ret void 165 } 166 167 ; Truncating stores. 168 169 ; CHECK-LABEL: sti8_a1: 170 ; CHECK-NEXT: .param i32, i32{{$}} 171 ; CHECK-NEXT: i32.store8 $drop=, 0($0), $1{{$}} 172 ; CHECK-NEXT: return{{$}} 173 define 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: .param i32, i32{{$}} 180 ; CHECK-NEXT: i32.store8 $drop=, 0($0), $1{{$}} 181 ; CHECK-NEXT: return{{$}} 182 define 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: .param i32, i32{{$}} 189 ; CHECK-NEXT: i32.store16 $drop=, 0($0):p2align=0, $1{{$}} 190 ; CHECK-NEXT: return{{$}} 191 define 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: .param i32, i32{{$}} 198 ; CHECK-NEXT: i32.store16 $drop=, 0($0), $1{{$}} 199 ; CHECK-NEXT: return{{$}} 200 define 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: .param i32, i32{{$}} 207 ; CHECK-NEXT: i32.store16 $drop=, 0($0), $1{{$}} 208 ; CHECK-NEXT: return{{$}} 209 define void @sti16_a4(i16 *%p, i16 %v) { 210 store i16 %v, i16* %p, align 4 211 ret void 212 } 213