spirv-fuzz: Handle dead blocks in TransformationEquationInstruction (#3933)
Fixes #3926.
diff --git a/source/fuzz/transformation_equation_instruction.cpp b/source/fuzz/transformation_equation_instruction.cpp
index 173b0d4..32e8351 100644
--- a/source/fuzz/transformation_equation_instruction.cpp
+++ b/source/fuzz/transformation_equation_instruction.cpp
@@ -50,8 +50,8 @@
if (!insert_before) {
return false;
}
- // The input ids must all exist, not be OpUndef, and be available before this
- // instruction.
+ // The input ids must all exist, not be OpUndef, not be irrelevant, and be
+ // available before this instruction.
for (auto id : message_.in_operand_id()) {
auto inst = ir_context->get_def_use_mgr()->GetDef(id);
if (!inst) {
@@ -92,8 +92,13 @@
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
- transformation_context->GetFactManager()->AddFactIdEquation(
- message_.fresh_id(), static_cast<SpvOp>(message_.opcode()), rhs_id);
+ // Add an equation fact as long as the result id is not irrelevant (it could
+ // be if we are inserting into a dead block).
+ if (!transformation_context->GetFactManager()->IdIsIrrelevant(
+ message_.fresh_id())) {
+ transformation_context->GetFactManager()->AddFactIdEquation(
+ message_.fresh_id(), static_cast<SpvOp>(message_.opcode()), rhs_id);
+ }
}
protobufs::Transformation TransformationEquationInstruction::ToMessage() const {
diff --git a/test/fuzz/transformation_equation_instruction_test.cpp b/test/fuzz/transformation_equation_instruction_test.cpp
index e937588..654fffc 100644
--- a/test/fuzz/transformation_equation_instruction_test.cpp
+++ b/test/fuzz/transformation_equation_instruction_test.cpp
@@ -1618,6 +1618,63 @@
transformation.IsApplicable(context.get(), transformation_context));
}
+TEST(TransformationEquationInstructionTest, HandlesDeadBlock) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %12 "main"
+ OpExecutionMode %12 OriginUpperLeft
+ OpSource ESSL 310
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %30 = OpTypeVector %6 3
+ %15 = OpConstant %6 24
+ %16 = OpConstant %6 37
+ %31 = OpConstantComposite %30 %15 %16 %15
+ %33 = OpTypeBool
+ %32 = OpConstantTrue %33
+ %12 = OpFunction %2 None %3
+ %13 = OpLabel
+ OpSelectionMerge %40 None
+ OpBranchConditional %32 %40 %41
+ %41 = OpLabel
+ OpBranch %40
+ %40 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ spvtools::ValidatorOptions validator_options;
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+
+ transformation_context.GetFactManager()->AddFactBlockIsDead(41);
+
+ TransformationEquationInstruction transformation1(
+ 14, SpvOpIAdd, {15, 16},
+ MakeInstructionDescriptor(13, SpvOpSelectionMerge, 0));
+ // No synonym is created since block is dead.
+ TransformationEquationInstruction transformation2(
+ 100, SpvOpISub, {14, 16}, MakeInstructionDescriptor(41, SpvOpBranch, 0));
+ ASSERT_TRUE(
+ transformation1.IsApplicable(context.get(), transformation_context));
+ ApplyAndCheckFreshIds(transformation1, context.get(),
+ &transformation_context);
+ ASSERT_TRUE(
+ transformation2.IsApplicable(context.get(), transformation_context));
+ ApplyAndCheckFreshIds(transformation2, context.get(),
+ &transformation_context);
+ ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+ MakeDataDescriptor(100, {}), MakeDataDescriptor(15, {})));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools