| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: llc < %s --mtriple=wasm32 | FileCheck %s --check-prefixes=NO-ATOMICS |
| ; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics | FileCheck %s --check-prefixes=ATOMICS |
| ; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED32 |
| ; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED64 |
| |
| ; Currently Wasm supports a constrained set of atomic memory orderings. |
| ; Originally it supported only sequential consistency, but now it also |
| ; supports relaxed atomics. Weaker orderings in LLVM IR are "upgraded" to |
| ; the next supported ordering. |
| |
| target triple = "wasm32-unknown-unknown" |
| |
| ;===---------------------------------------------------------------------------- |
| ; Atomic loads |
| ;===---------------------------------------------------------------------------- |
| |
| ; The 'release' and 'acq_rel' orderings are not valid on load instructions. |
| |
| define i32 @load_i32_unordered(ptr %p) { |
| ; NO-ATOMICS-LABEL: load_i32_unordered: |
| ; NO-ATOMICS: .functype load_i32_unordered (i32) -> (i32) |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: load_i32_unordered: |
| ; ATOMICS: .functype load_i32_unordered (i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: i32.atomic.load 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: load_i32_unordered: |
| ; RELAXED32: .functype load_i32_unordered (i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: load_i32_unordered: |
| ; RELAXED64: .functype load_i32_unordered (i64) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %v = load atomic i32, ptr %p unordered, align 4 |
| ret i32 %v |
| } |
| |
| define i32 @load_i32_monotonic(ptr %p) { |
| ; NO-ATOMICS-LABEL: load_i32_monotonic: |
| ; NO-ATOMICS: .functype load_i32_monotonic (i32) -> (i32) |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: load_i32_monotonic: |
| ; ATOMICS: .functype load_i32_monotonic (i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: i32.atomic.load 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: load_i32_monotonic: |
| ; RELAXED32: .functype load_i32_monotonic (i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: load_i32_monotonic: |
| ; RELAXED64: .functype load_i32_monotonic (i64) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %v = load atomic i32, ptr %p monotonic, align 4 |
| ret i32 %v |
| } |
| |
| define i32 @load_i32_acquire(ptr %p) { |
| ; NO-ATOMICS-LABEL: load_i32_acquire: |
| ; NO-ATOMICS: .functype load_i32_acquire (i32) -> (i32) |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: load_i32_acquire: |
| ; ATOMICS: .functype load_i32_acquire (i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: i32.atomic.load 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: load_i32_acquire: |
| ; RELAXED32: .functype load_i32_acquire (i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: load_i32_acquire: |
| ; RELAXED64: .functype load_i32_acquire (i64) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: i32.atomic.load acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %v = load atomic i32, ptr %p acquire, align 4 |
| ret i32 %v |
| } |
| |
| define i32 @load_i32_seq_cst(ptr %p) { |
| ; NO-ATOMICS-LABEL: load_i32_seq_cst: |
| ; NO-ATOMICS: .functype load_i32_seq_cst (i32) -> (i32) |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: load_i32_seq_cst: |
| ; ATOMICS: .functype load_i32_seq_cst (i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: i32.atomic.load 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: load_i32_seq_cst: |
| ; RELAXED32: .functype load_i32_seq_cst (i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: i32.atomic.load seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: load_i32_seq_cst: |
| ; RELAXED64: .functype load_i32_seq_cst (i64) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: i32.atomic.load seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %v = load atomic i32, ptr %p seq_cst, align 4 |
| ret i32 %v |
| } |
| |
| ;===---------------------------------------------------------------------------- |
| ; Atomic stores |
| ;===---------------------------------------------------------------------------- |
| |
| ; The 'acquire' and 'acq_rel' orderings aren’t valid on store instructions. |
| |
| define void @store_i32_unordered(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: store_i32_unordered: |
| ; NO-ATOMICS: .functype store_i32_unordered (i32, i32) -> () |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: store_i32_unordered: |
| ; ATOMICS: .functype store_i32_unordered (i32, i32) -> () |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.store 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: store_i32_unordered: |
| ; RELAXED32: .functype store_i32_unordered (i32, i32) -> () |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: store_i32_unordered: |
| ; RELAXED64: .functype store_i32_unordered (i64, i32) -> () |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| store atomic i32 %v, ptr %p unordered, align 4 |
| ret void |
| } |
| |
| define void @store_i32_monotonic(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: store_i32_monotonic: |
| ; NO-ATOMICS: .functype store_i32_monotonic (i32, i32) -> () |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: store_i32_monotonic: |
| ; ATOMICS: .functype store_i32_monotonic (i32, i32) -> () |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.store 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: store_i32_monotonic: |
| ; RELAXED32: .functype store_i32_monotonic (i32, i32) -> () |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: store_i32_monotonic: |
| ; RELAXED64: .functype store_i32_monotonic (i64, i32) -> () |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| store atomic i32 %v, ptr %p monotonic, align 4 |
| ret void |
| } |
| |
| define void @store_i32_release(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: store_i32_release: |
| ; NO-ATOMICS: .functype store_i32_release (i32, i32) -> () |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: store_i32_release: |
| ; ATOMICS: .functype store_i32_release (i32, i32) -> () |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.store 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: store_i32_release: |
| ; RELAXED32: .functype store_i32_release (i32, i32) -> () |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: store_i32_release: |
| ; RELAXED64: .functype store_i32_release (i64, i32) -> () |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.store acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| store atomic i32 %v, ptr %p release, align 4 |
| ret void |
| } |
| |
| define void @store_i32_seq_cst(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: store_i32_seq_cst: |
| ; NO-ATOMICS: .functype store_i32_seq_cst (i32, i32) -> () |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: store_i32_seq_cst: |
| ; ATOMICS: .functype store_i32_seq_cst (i32, i32) -> () |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.store 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: store_i32_seq_cst: |
| ; RELAXED32: .functype store_i32_seq_cst (i32, i32) -> () |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.store seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: store_i32_seq_cst: |
| ; RELAXED64: .functype store_i32_seq_cst (i64, i32) -> () |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.store seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| store atomic i32 %v, ptr %p seq_cst, align 4 |
| ret void |
| } |
| |
| ;===---------------------------------------------------------------------------- |
| ; Atomic read-modify-writes |
| ;===---------------------------------------------------------------------------- |
| |
| ; Out of several binary RMW instructions, here we test 'add' as an example. |
| ; The 'unordered' ordering is not valid on atomicrmw instructions. |
| |
| define i32 @add_i32_monotonic(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: add_i32_monotonic: |
| ; NO-ATOMICS: .functype add_i32_monotonic (i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 2 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.add |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: add_i32_monotonic: |
| ; ATOMICS: .functype add_i32_monotonic (i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.rmw.add 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: add_i32_monotonic: |
| ; RELAXED32: .functype add_i32_monotonic (i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: add_i32_monotonic: |
| ; RELAXED64: .functype add_i32_monotonic (i64, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %old = atomicrmw add ptr %p, i32 %v monotonic |
| ret i32 %old |
| } |
| |
| define i32 @add_i32_acquire(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: add_i32_acquire: |
| ; NO-ATOMICS: .functype add_i32_acquire (i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 2 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.add |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: add_i32_acquire: |
| ; ATOMICS: .functype add_i32_acquire (i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.rmw.add 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: add_i32_acquire: |
| ; RELAXED32: .functype add_i32_acquire (i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: add_i32_acquire: |
| ; RELAXED64: .functype add_i32_acquire (i64, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %old = atomicrmw add ptr %p, i32 %v acquire |
| ret i32 %old |
| } |
| |
| define i32 @add_i32_release(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: add_i32_release: |
| ; NO-ATOMICS: .functype add_i32_release (i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 2 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.add |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: add_i32_release: |
| ; ATOMICS: .functype add_i32_release (i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.rmw.add 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: add_i32_release: |
| ; RELAXED32: .functype add_i32_release (i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: add_i32_release: |
| ; RELAXED64: .functype add_i32_release (i64, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %old = atomicrmw add ptr %p, i32 %v release |
| ret i32 %old |
| } |
| |
| define i32 @add_i32_acq_rel(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: add_i32_acq_rel: |
| ; NO-ATOMICS: .functype add_i32_acq_rel (i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 2 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.add |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: add_i32_acq_rel: |
| ; ATOMICS: .functype add_i32_acq_rel (i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.rmw.add 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: add_i32_acq_rel: |
| ; RELAXED32: .functype add_i32_acq_rel (i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: add_i32_acq_rel: |
| ; RELAXED64: .functype add_i32_acq_rel (i64, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %old = atomicrmw add ptr %p, i32 %v acq_rel |
| ret i32 %old |
| } |
| |
| define i32 @add_i32_seq_cst(ptr %p, i32 %v) { |
| ; NO-ATOMICS-LABEL: add_i32_seq_cst: |
| ; NO-ATOMICS: .functype add_i32_seq_cst (i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 2 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.add |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: add_i32_seq_cst: |
| ; ATOMICS: .functype add_i32_seq_cst (i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: i32.atomic.rmw.add 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: add_i32_seq_cst: |
| ; RELAXED32: .functype add_i32_seq_cst (i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: i32.atomic.rmw.add seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: add_i32_seq_cst: |
| ; RELAXED64: .functype add_i32_seq_cst (i64, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: i32.atomic.rmw.add seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %old = atomicrmw add ptr %p, i32 %v seq_cst |
| ret i32 %old |
| } |
| |
| ; Ternary RMW instruction: cmpxchg |
| ; The success and failure ordering arguments specify how this cmpxchg |
| ; synchronizes with other atomic operations. Both ordering parameters must be at |
| ; least monotonic, the ordering constraint on failure must be no stronger than |
| ; that on success, and the failure ordering cannot be either release or acq_rel. |
| |
| define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic: |
| ; NO-ATOMICS: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic: |
| ; ATOMICS: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_monotonic_monotonic: |
| ; RELAXED32: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_monotonic_monotonic: |
| ; RELAXED64: .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_acquire_monotonic(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic: |
| ; NO-ATOMICS: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic: |
| ; ATOMICS: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_acquire_monotonic: |
| ; RELAXED32: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_acquire_monotonic: |
| ; RELAXED64: .functype cmpxchg_i32_acquire_monotonic (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire monotonic |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_release_monotonic: |
| ; NO-ATOMICS: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_release_monotonic: |
| ; ATOMICS: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_release_monotonic: |
| ; RELAXED32: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_release_monotonic: |
| ; RELAXED64: .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic: |
| ; NO-ATOMICS: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic: |
| ; ATOMICS: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_acq_rel_monotonic: |
| ; RELAXED32: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_acq_rel_monotonic: |
| ; RELAXED64: .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_seq_cst_monotonic(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic: |
| ; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic: |
| ; ATOMICS: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_seq_cst_monotonic: |
| ; RELAXED32: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_seq_cst_monotonic: |
| ; RELAXED64: .functype cmpxchg_i32_seq_cst_monotonic (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst monotonic |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_acquire: |
| ; NO-ATOMICS: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_acquire_acquire: |
| ; ATOMICS: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_acquire_acquire: |
| ; RELAXED32: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_acquire_acquire: |
| ; RELAXED64: .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_release_acquire(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_release_acquire: |
| ; NO-ATOMICS: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_release_acquire: |
| ; ATOMICS: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_release_acquire: |
| ; RELAXED32: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_release_acquire: |
| ; RELAXED64: .functype cmpxchg_i32_release_acquire (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new release acquire |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire: |
| ; NO-ATOMICS: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire: |
| ; ATOMICS: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_acq_rel_acquire: |
| ; RELAXED32: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_acq_rel_acquire: |
| ; RELAXED64: .functype cmpxchg_i32_acq_rel_acquire (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel acquire |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| ; CHECK-LABEL: cmpxchg_i32_seq_cst_acquire: |
| ; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32){{$}} |
| ; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} |
| ; CHECK-NEXT: return $pop0{{$}} |
| define i32 @cmpxchg_i32_seq_cst_acquire(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire: |
| ; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire: |
| ; ATOMICS: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_seq_cst_acquire: |
| ; RELAXED32: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_seq_cst_acquire: |
| ; RELAXED64: .functype cmpxchg_i32_seq_cst_acquire (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst acquire |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |
| |
| define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) { |
| ; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst: |
| ; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32) |
| ; NO-ATOMICS-NEXT: .local i32 |
| ; NO-ATOMICS-NEXT: # %bb.0: |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: local.get 2 |
| ; NO-ATOMICS-NEXT: local.get 0 |
| ; NO-ATOMICS-NEXT: i32.load 0 |
| ; NO-ATOMICS-NEXT: local.tee 3 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: local.get 1 |
| ; NO-ATOMICS-NEXT: i32.eq |
| ; NO-ATOMICS-NEXT: i32.select |
| ; NO-ATOMICS-NEXT: i32.store 0 |
| ; NO-ATOMICS-NEXT: local.get 3 |
| ; NO-ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst: |
| ; ATOMICS: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32) |
| ; ATOMICS-NEXT: # %bb.0: |
| ; ATOMICS-NEXT: local.get 0 |
| ; ATOMICS-NEXT: local.get 1 |
| ; ATOMICS-NEXT: local.get 2 |
| ; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0 |
| ; ATOMICS-NEXT: # fallthrough-return |
| ; |
| ; RELAXED32-LABEL: cmpxchg_i32_seq_cst_seq_cst: |
| ; RELAXED32: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32) |
| ; RELAXED32-NEXT: # %bb.0: |
| ; RELAXED32-NEXT: local.get 0 |
| ; RELAXED32-NEXT: local.get 1 |
| ; RELAXED32-NEXT: local.get 2 |
| ; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED32-NEXT: # fallthrough-return |
| ; |
| ; RELAXED64-LABEL: cmpxchg_i32_seq_cst_seq_cst: |
| ; RELAXED64: .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32) |
| ; RELAXED64-NEXT: # %bb.0: |
| ; RELAXED64-NEXT: local.get 0 |
| ; RELAXED64-NEXT: local.get 1 |
| ; RELAXED64-NEXT: local.get 2 |
| ; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0 |
| ; RELAXED64-NEXT: # fallthrough-return |
| %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst |
| %old = extractvalue { i32, i1 } %pair, 0 |
| ret i32 %old |
| } |