spirv-opt: Clone decorations when unrolling loops (#6373)
When unrolling a loop, the instructions in the body of the loop are
cloned.
If an instruction has a decoration, the decoration must be cloned and
applied to the new instruction.
This change ensures that the decorations are cloned.
Fixes #5902
diff --git a/source/opt/loop_unroller.cpp b/source/opt/loop_unroller.cpp
index 468b2ae..8765b16 100644
--- a/source/opt/loop_unroller.cpp
+++ b/source/opt/loop_unroller.cpp
@@ -938,6 +938,11 @@
inst.SetResultId(new_id);
def_use_mgr->AnalyzeInstDef(&inst);
+ // All decorations that can apply to an instruction in a function body
+ // modify the behaviour of the instruction, and should be on the
+ // new instruction to keep the same results.
+ context_->get_decoration_mgr()->CloneDecorations(old_id, new_id);
+
// Save the mapping of old_id -> new_id.
state_.new_inst[old_id] = inst.result_id();
// Check if this instruction is the induction variable.
diff --git a/test/opt/loop_optimizations/unroll_simple.cpp b/test/opt/loop_optimizations/unroll_simple.cpp
index 6214902..256b487 100644
--- a/test/opt/loop_optimizations/unroll_simple.cpp
+++ b/test/opt/loop_optimizations/unroll_simple.cpp
@@ -3864,6 +3864,81 @@
SinglePassRunAndCheck<LoopUnroller>(text, text, false);
}
+TEST_F(PassClassTest, ApplyDecorationsToClonedInstructions) {
+ const std::string text = R"(
+ ; CHECK: OpDecorate [[ld1:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[mul1:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[add1:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[ld2:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[mul2:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[add2:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[ld3:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[mul3:%\w+]] RelaxedPrecision
+ ; CHECK: OpDecorate [[add3:%\w+]] RelaxedPrecision
+
+; CHECK: [[ld1]] = OpLoad %float
+; CHECK: [[mul1]] = OpFMul %float
+; CHECK: [[add1]] = OpFAdd %float
+; CHECK: [[ld2]] = OpLoad %float
+; CHECK: [[mul2]] = OpFMul %float
+; CHECK: [[add2]] = OpFAdd %float
+; CHECK: [[ld3]] = OpLoad %float
+; CHECK: [[mul3]] = OpFMul %float
+; CHECK: [[add3]] = OpFAdd %float
+
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %1 "main" %2
+ OpExecutionMode %1 LocalSize 1 1 1
+ OpDecorate %2 DescriptorSet 0
+ OpDecorate %2 Binding 0
+ OpDecorate %_runtimearr_float ArrayStride 4
+ OpMemberDecorate %_struct_4 0 Offset 0
+ OpDecorate %_struct_4 Block
+ OpDecorate %5 RelaxedPrecision
+ OpDecorate %6 RelaxedPrecision
+ OpDecorate %7 RelaxedPrecision
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %int_3 = OpConstant %int 3
+ %int_1 = OpConstant %int 1
+ %float = OpTypeFloat 32
+%_runtimearr_float = OpTypeRuntimeArray %float
+ %_struct_4 = OpTypeStruct %_runtimearr_float
+%_ptr_StorageBuffer__struct_4 = OpTypePointer StorageBuffer %_struct_4
+ %uint = OpTypeInt 32 0
+ %void = OpTypeVoid
+ %16 = OpTypeFunction %void
+ %bool = OpTypeBool
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+ %2 = OpVariable %_ptr_StorageBuffer__struct_4 StorageBuffer
+ %1 = OpFunction %void None %16
+ %19 = OpLabel
+ OpBranch %20
+ %20 = OpLabel
+ %21 = OpPhi %int %int_0 %19 %22 %23
+ %24 = OpSLessThan %bool %21 %int_3
+ OpLoopMerge %25 %23 Unroll
+ OpBranchConditional %24 %26 %25
+ %26 = OpLabel
+ %27 = OpBitcast %uint %21
+ %28 = OpAccessChain %_ptr_StorageBuffer_float %2 %int_0 %27
+ %5 = OpLoad %float %28
+ %6 = OpFMul %float %5 %5
+ %7 = OpFAdd %float %5 %6
+ OpStore %28 %7
+ OpBranch %23
+ %23 = OpLabel
+ %22 = OpIAdd %int %21 %int_1
+ OpBranch %20
+ %25 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+ SetTargetEnv(SPV_ENV_UNIVERSAL_1_6);
+ SinglePassRunAndMatch<LoopUnroller>(text, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools