Properly mark IR changed if instruction folder creates more than one constant. (#3799)
In #3636, I missed that the instruction folder may create more than a
single constant per call. Since CCP was only checking whether one
constant had been created after folding, it was wrongly thinking that
the IR had not changed.
Fixes #3738.
diff --git a/source/opt/ccp_pass.cpp b/source/opt/ccp_pass.cpp
index b007f24..2d19bcb 100644
--- a/source/opt/ccp_pass.cpp
+++ b/source/opt/ccp_pass.cpp
@@ -150,7 +150,7 @@
// that CCP has modified the IR, independently of whether the constant is
// actually propagated. See
// https://github.com/KhronosGroup/SPIRV-Tools/issues/3636 for details.
- if (folded_inst->result_id() == next_id) created_new_constant_ = true;
+ if (folded_inst->result_id() >= next_id) created_new_constant_ = true;
return SSAPropagator::kInteresting;
}
diff --git a/test/opt/ccp_test.cpp b/test/opt/ccp_test.cpp
index f74fb47..943bc6c 100644
--- a/test/opt/ccp_test.cpp
+++ b/test/opt/ccp_test.cpp
@@ -1105,6 +1105,59 @@
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
}
+// Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3738
+// Similar to the previous one but more than one constant is generated in a
+// single call to the instruction folder.
+TEST_F(CCPTest, CCPNoChangeFailureSeveralConstantsDuringFolding) {
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "main"
+ OpExecutionMode %2 OriginUpperLeft
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %bool = OpTypeBool
+ %v3bool = OpTypeVector %bool 3
+ %float_0 = OpConstant %float 0
+ %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+%float_0_300000012 = OpConstant %float 0.300000012
+ %14 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
+
+; CCP is generating several constants during a single instruction evaluation.
+; When folding %19, it generates the constants %true and %24. They are dead
+; because they cannot be replaced anywhere in the IR. CCP was wrongly
+; considering the IR to be unmodified because of this.
+;
+; CHECK: %true = OpConstantTrue %bool
+; CHECK: %24 = OpConstantComposite %v3bool %true %true %true
+; CHECK: %float_1 = OpConstant %float 1
+; CHECK: %float_0_699999988 = OpConstant %float 0.699999988
+
+ %2 = OpFunction %void None %4
+ %15 = OpLabel
+ OpBranch %16
+ %16 = OpLabel
+ %17 = OpPhi %v3float %12 %15 %14 %18
+ %19 = OpFOrdLessThan %v3bool %17 %14
+ %20 = OpAll %bool %19
+ OpLoopMerge %21 %18 None
+ OpBranchConditional %20 %18 %21
+ %18 = OpLabel
+ OpBranch %16
+ %21 = OpLabel
+ %22 = OpExtInst %v3float %1 FMix %12 %17 %14
+ OpReturn
+ OpFunctionEnd
+)";
+
+ auto result = SinglePassRunAndMatch<CCPPass>(text, true);
+ EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
} // namespace
} // namespace opt
} // namespace spvtools