Derek Schuff 18d85a33cc
[WebAssembly] Support acquire-release atomics in CodeGen (#184900)
Set the correct memory ordering for relaxed atomics after ISel. This
allows
SelectionDAG to keep the simple generic selection for target-independent
AtomicLoad nodes, but keeps the ordering immediate correct in the MIR.
Notably, the MachineMemOperand still has the original memory ordering
and MIR passes would use that rather than the ordering immedate to make
their code motion decisions (if we had any for Wasm, which we don't).
2026-03-16 09:11:54 -07:00

144 lines
4.7 KiB
LLVM

; 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
; A multithread fence is lowered to an atomic.fence instruction.
define void @fence_acquire() {
; NO-ATOMICS-LABEL: fence_acquire:
; NO-ATOMICS: .functype fence_acquire () -> ()
; NO-ATOMICS-NEXT: # %bb.0:
; NO-ATOMICS-NEXT: # fallthrough-return
;
; ATOMICS-LABEL: fence_acquire:
; ATOMICS: .functype fence_acquire () -> ()
; ATOMICS-NEXT: # %bb.0:
; ATOMICS-NEXT: atomic.fence
; ATOMICS-NEXT: # fallthrough-return
;
; RELAXED32-LABEL: fence_acquire:
; RELAXED32: .functype fence_acquire () -> ()
; RELAXED32-NEXT: # %bb.0:
; RELAXED32-NEXT: atomic.fence acqrel
; RELAXED32-NEXT: # fallthrough-return
;
; RELAXED64-LABEL: fence_acquire:
; RELAXED64: .functype fence_acquire () -> ()
; RELAXED64-NEXT: # %bb.0:
; RELAXED64-NEXT: atomic.fence acqrel
; RELAXED64-NEXT: # fallthrough-return
fence acquire
ret void
}
define void @fence_release() {
; NO-ATOMICS-LABEL: fence_release:
; NO-ATOMICS: .functype fence_release () -> ()
; NO-ATOMICS-NEXT: # %bb.0:
; NO-ATOMICS-NEXT: # fallthrough-return
;
; ATOMICS-LABEL: fence_release:
; ATOMICS: .functype fence_release () -> ()
; ATOMICS-NEXT: # %bb.0:
; ATOMICS-NEXT: atomic.fence
; ATOMICS-NEXT: # fallthrough-return
;
; RELAXED32-LABEL: fence_release:
; RELAXED32: .functype fence_release () -> ()
; RELAXED32-NEXT: # %bb.0:
; RELAXED32-NEXT: atomic.fence acqrel
; RELAXED32-NEXT: # fallthrough-return
;
; RELAXED64-LABEL: fence_release:
; RELAXED64: .functype fence_release () -> ()
; RELAXED64-NEXT: # %bb.0:
; RELAXED64-NEXT: atomic.fence acqrel
; RELAXED64-NEXT: # fallthrough-return
fence release
ret void
}
define void @fence_acq_rel() {
; NO-ATOMICS-LABEL: fence_acq_rel:
; NO-ATOMICS: .functype fence_acq_rel () -> ()
; NO-ATOMICS-NEXT: # %bb.0:
; NO-ATOMICS-NEXT: # fallthrough-return
;
; ATOMICS-LABEL: fence_acq_rel:
; ATOMICS: .functype fence_acq_rel () -> ()
; ATOMICS-NEXT: # %bb.0:
; ATOMICS-NEXT: atomic.fence
; ATOMICS-NEXT: # fallthrough-return
;
; RELAXED32-LABEL: fence_acq_rel:
; RELAXED32: .functype fence_acq_rel () -> ()
; RELAXED32-NEXT: # %bb.0:
; RELAXED32-NEXT: atomic.fence acqrel
; RELAXED32-NEXT: # fallthrough-return
;
; RELAXED64-LABEL: fence_acq_rel:
; RELAXED64: .functype fence_acq_rel () -> ()
; RELAXED64-NEXT: # %bb.0:
; RELAXED64-NEXT: atomic.fence acqrel
; RELAXED64-NEXT: # fallthrough-return
fence acq_rel
ret void
}
define void @fence_seq_cst() {
; NO-ATOMICS-LABEL: fence_seq_cst:
; NO-ATOMICS: .functype fence_seq_cst () -> ()
; NO-ATOMICS-NEXT: # %bb.0:
; NO-ATOMICS-NEXT: # fallthrough-return
;
; ATOMICS-LABEL: fence_seq_cst:
; ATOMICS: .functype fence_seq_cst () -> ()
; ATOMICS-NEXT: # %bb.0:
; ATOMICS-NEXT: atomic.fence
; ATOMICS-NEXT: # fallthrough-return
;
; RELAXED32-LABEL: fence_seq_cst:
; RELAXED32: .functype fence_seq_cst () -> ()
; RELAXED32-NEXT: # %bb.0:
; RELAXED32-NEXT: atomic.fence seqcst
; RELAXED32-NEXT: # fallthrough-return
;
; RELAXED64-LABEL: fence_seq_cst:
; RELAXED64: .functype fence_seq_cst () -> ()
; RELAXED64-NEXT: # %bb.0:
; RELAXED64-NEXT: atomic.fence seqcst
; RELAXED64-NEXT: # fallthrough-return
fence seq_cst
ret void
}
; A singlethread fence becomes compiler_fence instruction, a pseudo instruction
; that acts as a compiler barrier. The barrier should not be emitted to .s file.
define void @singlethread_fence() {
; NO-ATOMICS-LABEL: singlethread_fence:
; NO-ATOMICS: .functype singlethread_fence () -> ()
; NO-ATOMICS-NEXT: # %bb.0:
; NO-ATOMICS-NEXT: # fallthrough-return
;
; ATOMICS-LABEL: singlethread_fence:
; ATOMICS: .functype singlethread_fence () -> ()
; ATOMICS-NEXT: # %bb.0:
; ATOMICS-NEXT: # fallthrough-return
;
; RELAXED32-LABEL: singlethread_fence:
; RELAXED32: .functype singlethread_fence () -> ()
; RELAXED32-NEXT: # %bb.0:
; RELAXED32-NEXT: # fallthrough-return
;
; RELAXED64-LABEL: singlethread_fence:
; RELAXED64: .functype singlethread_fence () -> ()
; RELAXED64-NEXT: # %bb.0:
; RELAXED64-NEXT: # fallthrough-return
fence syncscope("singlethread") seq_cst
fence syncscope("singlethread") acquire
fence syncscope("singlethread") release
fence syncscope("singlethread") acq_rel
ret void
}