Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Find the innermost loop that contains the current basic block
// 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
Expand All @@ -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
Expand Down
36 changes: 29 additions & 7 deletions lib/SPIRV/libSPIRV/SPIRVModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1855,20 +1855,42 @@ SPIRVInstruction *SPIRVModuleImpl::addSelectionMergeInst(
SPIRVInstruction *SPIRVModuleImpl::addLoopMergeInst(
SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl,
std::vector<SPIRVWord> LoopControlParameters, SPIRVBasicBlock *BB) {
return addInstruction(
new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl,
LoopControlParameters, BB),
BB, const_cast<SPIRVInstruction *>(BB->getTerminateInstr()));
SPIRVInstruction *TermInst = const_cast<SPIRVInstruction *>(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(
SPIRVWord LoopControl, std::vector<SPIRVWord> LoopControlParameters,
SPIRVBasicBlock *BB) {
addCapability(CapabilityUnstructuredLoopControlsINTEL);
addExtension(ExtensionID::SPV_INTEL_unstructured_loop_controls);
return addInstruction(
new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB,
const_cast<SPIRVInstruction *>(BB->getTerminateInstr()));
SPIRVInstruction *TermInst = const_cast<SPIRVInstruction *>(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(
Expand Down
10 changes: 10 additions & 0 deletions test/OpLoopMerge_loopMerge.ll
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add newline at end of file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add NEXT to verify that LoopMerge is immediately preceding?

Suggested change
; CHECK-SPIRV-TEXT: BranchConditional
; CHECK-SPIRV-TEXT-NEXT: BranchConditional

10 changes: 10 additions & 0 deletions test/OpLoopMerge_mergeBlock.ll
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add the test contents in plain text in this file and call llvm-as from here.

; 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add newline at end of file.

Binary file added test/loopMerge.bc
Copy link
Contributor

@YixingZhang007 YixingZhang007 Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these binary file should be removed from the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and the same for the other .bc file.

Binary file not shown.
Binary file added test/mergeBlock.bc
Binary file not shown.
Loading