[llvm] [SPIR-V] Guard against infinite loop in decorateUsesAsNonUniform (PR #208224)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 10 00:01:22 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/208224
>From a61a2fb7305e2d8b6ef96aaaf95277b52c3ef87c Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 8 Jul 2026 15:56:12 +0200
Subject: [PATCH 1/5] [SPIR-V] Guard against infinite loop in
decorateUsesAsNonUniform
Add a visited set so an SSA cycle through a loop-carried phi does not hang the worklist walk
Fix OpDecorate insertion to skip past phis so it does not displace them as the block leading instruction which broke phi patching
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 10 ++++-
.../RWBufferNonUniformIdxLoop.ll | 41 +++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 274a3265f7115..33523817d7a99 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -22,6 +22,7 @@
#include "SPIRVTypeInst.h"
#include "SPIRVUtils.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
@@ -6318,10 +6319,14 @@ bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
void SPIRVInstructionSelector::decorateUsesAsNonUniform(
Register &NonUniformReg) const {
llvm::SmallVector<Register> WorkList = {NonUniformReg};
+ llvm::SmallSet<Register, 8> Visited;
while (WorkList.size() > 0) {
Register CurrentReg = WorkList.back();
WorkList.pop_back();
+ if (!Visited.insert(CurrentReg).second)
+ continue;
+
bool IsDecorated = false;
for (MachineInstr &Use : MRI->use_instructions(CurrentReg)) {
if (Use.getOpcode() == SPIRV::OpDecorate &&
@@ -6340,7 +6345,10 @@ void SPIRVInstructionSelector::decorateUsesAsNonUniform(
}
if (!IsDecorated) {
- buildOpDecorate(CurrentReg, *MRI->getVRegDef(CurrentReg), TII,
+ MachineInstr *DefMI = MRI->getVRegDef(CurrentReg);
+ MachineBasicBlock &MBB = *DefMI->getParent();
+ MachineInstr &InsertPt = DefMI->isPHI() ? *MBB.getFirstNonPHI() : *DefMI;
+ buildOpDecorate(CurrentReg, InsertPt, TII,
SPIRV::Decoration::NonUniformEXT, {});
}
}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
new file mode 100644
index 0000000000000..839c25ab6bc51
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
@@ -0,0 +1,41 @@
+; RUN: llc -O0 -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}
+
+; A non-uniform index carried across a loop through a phi creates an SSA cycle
+; (phi <-> add) in the use walk that propagates the NonUniformEXT decoration.
+; Check that codegen terminates and still decorates both the loop-carried index
+; phi and the access chain derived from it.
+
+target triple = "spirv1.6-unknown-vulkan1.3-compute"
+
+; CHECK-DAG: OpCapability Shader
+; CHECK-DAG: OpCapability ShaderNonUniformEXT
+; CHECK-DAG: OpCapability StorageTexelBufferArrayNonUniformIndexingEXT
+; CHECK-DAG: %[[#phi:]] = OpPhi {{.*}}
+; CHECK-DAG: %[[#access:]] = OpAccessChain {{%[0-9]+}} {{%[0-9]+}} %[[#phi]]
+; CHECK-DAG: OpDecorate %[[#phi]] NonUniformEXT
+; CHECK-DAG: OpDecorate %[[#access]] NonUniformEXT
+ at ReadWriteBuf.str = private unnamed_addr constant [13 x i8] c"ReadWriteBuf\00", align 1
+
+define void @main() local_unnamed_addr #0 {
+entry:
+ %ce = call token @llvm.experimental.convergence.entry()
+ %0 = tail call i32 @llvm.spv.thread.id.in.group.i32(i32 0)
+ %1 = tail call noundef i32 @llvm.spv.resource.nonuniformindex(i32 %0)
+ br label %header
+
+header:
+ %idx = phi i32 [ %1, %entry ], [ %idx.next, %header ]
+ %cl = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %ce) ]
+ %idx.next = add i32 %idx, 1
+ %cond = icmp slt i32 %idx.next, 10
+ br i1 %cond, label %header, label %merge
+
+merge:
+ %2 = tail call target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) @llvm.spv.resource.handlefromimplicitbinding.tspirv.Image_i32_5_2_0_0_2_33t(i32 0, i32 0, i32 64, i32 %idx, ptr nonnull @ReadWriteBuf.str)
+ %3 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_33t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) %2, i32 96) [ "convergencectrl"(token %ce) ]
+ store i32 95, ptr addrspace(11) %3, align 4
+ ret void
+}
+
+attributes #0 = { convergent norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
>From 8557be5339f192898cf5ca58ff0869dd1b1a489d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 9 Jul 2026 10:29:15 +0200
Subject: [PATCH 2/5] Address comments
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 33523817d7a99..25c361c7dbe4c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -6318,11 +6318,11 @@ bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
void SPIRVInstructionSelector::decorateUsesAsNonUniform(
Register &NonUniformReg) const {
- llvm::SmallVector<Register> WorkList = {NonUniformReg};
+ llvm::SmallVector<std::pair<Register, MachineInstr *>> WorkList = {
+ {NonUniformReg, nullptr}};
llvm::SmallSet<Register, 8> Visited;
while (WorkList.size() > 0) {
- Register CurrentReg = WorkList.back();
- WorkList.pop_back();
+ auto [CurrentReg, DefMI] = WorkList.pop_back_val();
if (!Visited.insert(CurrentReg).second)
continue;
@@ -6340,12 +6340,13 @@ void SPIRVInstructionSelector::decorateUsesAsNonUniform(
Register ResultReg = Use.getOperand(0).getReg();
if (ResultReg == CurrentReg)
continue;
- WorkList.push_back(ResultReg);
+ WorkList.push_back({ResultReg, &Use});
}
}
if (!IsDecorated) {
- MachineInstr *DefMI = MRI->getVRegDef(CurrentReg);
+ if (!DefMI)
+ DefMI = MRI->getVRegDef(CurrentReg);
MachineBasicBlock &MBB = *DefMI->getParent();
MachineInstr &InsertPt = DefMI->isPHI() ? *MBB.getFirstNonPHI() : *DefMI;
buildOpDecorate(CurrentReg, InsertPt, TII,
>From ec2078056c9123f73261dd0ced6764a2d8a278b1 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 9 Jul 2026 10:56:34 +0200
Subject: [PATCH 3/5] fix
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 25c361c7dbe4c..eff2b0dba87a1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -6319,7 +6319,7 @@ bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
void SPIRVInstructionSelector::decorateUsesAsNonUniform(
Register &NonUniformReg) const {
llvm::SmallVector<std::pair<Register, MachineInstr *>> WorkList = {
- {NonUniformReg, nullptr}};
+ {NonUniformReg, MRI->getVRegDef(NonUniformReg)}};
llvm::SmallSet<Register, 8> Visited;
while (WorkList.size() > 0) {
auto [CurrentReg, DefMI] = WorkList.pop_back_val();
@@ -6345,8 +6345,6 @@ void SPIRVInstructionSelector::decorateUsesAsNonUniform(
}
if (!IsDecorated) {
- if (!DefMI)
- DefMI = MRI->getVRegDef(CurrentReg);
MachineBasicBlock &MBB = *DefMI->getParent();
MachineInstr &InsertPt = DefMI->isPHI() ? *MBB.getFirstNonPHI() : *DefMI;
buildOpDecorate(CurrentReg, InsertPt, TII,
>From 7092ef6cc9fdc42fc83139f2ad6cba43c73d4474 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 9 Jul 2026 11:39:43 +0200
Subject: [PATCH 4/5] Revert "fix"
This reverts commit ec2078056c9123f73261dd0ced6764a2d8a278b1.
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index eff2b0dba87a1..25c361c7dbe4c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -6319,7 +6319,7 @@ bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
void SPIRVInstructionSelector::decorateUsesAsNonUniform(
Register &NonUniformReg) const {
llvm::SmallVector<std::pair<Register, MachineInstr *>> WorkList = {
- {NonUniformReg, MRI->getVRegDef(NonUniformReg)}};
+ {NonUniformReg, nullptr}};
llvm::SmallSet<Register, 8> Visited;
while (WorkList.size() > 0) {
auto [CurrentReg, DefMI] = WorkList.pop_back_val();
@@ -6345,6 +6345,8 @@ void SPIRVInstructionSelector::decorateUsesAsNonUniform(
}
if (!IsDecorated) {
+ if (!DefMI)
+ DefMI = MRI->getVRegDef(CurrentReg);
MachineBasicBlock &MBB = *DefMI->getParent();
MachineInstr &InsertPt = DefMI->isPHI() ? *MBB.getFirstNonPHI() : *DefMI;
buildOpDecorate(CurrentReg, InsertPt, TII,
>From 64371bdfbbf279e63b41a320df942a82b29b760a Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 10 Jul 2026 09:01:08 +0200
Subject: [PATCH 5/5] Address comments
---
.../hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
index 839c25ab6bc51..f9be9eae40ea1 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/NonUniformIdx/RWBufferNonUniformIdxLoop.ll
@@ -5,13 +5,12 @@
; (phi <-> add) in the use walk that propagates the NonUniformEXT decoration.
; Check that codegen terminates and still decorates both the loop-carried index
; phi and the access chain derived from it.
-
target triple = "spirv1.6-unknown-vulkan1.3-compute"
; CHECK-DAG: OpCapability Shader
; CHECK-DAG: OpCapability ShaderNonUniformEXT
; CHECK-DAG: OpCapability StorageTexelBufferArrayNonUniformIndexingEXT
-; CHECK-DAG: %[[#phi:]] = OpPhi {{.*}}
+; CHECK-DAG: %[[#phi:]] = OpPhi [[#]]
; CHECK-DAG: %[[#access:]] = OpAccessChain {{%[0-9]+}} {{%[0-9]+}} %[[#phi]]
; CHECK-DAG: OpDecorate %[[#phi]] NonUniformEXT
; CHECK-DAG: OpDecorate %[[#access]] NonUniformEXT
More information about the llvm-commits
mailing list