diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp index ea82be35e..7c21e0dfe 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( diff --git a/test/OpLoopMerge_loopMerge.ll b/test/OpLoopMerge_loopMerge.ll new file mode 100644 index 000000000..993bd3a26 --- /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-NEXT: BranchConditional \ No newline at end of file diff --git a/test/loopMerge.bc b/test/loopMerge.bc new file mode 100644 index 000000000..5d38ccd87 Binary files /dev/null and b/test/loopMerge.bc differ