| ; 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 | |
| } |