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