1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt 2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s 3 4; Currently all wasm atomic memory access instructions are sequentially 5; consistent, so even if LLVM IR specifies weaker orderings than that, we 6; should upgrade them to sequential ordering and treat them in the same way. 7 8target triple = "wasm32-unknown-unknown" 9 10;===---------------------------------------------------------------------------- 11; Atomic loads 12;===---------------------------------------------------------------------------- 13 14; The 'release' and 'acq_rel' orderings are not valid on load instructions. 15 16; CHECK-LABEL: load_i32_unordered: 17; CHECK: i32.atomic.load $push0=, 0($0){{$}} 18; CHECK-NEXT: return $pop0{{$}} 19define i32 @load_i32_unordered(ptr %p) { 20 %v = load atomic i32, ptr %p unordered, align 4 21 ret i32 %v 22} 23 24; CHECK-LABEL: load_i32_monotonic: 25; CHECK: i32.atomic.load $push0=, 0($0){{$}} 26; CHECK-NEXT: return $pop0{{$}} 27define i32 @load_i32_monotonic(ptr %p) { 28 %v = load atomic i32, ptr %p monotonic, align 4 29 ret i32 %v 30} 31 32; CHECK-LABEL: load_i32_acquire: 33; CHECK: i32.atomic.load $push0=, 0($0){{$}} 34; CHECK-NEXT: return $pop0{{$}} 35define i32 @load_i32_acquire(ptr %p) { 36 %v = load atomic i32, ptr %p acquire, align 4 37 ret i32 %v 38} 39 40; CHECK-LABEL: load_i32_seq_cst: 41; CHECK: i32.atomic.load $push0=, 0($0){{$}} 42; CHECK-NEXT: return $pop0{{$}} 43define i32 @load_i32_seq_cst(ptr %p) { 44 %v = load atomic i32, ptr %p seq_cst, align 4 45 ret i32 %v 46} 47 48;===---------------------------------------------------------------------------- 49; Atomic stores 50;===---------------------------------------------------------------------------- 51 52; The 'acquire' and 'acq_rel' orderings aren’t valid on store instructions. 53 54; CHECK-LABEL: store_i32_unordered: 55; CHECK-NEXT: .functype store_i32_unordered (i32, i32) -> (){{$}} 56; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 57; CHECK-NEXT: return{{$}} 58define void @store_i32_unordered(ptr %p, i32 %v) { 59 store atomic i32 %v, ptr %p unordered, align 4 60 ret void 61} 62 63; CHECK-LABEL: store_i32_monotonic: 64; CHECK-NEXT: .functype store_i32_monotonic (i32, i32) -> (){{$}} 65; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 66; CHECK-NEXT: return{{$}} 67define void @store_i32_monotonic(ptr %p, i32 %v) { 68 store atomic i32 %v, ptr %p monotonic, align 4 69 ret void 70} 71 72; CHECK-LABEL: store_i32_release: 73; CHECK-NEXT: .functype store_i32_release (i32, i32) -> (){{$}} 74; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 75; CHECK-NEXT: return{{$}} 76define void @store_i32_release(ptr %p, i32 %v) { 77 store atomic i32 %v, ptr %p release, align 4 78 ret void 79} 80 81; CHECK-LABEL: store_i32_seq_cst: 82; CHECK-NEXT: .functype store_i32_seq_cst (i32, i32) -> (){{$}} 83; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}} 84; CHECK-NEXT: return{{$}} 85define void @store_i32_seq_cst(ptr %p, i32 %v) { 86 store atomic i32 %v, ptr %p seq_cst, align 4 87 ret void 88} 89 90;===---------------------------------------------------------------------------- 91; Atomic read-modify-writes 92;===---------------------------------------------------------------------------- 93 94; Out of several binary RMW instructions, here we test 'add' as an example. 95; The 'unordered' ordering is not valid on atomicrmw instructions. 96 97; CHECK-LABEL: add_i32_monotonic: 98; CHECK-NEXT: .functype add_i32_monotonic (i32, i32) -> (i32){{$}} 99; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 100; CHECK-NEXT: return $pop0{{$}} 101define i32 @add_i32_monotonic(ptr %p, i32 %v) { 102 %old = atomicrmw add ptr %p, i32 %v monotonic 103 ret i32 %old 104} 105 106; CHECK-LABEL: add_i32_acquire: 107; CHECK-NEXT: .functype add_i32_acquire (i32, i32) -> (i32){{$}} 108; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 109; CHECK-NEXT: return $pop0{{$}} 110define i32 @add_i32_acquire(ptr %p, i32 %v) { 111 %old = atomicrmw add ptr %p, i32 %v acquire 112 ret i32 %old 113} 114 115; CHECK-LABEL: add_i32_release: 116; CHECK-NEXT: .functype add_i32_release (i32, i32) -> (i32){{$}} 117; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 118; CHECK-NEXT: return $pop0{{$}} 119define i32 @add_i32_release(ptr %p, i32 %v) { 120 %old = atomicrmw add ptr %p, i32 %v release 121 ret i32 %old 122} 123 124; CHECK-LABEL: add_i32_acq_rel: 125; CHECK-NEXT: .functype add_i32_acq_rel (i32, i32) -> (i32){{$}} 126; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 127; CHECK-NEXT: return $pop0{{$}} 128define i32 @add_i32_acq_rel(ptr %p, i32 %v) { 129 %old = atomicrmw add ptr %p, i32 %v acq_rel 130 ret i32 %old 131} 132 133; CHECK-LABEL: add_i32_seq_cst: 134; CHECK-NEXT: .functype add_i32_seq_cst (i32, i32) -> (i32){{$}} 135; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 136; CHECK-NEXT: return $pop0{{$}} 137define i32 @add_i32_seq_cst(ptr %p, i32 %v) { 138 %old = atomicrmw add ptr %p, i32 %v seq_cst 139 ret i32 %old 140} 141 142; Ternary RMW instruction: cmpxchg 143; The success and failure ordering arguments specify how this cmpxchg 144; synchronizes with other atomic operations. Both ordering parameters must be at 145; least monotonic, the ordering constraint on failure must be no stronger than 146; that on success, and the failure ordering cannot be either release or acq_rel. 147 148; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic: 149; CHECK-NEXT: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32){{$}} 150; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 151; CHECK-NEXT: return $pop0{{$}} 152define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) { 153 %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic 154 %old = extractvalue { i32, i1 } %pair, 0 155 ret i32 %old 156} 157 158; CHECK-LABEL: cmpxchg_i32_acquire_monotonic: 159; CHECK-NEXT: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32){{$}} 160; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 161; CHECK-NEXT: return $pop0{{$}} 162define i32 @cmpxchg_i32_acquire_monotonic(ptr %p, i32 %exp, i32 %new) { 163 %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire monotonic 164 %old = extractvalue { i32, i1 } %pair, 0 165 ret i32 %old 166} 167 168; CHECK-LABEL: cmpxchg_i32_release_monotonic: 169; CHECK-NEXT: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32){{$}} 170; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 171; CHECK-NEXT: return $pop0{{$}} 172define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) { 173 %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic 174 %old = extractvalue { i32, i1 } %pair, 0 175 ret i32 %old 176} 177 178; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic: 179; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32){{$}} 180; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 181; CHECK-NEXT: return $pop0{{$}} 182define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) { 183 %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic 184 %old = extractvalue { i32, i1 } %pair, 0 185 ret i32 %old 186} 187 188; CHECK-LABEL: cmpxchg_i32_seq_cst_monotonic: 189; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32){{$}} 190; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 191; CHECK-NEXT: return $pop0{{$}} 192define i32 @cmpxchg_i32_seq_cst_monotonic(ptr %p, i32 %exp, i32 %new) { 193 %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst monotonic 194 %old = extractvalue { i32, i1 } %pair, 0 195 ret i32 %old 196} 197 198; CHECK-LABEL: cmpxchg_i32_acquire_acquire: 199; CHECK-NEXT: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32){{$}} 200; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 201; CHECK-NEXT: return $pop0{{$}} 202define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) { 203 %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire 204 %old = extractvalue { i32, i1 } %pair, 0 205 ret i32 %old 206} 207 208; CHECK-LABEL: cmpxchg_i32_release_acquire: 209; CHECK-NEXT: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32){{$}} 210; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 211; CHECK-NEXT: return $pop0{{$}} 212define i32 @cmpxchg_i32_release_acquire(ptr %p, i32 %exp, i32 %new) { 213 %pair = cmpxchg ptr %p, i32 %exp, i32 %new release acquire 214 %old = extractvalue { i32, i1 } %pair, 0 215 ret i32 %old 216} 217 218; CHECK-LABEL: cmpxchg_i32_acq_rel_acquire: 219; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32){{$}} 220; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 221; CHECK-NEXT: return $pop0{{$}} 222define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) { 223 %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel acquire 224 %old = extractvalue { i32, i1 } %pair, 0 225 ret i32 %old 226} 227 228; CHECK-LABEL: cmpxchg_i32_seq_cst_acquire: 229; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32){{$}} 230; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 231; CHECK-NEXT: return $pop0{{$}} 232define i32 @cmpxchg_i32_seq_cst_acquire(ptr %p, i32 %exp, i32 %new) { 233 %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst acquire 234 %old = extractvalue { i32, i1 } %pair, 0 235 ret i32 %old 236} 237 238; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst: 239; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32){{$}} 240; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 241; CHECK-NEXT: return $pop0{{$}} 242define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) { 243 %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst 244 %old = extractvalue { i32, i1 } %pair, 0 245 ret i32 %old 246} 247