[llvm] [AMDGPU] Reject illegal image atomic data widths in SelectionDAG (PR #210366)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 19 08:52:49 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/210366

>From b7ee0dff8d8f6057357bee28131110836420c5ce 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/3] [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 2b8396adf3eb678221be64b843464bbe6f6dbe3c 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/3] 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 c61a2edd45255..5f6626a851be1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -10464,6 +10464,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.

>From 2bd208ff10ad80e08a7f08429380a6e8752a4c25 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Sun, 19 Jul 2026 17:52:19 +0200
Subject: [PATCH 3/3] rename func

---
 llvm/include/llvm/CodeGen/SelectionDAG.h              | 7 ++++---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp        | 4 ++--
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 +-
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp             | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index c39a9d9a85d7d..799fab77ad1eb 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1519,9 +1519,10 @@ class SelectionDAG {
 
   /// 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);
+  /// node. Used to salvage a chain when an operation cannot be lowered due
+  /// to an error, and the program will be discarded.
+  LLVM_ABI SDValue getErrorMergeValues(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 5f6626a851be1..53ab797986dfc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -10464,8 +10464,8 @@ 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) {
+SDValue SelectionDAG::getErrorMergeValues(ArrayRef<EVT> ResultTypes,
+                                          SDValue Chain, const SDLoc &dl) {
   SmallVector<SDValue, 4> RetValues;
   RetValues.reserve(ResultTypes.size());
   for (EVT VT : ResultTypes)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index ccffd6f0bce7f..effa4a8d5f1b9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1821,7 +1821,7 @@ void SelectionDAGBuilder::setValueToPoison(const Value *V, const SDLoc &dl) {
   SmallVector<EVT, 4> ValueVTs;
   ComputeValueVTs(DAG.getTargetLoweringInfo(), DAG.getDataLayout(),
                   V->getType(), ValueVTs);
-  setValue(V, DAG.getPoisonMergeValues(ValueVTs, SDValue(), dl));
+  setValue(V, DAG.getErrorMergeValues(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 8f58c77f0ef4f..8156de7a24b01 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10333,7 +10333,7 @@ static SDValue diagnoseUnsupportedImage(SelectionDAG &DAG, SDValue Op,
                                         const SDLoc &DL, const Twine &Msg) {
   DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
       DAG.getMachineFunction().getFunction(), Msg, DL.getDebugLoc()));
-  return DAG.getPoisonMergeValues(ResultTypes, Op.getOperand(0), DL);
+  return DAG.getErrorMergeValues(ResultTypes, Op.getOperand(0), DL);
 }
 
 SDValue SITargetLowering::lowerImage(SDValue Op,



More information about the llvm-commits mailing list