[llvm-branch-commits] [llvm] [CodeGen][AMDGPU] Allow elementwise atomic load/store at element alignment (PR #219906)
Harrison Hao via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Aug 31 01:49:29 PDT 2026
https://github.com/harrisonGPU updated https://github.com/llvm/llvm-project/pull/219906
>From 7e5272286580e210c4b7592b81bce9e7b05c5250 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Mon, 31 Aug 2026 12:55:56 +0800
Subject: [PATCH] [CodeGen][AMDGPU] Allow elementwise atomic load/store at
element alignment
---
llvm/include/llvm/CodeGen/TargetLowering.h | 13 +-
llvm/lib/CodeGen/AtomicExpandPass.cpp | 41 +++++-
.../SelectionDAG/SelectionDAGBuilder.cpp | 10 +-
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 16 +++
llvm/lib/Target/AMDGPU/SIISelLowering.h | 4 +
llvm/test/CodeGen/AMDGPU/load-atomic-flat.ll | 40 ++++++
.../test/CodeGen/AMDGPU/load-atomic-global.ll | 120 ++++++++++++++++++
llvm/test/CodeGen/AMDGPU/store-atomic-flat.ll | 24 ++++
.../CodeGen/AMDGPU/store-atomic-global.ll | 72 +++++++++++
.../AtomicExpand/AMDGPU/unaligned-atomic.ll | 37 ++++++
10 files changed, 365 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index b2dcb38df0243..f2a645fb2e148 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -2280,11 +2280,14 @@ class LLVM_ABI TargetLoweringBase {
unsigned getMinCmpXchgSizeInBits() const { return MinCmpXchgSizeInBits; }
/// Return true if the target supports an atomic access of \p SizeInBytes
- /// bytes at the given \p Alignment. The default implementation only allows
- /// naturally aligned atomics, unless setSupportsUnalignedAtomics(true) was
- /// called.
- virtual bool isAtomicAlignmentSupported(Align Alignment,
- uint64_t SizeInBytes) const {
+ /// bytes at the given \p Alignment in \p AddrSpace. \p ElementSizeInBytes is
+ /// the granularity at which the access has to be indivisible; it is smaller
+ /// than \p SizeInBytes only for elementwise atomics. The default
+ /// implementation ignores both and only allows naturally aligned atomics,
+ /// unless setSupportsUnalignedAtomics(true) was called.
+ virtual bool isAtomicAlignmentSupported(Align Alignment, uint64_t SizeInBytes,
+ uint64_t ElementSizeInBytes,
+ unsigned AddrSpace) const {
return SupportsUnalignedAtomics || Alignment.value() >= SizeInBytes;
}
diff --git a/llvm/lib/CodeGen/AtomicExpandPass.cpp b/llvm/lib/CodeGen/AtomicExpandPass.cpp
index f2ffa40030cc0..7a1d6c08adde4 100644
--- a/llvm/lib/CodeGen/AtomicExpandPass.cpp
+++ b/llvm/lib/CodeGen/AtomicExpandPass.cpp
@@ -230,6 +230,37 @@ static unsigned getAtomicOpSize(AtomicCmpXchgInst *CASI) {
return DL.getTypeStoreSize(CASI->getCompareOperand()->getType());
}
+static unsigned getAtomicOpElementSize(LoadInst *LI) {
+ if (!LI->isElementwise())
+ return getAtomicOpSize(LI);
+ return LI->getDataLayout().getTypeStoreSize(LI->getType()->getScalarType());
+}
+
+static unsigned getAtomicOpElementSize(StoreInst *SI) {
+ if (!SI->isElementwise())
+ return getAtomicOpSize(SI);
+ return SI->getDataLayout().getTypeStoreSize(
+ SI->getValueOperand()->getType()->getScalarType());
+}
+
+template <typename Inst> static unsigned getAtomicOpElementSize(Inst *I) {
+ return getAtomicOpSize(I);
+}
+
+/// Return the size \p I has to be aligned to. The element size is smaller than
+/// the whole access only for elementwise atomics, and only counts if the target
+/// can issue them at element alignment.
+template <typename Inst>
+static unsigned getRequiredAtomicSize(const TargetLowering *TLI, Inst *I) {
+ unsigned Size = getAtomicOpSize(I);
+ unsigned ElementSize = getAtomicOpElementSize(I);
+ if (ElementSize != Size &&
+ TLI->isAtomicAlignmentSupported(I->getAlign(), Size, ElementSize,
+ I->getPointerAddressSpace()))
+ return ElementSize;
+ return Size;
+}
+
/// Copy metadata that's safe to preserve when widening atomics.
static void copyMetadataForAtomic(Instruction &Dest,
const Instruction &Source) {
@@ -265,22 +296,22 @@ static void copyMetadataForAtomic(Instruction &Dest,
template <typename Inst>
static bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) {
- unsigned Size = getAtomicOpSize(I);
- Align Alignment = I->getAlign();
unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
- return Alignment >= Size && Size <= MaxSize;
+ return I->getAlign() >= getRequiredAtomicSize(TLI, I) &&
+ getAtomicOpSize(I) <= MaxSize;
}
template <typename Inst>
static void writeUnsupportedAtomicSizeReason(const TargetLowering *TLI, Inst *I,
raw_ostream &OS) {
+ unsigned RequiredSize = getRequiredAtomicSize(TLI, I);
unsigned Size = getAtomicOpSize(I);
Align Alignment = I->getAlign();
bool NeedSeparator = false;
- if (Alignment < Size) {
+ if (Alignment < RequiredSize) {
OS << "instruction alignment " << Alignment.value()
- << " is smaller than the required " << Size
+ << " is smaller than the required " << RequiredSize
<< "-byte alignment for this atomic operation";
NeedSeparator = true;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 7fb2b2aa9a220..6d084b8e31aa1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5367,8 +5367,11 @@ void SelectionDAGBuilder::visitAtomicLoad(const LoadInst &I) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType());
EVT MemVT = TLI.getMemValueType(DAG.getDataLayout(), I.getType());
+ EVT ElementVT = I.isElementwise() ? MemVT.getScalarType() : MemVT;
- if (!TLI.isAtomicAlignmentSupported(I.getAlign(), MemVT.getSizeInBits() / 8))
+ if (!TLI.isAtomicAlignmentSupported(I.getAlign(), MemVT.getSizeInBits() / 8,
+ ElementVT.getSizeInBits() / 8,
+ I.getPointerAddressSpace()))
report_fatal_error("Cannot generate unaligned atomic load");
auto Flags = TLI.getLoadMemOperandFlags(I, DAG.getDataLayout(), AC, LibInfo);
@@ -5403,8 +5406,11 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
EVT MemVT =
TLI.getMemValueType(DAG.getDataLayout(), I.getValueOperand()->getType());
+ EVT ElementVT = I.isElementwise() ? MemVT.getScalarType() : MemVT;
- if (!TLI.isAtomicAlignmentSupported(I.getAlign(), MemVT.getSizeInBits() / 8))
+ if (!TLI.isAtomicAlignmentSupported(I.getAlign(), MemVT.getSizeInBits() / 8,
+ ElementVT.getSizeInBits() / 8,
+ I.getPointerAddressSpace()))
report_fatal_error("Cannot generate unaligned atomic store");
auto Flags = TLI.getStoreMemOperandFlags(I, DAG.getDataLayout());
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index a8b4d1f9a568b..867c02f81619b 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -2361,6 +2361,22 @@ bool SITargetLowering::allowsMisalignedMemoryAccesses(
Alignment, Flags, IsFast);
}
+bool SITargetLowering::isAtomicAlignmentSupported(Align Alignment,
+ uint64_t SizeInBytes,
+ uint64_t ElementSizeInBytes,
+ unsigned AddrSpace) const {
+ // Each naturally aligned dword is separately atomic. Only global and flat
+ // opt in: the LDS 4 byte rule in allowsMisalignedMemoryAccessesImpl assumes
+ // lowering to ds_read2_b32, which never happens for an atomic.
+ if (ElementSizeInBytes < SizeInBytes && ElementSizeInBytes >= 4 &&
+ (AMDGPU::isExtendedGlobalAddrSpace(AddrSpace) ||
+ AddrSpace == AMDGPUAS::FLAT_ADDRESS))
+ return Alignment.value() >= ElementSizeInBytes;
+
+ return TargetLoweringBase::isAtomicAlignmentSupported(
+ Alignment, SizeInBytes, ElementSizeInBytes, AddrSpace);
+}
+
EVT SITargetLowering::getOptimalMemOpType(
LLVMContext &Context, const MemOp &Op,
const AttributeList &FuncAttributes) const {
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 8ece9f279a100..131d2ff315542 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -391,6 +391,10 @@ class SITargetLowering final : public AMDGPUTargetLowering {
MachineMemOperand::Flags Flags = MachineMemOperand::MONone,
unsigned *IsFast = nullptr) const override;
+ bool isAtomicAlignmentSupported(Align Alignment, uint64_t SizeInBytes,
+ uint64_t ElementSizeInBytes,
+ unsigned AddrSpace) const override;
+
EVT getOptimalMemOpType(LLVMContext &Context, const MemOp &Op,
const AttributeList &FuncAttributes) const override;
diff --git a/llvm/test/CodeGen/AMDGPU/load-atomic-flat.ll b/llvm/test/CodeGen/AMDGPU/load-atomic-flat.ll
index 69e3378ae08b9..5e9a593de9a74 100644
--- a/llvm/test/CodeGen/AMDGPU/load-atomic-flat.ll
+++ b/llvm/test/CodeGen/AMDGPU/load-atomic-flat.ll
@@ -48,6 +48,46 @@ define amdgpu_cs void @atomic_load_f32x2_monotonic_agent(ptr addrspace(0) %p, pt
ret void
}
+define amdgpu_cs void @atomic_load_f32x2_monotonic_agent_elementwise(ptr addrspace(0) %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: flat_load_dwordx2 v[0:1], v[0:1] glc
+; GFX9-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX9-NEXT: global_store_dword v[2:3], v0, off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: flat_load_dwordx2 v[0:1], v[0:1] glc dlc
+; GFX10-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX10-NEXT: global_store_dword v[2:3], v0, off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: flat_load_b64 v[0:1], v[0:1] glc
+; GFX11-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX11-NEXT: global_store_b32 v[2:3], v0, off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: flat_load_b64 v[0:1], v[0:1] scope:SCOPE_DEV
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX12-NEXT: global_store_b32 v[2:3], v0, off
+; GFX12-NEXT: s_endpgm
+ %a0 = load atomic elementwise <2 x float>, ptr addrspace(0) %p syncscope("agent") monotonic, align 4
+ %num1 = extractelement <2 x float> %a0, i32 0
+ %num2 = extractelement <2 x float> %a0, i32 1
+ %res = fadd float %num1, %num2
+ store float %res, ptr addrspace(1) %out, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_load_f16x2_monotonic_agent(ptr addrspace(0) %p, ptr addrspace(1) %out) {
; GFX9-LABEL: atomic_load_f16x2_monotonic_agent:
; GFX9: ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/load-atomic-global.ll b/llvm/test/CodeGen/AMDGPU/load-atomic-global.ll
index 5ac3ca4786e92..4860f6b7cad1a 100644
--- a/llvm/test/CodeGen/AMDGPU/load-atomic-global.ll
+++ b/llvm/test/CodeGen/AMDGPU/load-atomic-global.ll
@@ -48,6 +48,86 @@ define amdgpu_cs void @atomic_load_f32x2_monotonic_agent(ptr addrspace(1) %p, pt
ret void
}
+define amdgpu_cs void @atomic_load_f32x2_monotonic_agent_elementwise(ptr addrspace(1) %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_load_dwordx2 v[0:1], v[0:1], off glc
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX9-NEXT: global_store_dword v[2:3], v0, off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_load_dwordx2 v[0:1], v[0:1], off glc dlc
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX10-NEXT: global_store_dword v[2:3], v0, off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_load_b64 v[0:1], v[0:1], off glc
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX11-NEXT: global_store_b32 v[2:3], v0, off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_load_f32x2_monotonic_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_load_b64 v[0:1], v[0:1], off scope:SCOPE_DEV
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX12-NEXT: global_store_b32 v[2:3], v0, off
+; GFX12-NEXT: s_endpgm
+ %a0 = load atomic elementwise <2 x float>, ptr addrspace(1) %p syncscope("agent") monotonic, align 4
+ %num1 = extractelement <2 x float> %a0, i32 0
+ %num2 = extractelement <2 x float> %a0, i32 1
+ %res = fadd float %num1, %num2
+ store float %res, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+define amdgpu_cs void @atomic_load_f32x2_unordered_agent_elementwise(ptr addrspace(1) %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_load_f32x2_unordered_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_load_dwordx2 v[0:1], v[0:1], off
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX9-NEXT: global_store_dword v[2:3], v0, off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_load_f32x2_unordered_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_load_dwordx2 v[0:1], v[0:1], off
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX10-NEXT: global_store_dword v[2:3], v0, off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_load_f32x2_unordered_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_load_b64 v[0:1], v[0:1], off
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX11-NEXT: global_store_b32 v[2:3], v0, off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_load_f32x2_unordered_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_load_b64 v[0:1], v[0:1], off
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX12-NEXT: global_store_b32 v[2:3], v0, off
+; GFX12-NEXT: s_endpgm
+ %a0 = load atomic elementwise <2 x float>, ptr addrspace(1) %p syncscope("agent") unordered, align 4
+ %num1 = extractelement <2 x float> %a0, i32 0
+ %num2 = extractelement <2 x float> %a0, i32 1
+ %res = fadd float %num1, %num2
+ store float %res, ptr addrspace(1) %out, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_load_f32x2_seq_cst_agent(ptr addrspace(1) %p, ptr addrspace(1) %out) {
; GFX9-LABEL: atomic_load_f32x2_seq_cst_agent:
; GFX9: ; %bb.0:
@@ -134,6 +214,46 @@ define amdgpu_cs void @atomic_load_f32x2_monotonic_wavefront(ptr addrspace(1) %p
ret void
}
+define amdgpu_cs void @atomic_load_f32x2_monotonic_wavefront_elementwise(ptr addrspace(1) %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_load_f32x2_monotonic_wavefront_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_load_dwordx2 v[0:1], v[0:1], off
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX9-NEXT: global_store_dword v[2:3], v0, off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_load_f32x2_monotonic_wavefront_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_load_dwordx2 v[0:1], v[0:1], off
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX10-NEXT: global_store_dword v[2:3], v0, off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_load_f32x2_monotonic_wavefront_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_load_b64 v[0:1], v[0:1], off
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX11-NEXT: global_store_b32 v[2:3], v0, off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_load_f32x2_monotonic_wavefront_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_load_b64 v[0:1], v[0:1], off
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: v_add_f32_e32 v0, v0, v1
+; GFX12-NEXT: global_store_b32 v[2:3], v0, off
+; GFX12-NEXT: s_endpgm
+ %a0 = load atomic elementwise <2 x float>, ptr addrspace(1) %p syncscope("wavefront") monotonic, align 4
+ %num1 = extractelement <2 x float> %a0, i32 0
+ %num2 = extractelement <2 x float> %a0, i32 1
+ %res = fadd float %num1, %num2
+ store float %res, ptr addrspace(1) %out, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_load_f16x2_monotonic_agent(ptr addrspace(1) %p, ptr addrspace(1) %out) {
; GFX9-LABEL: atomic_load_f16x2_monotonic_agent:
; GFX9: ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/store-atomic-flat.ll b/llvm/test/CodeGen/AMDGPU/store-atomic-flat.ll
index 855091bb8a005..e2678e204d557 100644
--- a/llvm/test/CodeGen/AMDGPU/store-atomic-flat.ll
+++ b/llvm/test/CodeGen/AMDGPU/store-atomic-flat.ll
@@ -32,6 +32,30 @@ define amdgpu_cs void @atomic_store_f32x2_monotonic_agent(<2 x float> %in, ptr a
ret void
}
+define amdgpu_cs void @atomic_store_f32x2_monotonic_agent_elementwise(<2 x float> %in, ptr addrspace(0) %out) {
+; GFX9-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: flat_store_dwordx2 v[2:3], v[0:1]
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: flat_store_dwordx2 v[2:3], v[0:1]
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: flat_store_b64 v[2:3], v[0:1]
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: flat_store_b64 v[2:3], v[0:1] scope:SCOPE_DEV
+; GFX12-NEXT: s_endpgm
+ store atomic elementwise <2 x float> %in, ptr addrspace(0) %out syncscope("agent") monotonic, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_store_f16x2_monotonic_agent(<2 x half> %in, ptr addrspace(0) %out) {
; GFX9-LABEL: atomic_store_f16x2_monotonic_agent:
; GFX9: ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/store-atomic-global.ll b/llvm/test/CodeGen/AMDGPU/store-atomic-global.ll
index 3de24b553f793..9ff69256f1b92 100644
--- a/llvm/test/CodeGen/AMDGPU/store-atomic-global.ll
+++ b/llvm/test/CodeGen/AMDGPU/store-atomic-global.ll
@@ -32,6 +32,54 @@ define amdgpu_cs void @atomic_store_f32x2_monotonic_agent(<2 x float> %in, ptr a
ret void
}
+define amdgpu_cs void @atomic_store_f32x2_monotonic_agent_elementwise(<2 x float> %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_store_b64 v[2:3], v[0:1], off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_store_f32x2_monotonic_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_store_b64 v[2:3], v[0:1], off scope:SCOPE_DEV
+; GFX12-NEXT: s_endpgm
+ store atomic elementwise <2 x float> %in, ptr addrspace(1) %out syncscope("agent") monotonic, align 4
+ ret void
+}
+
+define amdgpu_cs void @atomic_store_f32x2_unordered_agent_elementwise(<2 x float> %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_store_f32x2_unordered_agent_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_store_f32x2_unordered_agent_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_store_f32x2_unordered_agent_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_store_b64 v[2:3], v[0:1], off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_store_f32x2_unordered_agent_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_store_b64 v[2:3], v[0:1], off
+; GFX12-NEXT: s_endpgm
+ store atomic elementwise <2 x float> %in, ptr addrspace(1) %out syncscope("agent") unordered, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_store_f32x2_seq_cst_agent(<2 x float> %in, ptr addrspace(1) %out) {
; GFX9-LABEL: atomic_store_f32x2_seq_cst_agent:
; GFX9: ; %bb.0:
@@ -80,6 +128,30 @@ define amdgpu_cs void @atomic_store_f32x2_seq_cst_wavefront(<2 x float> %in, ptr
ret void
}
+define amdgpu_cs void @atomic_store_f32x2_monotonic_wavefront_elementwise(<2 x float> %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: atomic_store_f32x2_monotonic_wavefront_elementwise:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX9-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_store_f32x2_monotonic_wavefront_elementwise:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: global_store_dwordx2 v[2:3], v[0:1], off
+; GFX10-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_store_f32x2_monotonic_wavefront_elementwise:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: global_store_b64 v[2:3], v[0:1], off
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_store_f32x2_monotonic_wavefront_elementwise:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: global_store_b64 v[2:3], v[0:1], off
+; GFX12-NEXT: s_endpgm
+ store atomic elementwise <2 x float> %in, ptr addrspace(1) %out syncscope("wavefront") monotonic, align 4
+ ret void
+}
+
define amdgpu_cs void @atomic_store_f16x2_monotonic_agent(<2 x half> %in, ptr addrspace(1) %out) {
; GFX9-LABEL: atomic_store_f16x2_monotonic_agent:
; GFX9: ; %bb.0:
diff --git a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
index e8884970c33e5..38a156684ff14 100644
--- a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
+++ b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
@@ -11,3 +11,40 @@ define void @atomic_store_global_align1(ptr addrspace(1) %ptr, i32 %val) {
store atomic i32 %val, ptr addrspace(1) %ptr monotonic, align 1
ret void
}
+
+; CHECK: error: unsupported atomic load: instruction alignment 2 is smaller than the required 8-byte alignment for this atomic operation
+define <2 x float> @atomic_load_global_elementwise_align2(ptr addrspace(1) %ptr) {
+ %val = load atomic elementwise <2 x float>, ptr addrspace(1) %ptr monotonic, align 2
+ ret <2 x float> %val
+}
+
+; CHECK: error: unsupported atomic store: instruction alignment 2 is smaller than the required 8-byte alignment for this atomic operation
+define void @atomic_store_global_elementwise_align2(ptr addrspace(1) %ptr, <2 x float> %val) {
+ store atomic elementwise <2 x float> %val, ptr addrspace(1) %ptr monotonic, align 2
+ ret void
+}
+
+; CHECK: error: unsupported atomic load: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
+define <2 x float> @atomic_load_global_align4(ptr addrspace(1) %ptr) {
+ %val = load atomic <2 x float>, ptr addrspace(1) %ptr monotonic, align 4
+ ret <2 x float> %val
+}
+
+; CHECK: error: unsupported atomic load: instruction alignment 2 is smaller than the required 4-byte alignment for this atomic operation
+define <2 x half> @atomic_load_global_elementwise_f16_align2(ptr addrspace(1) %ptr) {
+ %val = load atomic elementwise <2 x half>, ptr addrspace(1) %ptr monotonic, align 2
+ ret <2 x half> %val
+}
+
+; The LDS 4-byte rule assumes lowering to ds_read2_b32, which atomics never get.
+; CHECK: error: unsupported atomic load: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
+define <2 x float> @atomic_load_local_elementwise_align4(ptr addrspace(3) %ptr) {
+ %val = load atomic elementwise <2 x float>, ptr addrspace(3) %ptr monotonic, align 4
+ ret <2 x float> %val
+}
+
+; CHECK: error: unsupported atomic load: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
+define <4 x float> @atomic_load_global_elementwise_v4f32_align4(ptr addrspace(1) %ptr) {
+ %val = load atomic elementwise <4 x float>, ptr addrspace(1) %ptr monotonic, align 4
+ ret <4 x float> %val
+}
More information about the llvm-branch-commits
mailing list