[llvm] [SPIR-V] Add SPV_INTEL_unstructured_loop_controls extension (PR #178799)
Dmitry Sidorov via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 2 04:53:24 PST 2026
https://github.com/MrSidims updated https://github.com/llvm/llvm-project/pull/178799
>From c0feae4d91a144e9b310e18f0bbaad88d451d115 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 30 Jan 2026 01:31:24 +0100
Subject: [PATCH 1/4] [SPIR-V] Add SPV_INTEL_unstructured_loop_controls
extension
For compute we don't run structurizer hence we won't be able to preserve
loop metadata via LoopMerge instruction. So SPV_INTEL_unstructured_loop_controls
is the only way we can preserve the info in unstructured control flow.
---
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 +
.../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 3 +-
llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp | 4 +-
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 36 ++++++
llvm/lib/Target/SPIRV/SPIRVInstrInfo.td | 2 +
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 7 ++
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 5 +
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 1 +
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 30 +++--
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 +
.../loop-unroll.ll | 103 ++++++++++++++++++
11 files changed, 182 insertions(+), 12 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 6124ce594d1ea..c5d4febb7a08d 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -35,6 +35,7 @@ let TargetPrefix = "spv" in {
def int_spv_ptrcast : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
def int_spv_switch : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
def int_spv_loop_merge : Intrinsic<[], [llvm_vararg_ty]>;
+ def int_spv_loop_control_intel : Intrinsic<[], [llvm_vararg_ty]>;
def int_spv_selection_merge : Intrinsic<[], [llvm_any_ty, llvm_i32_ty], [ImmArg<ArgIndex<1>>]>;
def int_spv_cmpxchg : Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_vararg_ty]>;
def int_spv_unreachable : Intrinsic<[], []>;
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 42de884840dc9..66500f5626fd1 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -155,7 +155,8 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
break;
case SPIRV::OpExecutionMode:
case SPIRV::OpExecutionModeId:
- case SPIRV::OpLoopMerge: {
+ case SPIRV::OpLoopMerge:
+ case SPIRV::OpLoopControlINTEL: {
// Print any literals after the OPERAND_UNKNOWN argument normally.
printRemainingVariableOps(MI, NumFixedOps, OS);
break;
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 5a70c95bc6fd3..0abdc3b71c4ec 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -181,7 +181,9 @@ static const std::map<StringRef, SPIRV::Extension::Extension>
SPIRV::Extension::Extension::
SPV_ALTERA_arbitrary_precision_fixed_point},
{"SPV_EXT_image_raw10_raw12",
- SPIRV::Extension::Extension::SPV_EXT_image_raw10_raw12}};
+ SPIRV::Extension::Extension::SPV_EXT_image_raw10_raw12},
+ {"SPV_INTEL_unstructured_loop_controls",
+ SPIRV::Extension::Extension::SPV_INTEL_unstructured_loop_controls}};
bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 0ae30a2cdf1ac..c6b46be2eb3f9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -207,6 +207,8 @@ class SPIRVEmitIntrinsics
void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
+ void emitUnstructuredLoopControls(Function &F, IRBuilder<> &B);
+
// Tries to walk the type accessed by the given GEP instruction.
// For each nested type access, one of the 2 callbacks is called:
// - OnLiteralIndexing when the index is a known constant value.
@@ -2878,6 +2880,38 @@ SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {
return nullptr;
}
+void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &F,
+ IRBuilder<> &B) {
+ const SPIRVSubtarget *ST = TM->getSubtargetImpl(F);
+ // Shaders use SPIRVStructurizer which emits OpLoopMerge via spv_loop_merge.
+ if (ST->isShader())
+ return;
+ if (!ST->canUseExtension(
+ SPIRV::Extension::SPV_INTEL_unstructured_loop_controls))
+ return;
+
+ for (BasicBlock &BB : F) {
+ Instruction *Term = BB.getTerminator();
+ MDNode *LoopMD = Term->getMetadata(LLVMContext::MD_loop);
+ if (!LoopMD)
+ continue;
+
+ SmallVector<unsigned, 1> Ops =
+ getSpirvLoopControlOperandsFromLoopMetadata(LoopMD);
+ unsigned LC = Ops[0];
+ if (LC == SPIRV::LoopControl::None)
+ continue;
+
+ // Emit intrinsic: loop control mask + optional parameters.
+ B.SetInsertPoint(Term);
+ SmallVector<Value *, 4> IntrArgs;
+ IntrArgs.push_back(ConstantInt::get(B.getInt32Ty(), LC));
+ for (unsigned I = 1; I < Ops.size(); ++I)
+ IntrArgs.push_back(ConstantInt::get(B.getInt32Ty(), Ops[I]));
+ B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, {}, IntrArgs);
+ }
+}
+
bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
if (Func.isDeclaration())
return false;
@@ -2994,6 +3028,8 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
processInstrAfterVisit(I, B);
}
+ emitUnstructuredLoopControls(Func, B);
+
return true;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
index 7ca1384abc950..678672c3651d5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
@@ -622,6 +622,8 @@ def OpPhi: Op<245, (outs ID:$res), (ins TYPE:$type, ID:$var0, ID:$block0, variab
"$res = OpPhi $type $var0 $block0">;
def OpLoopMerge: Op<246, (outs), (ins unknown:$merge, unknown:$continue, LoopControl:$lc, variable_ops),
"OpLoopMerge $merge $continue $lc">;
+def OpLoopControlINTEL: Op<5887, (outs), (ins LoopControl:$lc, variable_ops),
+ "OpLoopControlINTEL $lc">;
def OpSelectionMerge: Op<247, (outs), (ins unknown:$merge, SelectionControl:$sc),
"OpSelectionMerge $merge $sc">;
def OpLabel: Op<248, (outs ID:$label), (ins), "$label = OpLabel">;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 915db6824d7c6..ac02283079fae 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3644,6 +3644,13 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
}
return MIB.constrainAllUses(TII, TRI, RBI);
}
+ case Intrinsic::spv_loop_control_intel: {
+ auto MIB =
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
+ for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i)
+ MIB.addImm(foldImm(I.getOperand(i), MRI));
+ return MIB.constrainAllUses(TII, TRI, RBI);
+ }
case Intrinsic::spv_selection_merge: {
auto MIB =
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge));
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 69195500502ca..d6cffa7c3970e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2331,6 +2331,11 @@ void addInstrRequirements(const MachineInstr &MI,
Reqs.addCapability(SPIRV::Capability::DerivativeControl);
break;
}
+ case SPIRV::OpLoopControlINTEL: {
+ Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
+ Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
+ break;
+ }
default:
break;
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 6f50f6a6421e1..56035cccca99d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -622,6 +622,7 @@ defm BFloat16CooperativeMatrixKHR : CapabilityOperand<5118, 0, 0, [SPV_KHR_bfloa
defm BlockingPipesALTERA : CapabilityOperand<5945, 0, 0, [SPV_ALTERA_blocking_pipes], []>;
defm ArbitraryPrecisionFixedPointALTERA : CapabilityOperand<5922, 0, 0, [SPV_ALTERA_arbitrary_precision_fixed_point], []>;
defm ArbitraryPrecisionFloatingPointALTERA : CapabilityOperand<5845, 0, 0,[SPV_ALTERA_arbitrary_precision_floating_point], []>;
+defm UnstructuredLoopControlsINTEL : CapabilityOperand<5886, 0, 0, [SPV_INTEL_unstructured_loop_controls], []>;
//===----------------------------------------------------------------------===//
// Multiclass used to define SourceLanguage enum values and at the same time
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 9c0473e69e076..9147611de495d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -986,25 +986,31 @@ createContinuedInstructions(MachineIRBuilder &MIRBuilder, unsigned Opcode,
return Instructions;
}
-SmallVector<unsigned, 1> getSpirvLoopControlOperandsFromLoopMetadata(Loop *L) {
+SmallVector<unsigned, 1>
+getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD) {
unsigned LC = SPIRV::LoopControl::None;
// Currently used only to store PartialCount value. Later when other
// LoopControls are added - this map should be sorted before making
// them loop_merge operands to satisfy 3.23. Loop Control requirements.
std::vector<std::pair<unsigned, unsigned>> MaskToValueMap;
- if (getBooleanLoopAttribute(L, "llvm.loop.unroll.disable")) {
+ if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.disable")) {
LC |= SPIRV::LoopControl::DontUnroll;
} else {
- if (getBooleanLoopAttribute(L, "llvm.loop.unroll.enable") ||
- getBooleanLoopAttribute(L, "llvm.loop.unroll.full")) {
+ if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.enable") ||
+ findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.full")) {
LC |= SPIRV::LoopControl::Unroll;
}
- std::optional<int> Count =
- getOptionalIntLoopAttribute(L, "llvm.loop.unroll.count");
- if (Count && Count != 1) {
- LC |= SPIRV::LoopControl::PartialCount;
- MaskToValueMap.emplace_back(
- std::make_pair(SPIRV::LoopControl::PartialCount, *Count));
+ if (MDNode *CountMD =
+ findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.count")) {
+ if (auto *CI =
+ mdconst::extract_or_null<ConstantInt>(CountMD->getOperand(1))) {
+ unsigned Count = CI->getZExtValue();
+ if (Count != 1) {
+ LC |= SPIRV::LoopControl::PartialCount;
+ MaskToValueMap.emplace_back(
+ std::make_pair(SPIRV::LoopControl::PartialCount, Count));
+ }
+ }
}
}
SmallVector<unsigned, 1> Result = {LC};
@@ -1013,6 +1019,10 @@ SmallVector<unsigned, 1> getSpirvLoopControlOperandsFromLoopMetadata(Loop *L) {
return Result;
}
+SmallVector<unsigned, 1> getSpirvLoopControlOperandsFromLoopMetadata(Loop *L) {
+ return getSpirvLoopControlOperandsFromLoopMetadata(L->getLoopID());
+}
+
const std::set<unsigned> &getTypeFoldingSupportedOpcodes() {
// clang-format off
static const std::set<unsigned> TypeFoldingSupportingOpcs = {
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 33e28627bcf89..50042c90a86d3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -571,6 +571,8 @@ bool isTypeFoldingSupported(unsigned Opcode);
// Get loop controls from llvm.loop. metadata.
SmallVector<unsigned, 1> getSpirvLoopControlOperandsFromLoopMetadata(Loop *L);
+SmallVector<unsigned, 1>
+getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD);
// Traversing [g]MIR accounting for pseudo-instructions.
MachineInstr *passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI);
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
new file mode 100644
index 0000000000000..64e9d85f5bd60
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
@@ -0,0 +1,103 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_unstructured_loop_controls %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXT
+
+; Check that extension and capability are emitted when extension is enabled
+; CHECK-SPIRV-DAG: OpCapability UnstructuredLoopControlsINTEL
+; CHECK-SPIRV-DAG: OpExtension "SPV_INTEL_unstructured_loop_controls"
+
+; Check that OpLoopControlINTEL is NOT emitted when extension is not enabled
+; CHECK-NO-EXT-NOT: OpLoopControlINTEL
+
+; Test 1: llvm.loop.unroll.enable -> OpLoopControlINTEL Unroll
+; CHECK-SPIRV: test_unroll_enable
+; CHECK-SPIRV: OpLoopControlINTEL Unroll
+; CHECK-SPIRV-NEXT: OpBranchConditional
+
+define spir_kernel void @test_unroll_enable(ptr addrspace(1) %dst) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %ptr = getelementptr inbounds i32, ptr addrspace(1) %dst, i32 %i
+ store i32 %i, ptr addrspace(1) %ptr, align 4
+ %inc = add nuw nsw i32 %i, 1
+ %cmp = icmp ult i32 %inc, 10
+ br i1 %cmp, label %for.body, label %for.end, !llvm.loop !0
+
+for.end:
+ ret void
+}
+
+; Test 2: llvm.loop.unroll.disable -> OpLoopControlINTEL DontUnroll
+; CHECK-SPIRV: test_unroll_disable
+; CHECK-SPIRV: OpLoopControlINTEL DontUnroll
+; CHECK-SPIRV-NEXT: OpBranchConditional
+
+define spir_kernel void @test_unroll_disable(ptr addrspace(1) %dst) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %ptr = getelementptr inbounds i32, ptr addrspace(1) %dst, i32 %i
+ store i32 %i, ptr addrspace(1) %ptr, align 4
+ %inc = add nuw nsw i32 %i, 1
+ %cmp = icmp ult i32 %inc, 10
+ br i1 %cmp, label %for.body, label %for.end, !llvm.loop !1
+
+for.end:
+ ret void
+}
+
+; Test 3: llvm.loop.unroll.count N -> OpLoopControlINTEL PartialCount N
+; CHECK-SPIRV: test_unroll_count
+; CHECK-SPIRV: OpLoopControlINTEL PartialCount 4
+; CHECK-SPIRV-NEXT: OpBranchConditional
+
+define spir_kernel void @test_unroll_count(ptr addrspace(1) %dst) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %ptr = getelementptr inbounds i32, ptr addrspace(1) %dst, i32 %i
+ store i32 %i, ptr addrspace(1) %ptr, align 4
+ %inc = add nuw nsw i32 %i, 1
+ %cmp = icmp ult i32 %inc, 10
+ br i1 %cmp, label %for.body, label %for.end, !llvm.loop !2
+
+for.end:
+ ret void
+}
+
+; Test 4: llvm.loop.unroll.full -> OpLoopControlINTEL Unroll
+; CHECK-SPIRV: test_unroll_full
+; CHECK-SPIRV: OpLoopControlINTEL Unroll
+; CHECK-SPIRV-NEXT: OpBranchConditional
+
+define spir_kernel void @test_unroll_full(ptr addrspace(1) %dst) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %ptr = getelementptr inbounds i32, ptr addrspace(1) %dst, i32 %i
+ store i32 %i, ptr addrspace(1) %ptr, align 4
+ %inc = add nuw nsw i32 %i, 1
+ %cmp = icmp ult i32 %inc, 10
+ br i1 %cmp, label %for.body, label %for.end, !llvm.loop !3
+
+for.end:
+ ret void
+}
+
+!0 = distinct !{!0, !4}
+!1 = distinct !{!1, !5}
+!2 = distinct !{!2, !6}
+!3 = distinct !{!3, !7}
+
+!4 = !{!"llvm.loop.unroll.enable"}
+!5 = !{!"llvm.loop.unroll.disable"}
+!6 = !{!"llvm.loop.unroll.count", i32 4}
+!7 = !{!"llvm.loop.unroll.full"}
>From bed74c89f4ef52594706f4ef56c385819af00418 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 30 Jan 2026 19:19:56 +0100
Subject: [PATCH 2/4] comments
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index c6b46be2eb3f9..bf6d1d7a7328c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2905,10 +2905,10 @@ void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &F,
// Emit intrinsic: loop control mask + optional parameters.
B.SetInsertPoint(Term);
SmallVector<Value *, 4> IntrArgs;
- IntrArgs.push_back(ConstantInt::get(B.getInt32Ty(), LC));
+ IntrArgs.push_back(B.getInt32(LC));
for (unsigned I = 1; I < Ops.size(); ++I)
- IntrArgs.push_back(ConstantInt::get(B.getInt32Ty(), Ops[I]));
- B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, {}, IntrArgs);
+ IntrArgs.push_back(B.getInt32(Ops[I]));
+ B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
}
}
>From 0948b8b7fc25c8d5bac85739e3e2749fef49cb93 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 30 Jan 2026 20:57:28 +0100
Subject: [PATCH 3/4] address comments
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 4 ++--
.../loop-unroll.ll | 12 ++++++------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index ac02283079fae..20972d9325473 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3647,8 +3647,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
case Intrinsic::spv_loop_control_intel: {
auto MIB =
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
- for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i)
- MIB.addImm(foldImm(I.getOperand(i), MRI));
+ for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
+ MIB.addImm(foldImm(I.getOperand(J), MRI));
return MIB.constrainAllUses(TII, TRI, RBI);
}
case Intrinsic::spv_selection_merge: {
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
index 64e9d85f5bd60..557ce3610cca0 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
@@ -1,14 +1,14 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_unstructured_loop_controls %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXT
-; Check that extension and capability are emitted when extension is enabled
+; Check that extension and capability are emitted when extension is enabled.
; CHECK-SPIRV-DAG: OpCapability UnstructuredLoopControlsINTEL
; CHECK-SPIRV-DAG: OpExtension "SPV_INTEL_unstructured_loop_controls"
-; Check that OpLoopControlINTEL is NOT emitted when extension is not enabled
+; Check that OpLoopControlINTEL is NOT emitted when extension is not enabled.
; CHECK-NO-EXT-NOT: OpLoopControlINTEL
-; Test 1: llvm.loop.unroll.enable -> OpLoopControlINTEL Unroll
+; Test 1: llvm.loop.unroll.enable -> OpLoopControlINTEL Unroll.
; CHECK-SPIRV: test_unroll_enable
; CHECK-SPIRV: OpLoopControlINTEL Unroll
; CHECK-SPIRV-NEXT: OpBranchConditional
@@ -29,7 +29,7 @@ for.end:
ret void
}
-; Test 2: llvm.loop.unroll.disable -> OpLoopControlINTEL DontUnroll
+; Test 2: llvm.loop.unroll.disable -> OpLoopControlINTEL DontUnroll.
; CHECK-SPIRV: test_unroll_disable
; CHECK-SPIRV: OpLoopControlINTEL DontUnroll
; CHECK-SPIRV-NEXT: OpBranchConditional
@@ -50,7 +50,7 @@ for.end:
ret void
}
-; Test 3: llvm.loop.unroll.count N -> OpLoopControlINTEL PartialCount N
+; Test 3: llvm.loop.unroll.count N -> OpLoopControlINTEL PartialCount N.
; CHECK-SPIRV: test_unroll_count
; CHECK-SPIRV: OpLoopControlINTEL PartialCount 4
; CHECK-SPIRV-NEXT: OpBranchConditional
@@ -71,7 +71,7 @@ for.end:
ret void
}
-; Test 4: llvm.loop.unroll.full -> OpLoopControlINTEL Unroll
+; Test 4: llvm.loop.unroll.full -> OpLoopControlINTEL Unroll.
; CHECK-SPIRV: test_unroll_full
; CHECK-SPIRV: OpLoopControlINTEL Unroll
; CHECK-SPIRV-NEXT: OpBranchConditional
>From fe0c282745ea7d6bc01050189c1bae985550b4b4 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Mon, 2 Feb 2026 05:26:18 -0600
Subject: [PATCH 4/4] add spirv-val
---
.../SPV_INTEL_unstructured_loop_controls/loop-unroll.ll | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
index 557ce3610cca0..b3aed5b4f2339 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_unstructured_loop_controls/loop-unroll.ll
@@ -1,5 +1,6 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_unstructured_loop_controls %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXT
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_unstructured_loop_controls %s -o - -filetype=obj | spirv-val %}
; Check that extension and capability are emitted when extension is enabled.
; CHECK-SPIRV-DAG: OpCapability UnstructuredLoopControlsINTEL
More information about the llvm-commits
mailing list