1; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt 2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s 3 4; Test that atomic loads are assembled properly. 5 6target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 7target triple = "wasm32-unknown-unknown" 8 9; CHECK-LABEL: load_i32_no_offset: 10; CHECK: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 11; CHECK-NEXT: return $pop[[NUM]]{{$}} 12define i32 @load_i32_no_offset(i32 *%p) { 13 %v = load atomic i32, i32* %p seq_cst, align 4 14 ret i32 %v 15} 16 17; With an nuw add, we can fold an offset. 18 19; CHECK-LABEL: load_i32_with_folded_offset: 20; CHECK: i32.atomic.load $push0=, 24($0){{$}} 21define i32 @load_i32_with_folded_offset(i32* %p) { 22 %q = ptrtoint i32* %p to i32 23 %r = add nuw i32 %q, 24 24 %s = inttoptr i32 %r to i32* 25 %t = load atomic i32, i32* %s seq_cst, align 4 26 ret i32 %t 27} 28 29; With an inbounds gep, we can fold an offset. 30 31; CHECK-LABEL: load_i32_with_folded_gep_offset: 32; CHECK: i32.atomic.load $push0=, 24($0){{$}} 33define i32 @load_i32_with_folded_gep_offset(i32* %p) { 34 %s = getelementptr inbounds i32, i32* %p, i32 6 35 %t = load atomic i32, i32* %s seq_cst, align 4 36 ret i32 %t 37} 38 39; We can't fold a negative offset though, even with an inbounds gep. 40 41; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset: 42; CHECK: i32.const $push0=, -24{{$}} 43; CHECK: i32.add $push1=, $0, $pop0{{$}} 44; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} 45define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) { 46 %s = getelementptr inbounds i32, i32* %p, i32 -6 47 %t = load atomic i32, i32* %s seq_cst, align 4 48 ret i32 %t 49} 50 51; Without nuw, and even with nsw, we can't fold an offset. 52 53; CHECK-LABEL: load_i32_with_unfolded_offset: 54; CHECK: i32.const $push0=, 24{{$}} 55; CHECK: i32.add $push1=, $0, $pop0{{$}} 56; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} 57define i32 @load_i32_with_unfolded_offset(i32* %p) { 58 %q = ptrtoint i32* %p to i32 59 %r = add nsw i32 %q, 24 60 %s = inttoptr i32 %r to i32* 61 %t = load atomic i32, i32* %s seq_cst, align 4 62 ret i32 %t 63} 64 65; Without inbounds, we can't fold a gep offset. 66 67; CHECK-LABEL: load_i32_with_unfolded_gep_offset: 68; CHECK: i32.const $push0=, 24{{$}} 69; CHECK: i32.add $push1=, $0, $pop0{{$}} 70; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} 71define i32 @load_i32_with_unfolded_gep_offset(i32* %p) { 72 %s = getelementptr i32, i32* %p, i32 6 73 %t = load atomic i32, i32* %s seq_cst, align 4 74 ret i32 %t 75} 76 77; CHECK-LABEL: load_i64_no_offset: 78; CHECK: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} 79; CHECK-NEXT: return $pop[[NUM]]{{$}} 80define i64 @load_i64_no_offset(i64 *%p) { 81 %v = load atomic i64, i64* %p seq_cst, align 8 82 ret i64 %v 83} 84 85; Same as above but with i64. 86 87; CHECK-LABEL: load_i64_with_folded_offset: 88; CHECK: i64.atomic.load $push0=, 24($0){{$}} 89define i64 @load_i64_with_folded_offset(i64* %p) { 90 %q = ptrtoint i64* %p to i32 91 %r = add nuw i32 %q, 24 92 %s = inttoptr i32 %r to i64* 93 %t = load atomic i64, i64* %s seq_cst, align 8 94 ret i64 %t 95} 96 97; Same as above but with i64. 98 99; CHECK-LABEL: load_i64_with_folded_gep_offset: 100; CHECK: i64.atomic.load $push0=, 24($0){{$}} 101define i64 @load_i64_with_folded_gep_offset(i64* %p) { 102 %s = getelementptr inbounds i64, i64* %p, i32 3 103 %t = load atomic i64, i64* %s seq_cst, align 8 104 ret i64 %t 105} 106 107; Same as above but with i64. 108 109; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset: 110; CHECK: i32.const $push0=, -24{{$}} 111; CHECK: i32.add $push1=, $0, $pop0{{$}} 112; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} 113define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) { 114 %s = getelementptr inbounds i64, i64* %p, i32 -3 115 %t = load atomic i64, i64* %s seq_cst, align 8 116 ret i64 %t 117} 118 119; Same as above but with i64. 120 121; CHECK-LABEL: load_i64_with_unfolded_offset: 122; CHECK: i32.const $push0=, 24{{$}} 123; CHECK: i32.add $push1=, $0, $pop0{{$}} 124; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} 125define i64 @load_i64_with_unfolded_offset(i64* %p) { 126 %q = ptrtoint i64* %p to i32 127 %r = add nsw i32 %q, 24 128 %s = inttoptr i32 %r to i64* 129 %t = load atomic i64, i64* %s seq_cst, align 8 130 ret i64 %t 131} 132 133; Same as above but with i64. 134 135; CHECK-LABEL: load_i64_with_unfolded_gep_offset: 136; CHECK: i32.const $push0=, 24{{$}} 137; CHECK: i32.add $push1=, $0, $pop0{{$}} 138; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} 139define i64 @load_i64_with_unfolded_gep_offset(i64* %p) { 140 %s = getelementptr i64, i64* %p, i32 3 141 %t = load atomic i64, i64* %s seq_cst, align 8 142 ret i64 %t 143} 144 145; CHECK-LABEL: load_i32_with_folded_or_offset: 146; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}} 147; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}} 148define i32 @load_i32_with_folded_or_offset(i32 %x) { 149 %and = and i32 %x, -4 150 %t0 = inttoptr i32 %and to i8* 151 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2 152 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8 153 %conv = sext i8 %t1 to i32 154 ret i32 %conv 155} 156 157; When loading from a fixed address, materialize a zero. 158 159; CHECK-LABEL: load_i32_from_numeric_address 160; CHECK: i32.const $push0=, 0{{$}} 161; CHECK: i32.atomic.load $push1=, 42($pop0){{$}} 162define i32 @load_i32_from_numeric_address() { 163 %s = inttoptr i32 42 to i32* 164 %t = load atomic i32, i32* %s seq_cst, align 4 165 ret i32 %t 166} 167 168 169; CHECK-LABEL: load_i32_from_global_address 170; CHECK: i32.const $push0=, 0{{$}} 171; CHECK: i32.atomic.load $push1=, gv($pop0){{$}} 172@gv = global i32 0 173define i32 @load_i32_from_global_address() { 174 %t = load atomic i32, i32* @gv seq_cst, align 4 175 ret i32 %t 176} 177 178; Fold an offset into a sign-extending load. 179 180; CHECK-LABEL: load_i8_s_with_folded_offset: 181; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} 182; CHECK-NEXT: i32.extend8_s $push1=, $pop0 183define i32 @load_i8_s_with_folded_offset(i8* %p) { 184 %q = ptrtoint i8* %p to i32 185 %r = add nuw i32 %q, 24 186 %s = inttoptr i32 %r to i8* 187 %t = load atomic i8, i8* %s seq_cst, align 1 188 %u = sext i8 %t to i32 189 ret i32 %u 190} 191 192; Fold a gep offset into a sign-extending load. 193 194; CHECK-LABEL: load_i8_s_with_folded_gep_offset: 195; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} 196; CHECK-NEXT: i32.extend8_s $push1=, $pop0 197define i32 @load_i8_s_with_folded_gep_offset(i8* %p) { 198 %s = getelementptr inbounds i8, i8* %p, i32 24 199 %t = load atomic i8, i8* %s seq_cst, align 1 200 %u = sext i8 %t to i32 201 ret i32 %u 202} 203 204; CHECK-LABEL: load_i16_s_i64_with_folded_gep_offset: 205; CHECK: i64.atomic.load16_u $push0=, 6($0){{$}} 206define i64 @load_i16_s_i64_with_folded_gep_offset(i16* %p) { 207 %s = getelementptr inbounds i16, i16* %p, i32 3 208 %t = load atomic i16, i16* %s seq_cst, align 2 209 %u = zext i16 %t to i64 210 ret i64 %u 211} 212 213; CHECK-LABEL: load_i64_with_folded_or_offset: 214; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}} 215; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}} 216define i64 @load_i64_with_folded_or_offset(i32 %x) { 217 %and = and i32 %x, -4 218 %t0 = inttoptr i32 %and to i8* 219 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2 220 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8 221 %conv = sext i8 %t1 to i64 222 ret i64 %conv 223} 224 225 226; Fold an offset into a zero-extending load. 227 228; CHECK-LABEL: load_i16_u_with_folded_offset: 229; CHECK: i32.atomic.load16_u $push0=, 24($0){{$}} 230define i32 @load_i16_u_with_folded_offset(i8* %p) { 231 %q = ptrtoint i8* %p to i32 232 %r = add nuw i32 %q, 24 233 %s = inttoptr i32 %r to i16* 234 %t = load atomic i16, i16* %s seq_cst, align 2 235 %u = zext i16 %t to i32 236 ret i32 %u 237} 238 239; Fold a gep offset into a zero-extending load. 240 241; CHECK-LABEL: load_i8_u_with_folded_gep_offset: 242; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} 243define i32 @load_i8_u_with_folded_gep_offset(i8* %p) { 244 %s = getelementptr inbounds i8, i8* %p, i32 24 245 %t = load atomic i8, i8* %s seq_cst, align 1 246 %u = zext i8 %t to i32 247 ret i32 %u 248} 249 250 251; When loading from a fixed address, materialize a zero. 252; As above but with extending load. 253 254; CHECK-LABEL: load_zext_i32_from_numeric_address 255; CHECK: i32.const $push0=, 0{{$}} 256; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}} 257define i32 @load_zext_i32_from_numeric_address() { 258 %s = inttoptr i32 42 to i16* 259 %t = load atomic i16, i16* %s seq_cst, align 2 260 %u = zext i16 %t to i32 261 ret i32 %u 262} 263 264; CHECK-LABEL: load_sext_i32_from_global_address 265; CHECK: i32.const $push0=, 0{{$}} 266; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}} 267; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}} 268@gv8 = global i8 0 269define i32 @load_sext_i32_from_global_address() { 270 %t = load atomic i8, i8* @gv8 seq_cst, align 1 271 %u = sext i8 %t to i32 272 ret i32 %u 273} 274 275; Fold an offset into a sign-extending load. 276; As above but 32 extended to 64 bit. 277; CHECK-LABEL: load_i32_i64_s_with_folded_offset: 278; CHECK: i32.atomic.load $push0=, 24($0){{$}} 279; CHECK-NEXT: i64.extend_s/i32 $push1=, $pop0{{$}} 280define i64 @load_i32_i64_s_with_folded_offset(i32* %p) { 281 %q = ptrtoint i32* %p to i32 282 %r = add nuw i32 %q, 24 283 %s = inttoptr i32 %r to i32* 284 %t = load atomic i32, i32* %s seq_cst, align 4 285 %u = sext i32 %t to i64 286 ret i64 %u 287} 288 289; Fold a gep offset into a zero-extending load. 290; As above but 32 extended to 64 bit. 291; CHECK-LABEL: load_i32_i64_u_with_folded_gep_offset: 292; CHECK: i64.atomic.load32_u $push0=, 96($0){{$}} 293define i64 @load_i32_i64_u_with_folded_gep_offset(i32* %p) { 294 %s = getelementptr inbounds i32, i32* %p, i32 24 295 %t = load atomic i32, i32* %s seq_cst, align 4 296 %u = zext i32 %t to i64 297 ret i64 %u 298} 299 300; i8 return value should test anyext loads 301; CHECK-LABEL: ldi8_a1: 302; CHECK: i32.atomic.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} 303; CHECK-NEXT: return $pop[[NUM]]{{$}} 304define i8 @ldi8_a1(i8 *%p) { 305 %v = load atomic i8, i8* %p seq_cst, align 1 306 ret i8 %v 307} 308