[llvm] [AMDGPU] Reject illegal image atomic data widths in SelectionDAG (PR #210366)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 10:03:26 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/210366
>From e19680293e153533f71262535b7f1c640c111ddf Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 17 Jul 2026 18:25:06 +0200
Subject: [PATCH 1/2] [AMDGPU] Reject illegal image atomic data widths in
SelectionDAG
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 18 ++++++++
...cn.image.atomic.illegal-data-type.xfail.ll | 45 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 87e951e489ba5..4258911cb8792 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10373,6 +10373,24 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16 ||
IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16_NORTN);
+ if (!IsAtomicPacked16Bit && VData.getValueSizeInBits() != 32 &&
+ VData.getValueSizeInBits() != 64) {
+ DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+ DAG.getMachineFunction().getFunction(),
+ "unsupported image atomic data type", DL.getDebugLoc()));
+
+ unsigned Idx = 0;
+ SmallVector<SDValue, 3> RetValues(OrigResultTypes.size());
+ for (EVT VT : OrigResultTypes) {
+ if (VT == MVT::Other)
+ RetValues[Idx++] = Op.getOperand(0); // Chain
+ else
+ RetValues[Idx++] = DAG.getPOISON(VT);
+ }
+
+ return DAG.getMergeValues(RetValues, DL);
+ }
+
bool Is64Bit = VData.getValueSizeInBits() == 64;
if (BaseOpcode->AtomicX2) {
SDValue VData2 = Op.getOperand(3);
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll
new file mode 100644
index 0000000000000..59bdeb71b8a18
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll
@@ -0,0 +1,45 @@
+; RUN: not llc -mtriple=amdgcn -mcpu=gfx90a -filetype=null %s 2>&1 | FileCheck %s
+
+; llvm.amdgcn.image.atomic.<op> only supports 32-bit, 64-bit, and packed
+; f16/bf16 data.
+
+; CHECK: error: {{.*}}unsupported image atomic data type
+define amdgpu_kernel void @swap_v3i32(<8 x i32> inreg %rsrc, i32 %s, <3 x i32> %data, ptr addrspace(1) %out) {
+ %v = call <3 x i32> @llvm.amdgcn.image.atomic.swap.1d.v3i32.i32(<3 x i32> %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ store <3 x i32> %v, ptr addrspace(1) %out
+ ret void
+}
+
+; CHECK: error: {{.*}}unsupported image atomic data type
+define amdgpu_kernel void @swap_v3i16(<8 x i32> inreg %rsrc, i32 %s, <3 x i16> %data, ptr addrspace(1) %out) {
+ %v = call <3 x i16> @llvm.amdgcn.image.atomic.swap.1d.v3i16.i32(<3 x i16> %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ store <3 x i16> %v, ptr addrspace(1) %out
+ ret void
+}
+
+; CHECK: error: {{.*}}unsupported image atomic data type
+define amdgpu_kernel void @swap_bf16(<8 x i32> inreg %rsrc, i32 %s, bfloat %data, ptr addrspace(1) %out) {
+ %v = call bfloat @llvm.amdgcn.image.atomic.swap.1d.bf16.i32(bfloat %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ store bfloat %v, ptr addrspace(1) %out
+ ret void
+}
+
+; CHECK: error: {{.*}}unsupported image atomic data type
+define amdgpu_kernel void @swap_i128(<8 x i32> inreg %rsrc, i32 %s, i128 %data, ptr addrspace(1) %out) {
+ %v = call i128 @llvm.amdgcn.image.atomic.swap.1d.i128.i32(i128 %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ store i128 %v, ptr addrspace(1) %out
+ ret void
+}
+
+; CHECK: error: {{.*}}unsupported image atomic data type
+define amdgpu_kernel void @cmpswap_i128(<8 x i32> inreg %rsrc, i32 %s, i128 %cmp, i128 %data, ptr addrspace(1) %out) {
+ %v = call i128 @llvm.amdgcn.image.atomic.cmpswap.1d.i128.i32(i128 %cmp, i128 %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ store i128 %v, ptr addrspace(1) %out
+ ret void
+}
+
+declare <3 x i32> @llvm.amdgcn.image.atomic.swap.1d.v3i32.i32(<3 x i32>, i32, <8 x i32>, i32, i32)
+declare <3 x i16> @llvm.amdgcn.image.atomic.swap.1d.v3i16.i32(<3 x i16>, i32, <8 x i32>, i32, i32)
+declare bfloat @llvm.amdgcn.image.atomic.swap.1d.bf16.i32(bfloat, i32, <8 x i32>, i32, i32)
+declare i128 @llvm.amdgcn.image.atomic.swap.1d.i128.i32(i128, i32, <8 x i32>, i32, i32)
+declare i128 @llvm.amdgcn.image.atomic.cmpswap.1d.i128.i32(i128, i128, i32, <8 x i32>, i32, i32)
>From f09d924e34677b53da472c5117d3684b9e287090 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 17 Jul 2026 19:03:10 +0200
Subject: [PATCH 2/2] Address comments
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 6 +++
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 9 ++++
.../SelectionDAG/SelectionDAGBuilder.cpp | 5 +--
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 44 +++++++------------
...gcn.image.atomic.illegal-data-type.err.ll} | 2 +-
5 files changed, 32 insertions(+), 34 deletions(-)
rename llvm/test/CodeGen/AMDGPU/{llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll => llvm.amdgcn.image.atomic.illegal-data-type.err.ll} (96%)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index abc2e1f0ebe4f..c39a9d9a85d7d 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1517,6 +1517,12 @@ class SelectionDAG {
/// Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDValue getMergeValues(ArrayRef<SDValue> Ops, const SDLoc &dl);
+ /// Return poison values for each of \p ResultTypes, substituting \p Chain
+ /// for any result of type MVT::Other, merged into a single MERGE_VALUES
+ /// node. Used to salvage a chain when an operation cannot be lowered.
+ LLVM_ABI SDValue getPoisonMergeValues(ArrayRef<EVT> ResultTypes,
+ SDValue Chain, const SDLoc &dl);
+
/// Loads are not normal binary operators: their result type is not
/// determined by their operands, and they produce a value AND a token chain.
///
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index a8ae7927726ce..d427e189f0f70 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -10431,6 +10431,15 @@ SDValue SelectionDAG::getMergeValues(ArrayRef<SDValue> Ops, const SDLoc &dl) {
return getNode(ISD::MERGE_VALUES, dl, getVTList(VTs), Ops);
}
+SDValue SelectionDAG::getPoisonMergeValues(ArrayRef<EVT> ResultTypes,
+ SDValue Chain, const SDLoc &dl) {
+ SmallVector<SDValue, 4> RetValues;
+ RetValues.reserve(ResultTypes.size());
+ for (EVT VT : ResultTypes)
+ RetValues.push_back(VT == MVT::Other ? Chain : getPOISON(VT));
+ return getMergeValues(RetValues, dl);
+}
+
SDValue SelectionDAG::getMemIntrinsicNode(
unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef<SDValue> Ops,
EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 0f6bd53cafdd8..ccffd6f0bce7f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1821,10 +1821,7 @@ void SelectionDAGBuilder::setValueToPoison(const Value *V, const SDLoc &dl) {
SmallVector<EVT, 4> ValueVTs;
ComputeValueVTs(DAG.getTargetLoweringInfo(), DAG.getDataLayout(),
V->getType(), ValueVTs);
- SmallVector<SDValue, 4> Results;
- for (EVT VT : ValueVTs)
- Results.push_back(DAG.getPOISON(VT));
- setValue(V, DAG.getMergeValues(Results, dl));
+ setValue(V, DAG.getPoisonMergeValues(ValueVTs, SDValue(), dl));
}
/// getNonRegisterValue - Return an SDValue for the given Value, but
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 4258911cb8792..8f58c77f0ef4f 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10326,6 +10326,16 @@ static void packImage16bitOpsToDwords(SelectionDAG &DAG, SDValue Op,
}
}
+/// Emit a DiagnosticInfoUnsupported for an unsupported image intrinsic and
+/// return poison values of \p ResultTypes, preserving the chain if present.
+static SDValue diagnoseUnsupportedImage(SelectionDAG &DAG, SDValue Op,
+ ArrayRef<EVT> ResultTypes,
+ const SDLoc &DL, const Twine &Msg) {
+ DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+ DAG.getMachineFunction().getFunction(), Msg, DL.getDebugLoc()));
+ return DAG.getPoisonMergeValues(ResultTypes, Op.getOperand(0), DL);
+}
+
SDValue SITargetLowering::lowerImage(SDValue Op,
const AMDGPU::ImageDimIntrinsicInfo *Intr,
SelectionDAG &DAG, bool WithChain) const {
@@ -10375,20 +10385,8 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
if (!IsAtomicPacked16Bit && VData.getValueSizeInBits() != 32 &&
VData.getValueSizeInBits() != 64) {
- DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
- DAG.getMachineFunction().getFunction(),
- "unsupported image atomic data type", DL.getDebugLoc()));
-
- unsigned Idx = 0;
- SmallVector<SDValue, 3> RetValues(OrigResultTypes.size());
- for (EVT VT : OrigResultTypes) {
- if (VT == MVT::Other)
- RetValues[Idx++] = Op.getOperand(0); // Chain
- else
- RetValues[Idx++] = DAG.getPOISON(VT);
- }
-
- return DAG.getMergeValues(RetValues, DL);
+ return diagnoseUnsupportedImage(DAG, Op, OrigResultTypes, DL,
+ "unsupported image atomic data type");
}
bool Is64Bit = VData.getValueSizeInBits() == 64;
@@ -10710,21 +10708,9 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx90a,
NumVDataDwords, NumVAddrDwords);
if (Opcode == -1) {
- DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
- DAG.getMachineFunction().getFunction(),
- "requested image instruction is not supported on this GPU",
- DL.getDebugLoc()));
-
- unsigned Idx = 0;
- SmallVector<SDValue, 3> RetValues(OrigResultTypes.size());
- for (EVT VT : OrigResultTypes) {
- if (VT == MVT::Other)
- RetValues[Idx++] = Op.getOperand(0); // Chain
- else
- RetValues[Idx++] = DAG.getPOISON(VT);
- }
-
- return DAG.getMergeValues(RetValues, DL);
+ return diagnoseUnsupportedImage(
+ DAG, Op, OrigResultTypes, DL,
+ "requested image instruction is not supported on this GPU");
}
}
if (Opcode == -1 &&
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.err.ll
similarity index 96%
rename from llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll
rename to llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.err.ll
index 59bdeb71b8a18..abab901a22ec4 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.xfail.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.atomic.illegal-data-type.err.ll
@@ -1,4 +1,4 @@
-; RUN: not llc -mtriple=amdgcn -mcpu=gfx90a -filetype=null %s 2>&1 | FileCheck %s
+; RUN: not llc -mtriple=amdgpu9.0a -filetype=null %s 2>&1 | FileCheck %s
; llvm.amdgcn.image.atomic.<op> only supports 32-bit, 64-bit, and packed
; f16/bf16 data.
More information about the llvm-commits
mailing list