From 6fe270bd3d130f772f7ea89ec94fd436c1860d42 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 23 Jul 2025 13:18:01 +0300 Subject: [PATCH 1/6] add LoopMerge test --- loopMerge.bc | Bin 0 -> 4316 bytes test/OpLoopMerge_loopMerge.ll | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 loopMerge.bc create mode 100644 test/OpLoopMerge_loopMerge.ll diff --git a/loopMerge.bc b/loopMerge.bc new file mode 100644 index 0000000000000000000000000000000000000000..5d38ccd87214dc9a8b5bd1fdf439761c2374e2c2 GIT binary patch literal 4316 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 H6QX|s&#cy; literal 0 HcmV?d00001 diff --git a/test/OpLoopMerge_loopMerge.ll b/test/OpLoopMerge_loopMerge.ll new file mode 100644 index 0000000000..a48367fcc9 --- /dev/null +++ b/test/OpLoopMerge_loopMerge.ll @@ -0,0 +1,10 @@ +; Test case for OpLoopMerge instruction placement validation. +; This test verifies that OpLoopMerge instructions are properly placed as the second-to-last +; instruction in their basic block, immediately preceding the branch instruction. + +; RUN: llvm-spirv %S/../loopMerge.bc -o %t.spv +; RUN: spirv-val %t.spv + +; RUN: llvm-spirv --to-text %t.spv -o - | FileCheck %s --check-prefix=CHECK-SPIRV-TEXT +; CHECK-SPIRV-TEXT: LoopMerge +; CHECK-SPIRV-TEXT: BranchConditional \ No newline at end of file From 6544a098947ceb29ec9a5e64ddab6a2781aa5ff8 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 23 Jul 2025 13:33:02 +0300 Subject: [PATCH 2/6] Fix LoopMerge error --- lib/SPIRV/libSPIRV/SPIRVModule.cpp | 36 ++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp index ea82be35e9..7c21e0dfe3 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -1855,10 +1855,22 @@ SPIRVInstruction *SPIRVModuleImpl::addSelectionMergeInst( SPIRVInstruction *SPIRVModuleImpl::addLoopMergeInst( SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl, std::vector LoopControlParameters, SPIRVBasicBlock *BB) { - return addInstruction( - new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, - LoopControlParameters, BB), - BB, const_cast(BB->getTerminateInstr())); + SPIRVInstruction *TermInst = const_cast(BB->getTerminateInstr()); + // OpLoopMerge must be the second-to-last instruction in the block, + // immediately preceding the branch instruction (OpBranch or OpBranchConditional) + if (TermInst && (TermInst->getOpCode() == OpBranch || + TermInst->getOpCode() == OpBranchConditional)) { + return addInstruction( + new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, + LoopControlParameters, BB), + BB, TermInst); + } else { + // If there's no proper terminator, add at the end + return addInstruction( + new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, + LoopControlParameters, BB), + BB); + } } SPIRVInstruction *SPIRVModuleImpl::addLoopControlINTELInst( @@ -1866,9 +1878,19 @@ SPIRVInstruction *SPIRVModuleImpl::addLoopControlINTELInst( SPIRVBasicBlock *BB) { addCapability(CapabilityUnstructuredLoopControlsINTEL); addExtension(ExtensionID::SPV_INTEL_unstructured_loop_controls); - return addInstruction( - new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB, - const_cast(BB->getTerminateInstr())); + SPIRVInstruction *TermInst = const_cast(BB->getTerminateInstr()); + // OpLoopControlINTEL must be the second-to-last instruction in the block, + // immediately preceding the branch instruction (OpBranch or OpBranchConditional) + if (TermInst && (TermInst->getOpCode() == OpBranch || + TermInst->getOpCode() == OpBranchConditional)) { + return addInstruction( + new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB, + TermInst); + } else { + // If there's no proper terminator, add at the end + return addInstruction( + new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB); + } } SPIRVInstruction *SPIRVModuleImpl::addFixedPointIntelInst( From 606f935932ae8adc6ac77c6342d94d811fbb2905 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 23 Jul 2025 14:01:34 +0300 Subject: [PATCH 3/6] move test files --- test/OpLoopMerge_loopMerge.ll | 2 +- loopMerge.bc => test/loopMerge.bc | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename loopMerge.bc => test/loopMerge.bc (100%) diff --git a/test/OpLoopMerge_loopMerge.ll b/test/OpLoopMerge_loopMerge.ll index a48367fcc9..efd9eccdce 100644 --- a/test/OpLoopMerge_loopMerge.ll +++ b/test/OpLoopMerge_loopMerge.ll @@ -2,7 +2,7 @@ ; This test verifies that OpLoopMerge instructions are properly placed as the second-to-last ; instruction in their basic block, immediately preceding the branch instruction. -; RUN: llvm-spirv %S/../loopMerge.bc -o %t.spv +; RUN: llvm-spirv %S/loopMerge.bc -o %t.spv ; RUN: spirv-val %t.spv ; RUN: llvm-spirv --to-text %t.spv -o - | FileCheck %s --check-prefix=CHECK-SPIRV-TEXT diff --git a/loopMerge.bc b/test/loopMerge.bc similarity index 100% rename from loopMerge.bc rename to test/loopMerge.bc From ea9c2aff933cea898b72c5ed5e58404eb4b38159 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 23 Jul 2025 17:03:16 +0300 Subject: [PATCH 4/6] MergeBlock test --- mergeBlock.bc | Bin 0 -> 4456 bytes test/OpLoopMerge_mergeBlock.ll | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 mergeBlock.bc create mode 100644 test/OpLoopMerge_mergeBlock.ll diff --git a/mergeBlock.bc b/mergeBlock.bc new file mode 100644 index 0000000000000000000000000000000000000000..64dc792804c0aaf0fa6da6487210c002482dad44 GIT binary patch literal 4456 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 R47RqE3qP-?{}5}(e*$hUL5ctX literal 0 HcmV?d00001 diff --git a/test/OpLoopMerge_mergeBlock.ll b/test/OpLoopMerge_mergeBlock.ll new file mode 100644 index 0000000000..3cf37b19b2 --- /dev/null +++ b/test/OpLoopMerge_mergeBlock.ll @@ -0,0 +1,10 @@ +; Test case for OpLoopMerge merge block assignment validation. +; This test verifies that OpLoopMerge instructions properly assign unique merge blocks +; and don't create conflicts where the same block is used as a merge block for multiple loops. + +; RUN: llvm-spirv %S/../mergeBlock.bc -o %t.spv +; RUN: spirv-val %t.spv + +; RUN: llvm-spirv --to-text %t.spv -o - | FileCheck %s --check-prefix=CHECK-SPIRV-TEXT +; CHECK-SPIRV-TEXT: LoopMerge +; CHECK-SPIRV-TEXT: BranchConditional \ No newline at end of file From 5185e4108be239b09efd82df5e4d63be874200d3 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 23 Jul 2025 17:10:08 +0300 Subject: [PATCH 5/6] fix blockMerge --- lib/SPIRV/SPIRVWriter.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index a8f25b8c27..933a7733d0 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -2453,7 +2453,11 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, Function *Fun = Branch->getFunction(); DominatorTree DomTree(*Fun); LoopInfo LI(DomTree); - for (const auto *LoopObj : LI.getLoopsInPreorder()) { + // Find the innermost loop that contains the current basic block + BasicBlock *CurrentBB = Branch->getParent(); + const Loop *ContainingLoop = LI.getLoopFor(CurrentBB); + + if (ContainingLoop) { // Check whether SuccessorFalse or SuccessorTrue is the loop header BB. // For example consider following LLVM IR: // br i1 %compare, label %for.body, label %for.end @@ -2462,12 +2466,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, // <- SuccessorTrue is 'for.end' aka successor(1) // meanwhile the true successor (by definition) should be a loop header // aka 'for.body' - if (LoopObj->getHeader() == Branch->getSuccessor(1)) + if (ContainingLoop->getHeader() == Branch->getSuccessor(1)) // SuccessorFalse is the loop header BB. BM->addLoopMergeInst(SuccessorTrue->getId(), // Merge Block BB->getId(), // Continue Target LoopControl, Parameters, SuccessorFalse); - else + else if (ContainingLoop->getHeader() == Branch->getSuccessor(0)) // SuccessorTrue is the loop header BB. BM->addLoopMergeInst(SuccessorFalse->getId(), // Merge Block BB->getId(), // Continue Target From 1a3a3c943d14840448892b081528981abb26a455 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Sun, 27 Jul 2025 11:16:54 +0300 Subject: [PATCH 6/6] move test file --- test/OpLoopMerge_mergeBlock.ll | 2 +- mergeBlock.bc => test/mergeBlock.bc | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename mergeBlock.bc => test/mergeBlock.bc (100%) diff --git a/test/OpLoopMerge_mergeBlock.ll b/test/OpLoopMerge_mergeBlock.ll index 3cf37b19b2..25299b82fb 100644 --- a/test/OpLoopMerge_mergeBlock.ll +++ b/test/OpLoopMerge_mergeBlock.ll @@ -2,7 +2,7 @@ ; This test verifies that OpLoopMerge instructions properly assign unique merge blocks ; and don't create conflicts where the same block is used as a merge block for multiple loops. -; RUN: llvm-spirv %S/../mergeBlock.bc -o %t.spv +; RUN: llvm-spirv %S/mergeBlock.bc -o %t.spv ; RUN: spirv-val %t.spv ; RUN: llvm-spirv --to-text %t.spv -o - | FileCheck %s --check-prefix=CHECK-SPIRV-TEXT diff --git a/mergeBlock.bc b/test/mergeBlock.bc similarity index 100% rename from mergeBlock.bc rename to test/mergeBlock.bc