spirv-fuzz: Respect control flow rules when merging returns (#4279)
Fixes #4278.
Some minor code cleanup is incorporated.
diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.cpp b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
index 70fa820..ee82eca 100644
--- a/source/fuzz/fuzzer_pass_merge_function_returns.cpp
+++ b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
@@ -172,8 +172,9 @@
}
// Get the ids needed by the transformation.
- uint32_t outer_header_id = GetFuzzerContext()->GetFreshId();
- uint32_t outer_return_id = GetFuzzerContext()->GetFreshId();
+ const uint32_t outer_header_id = GetFuzzerContext()->GetFreshId();
+ const uint32_t unreachable_continue_id = GetFuzzerContext()->GetFreshId();
+ const uint32_t outer_return_id = GetFuzzerContext()->GetFreshId();
bool function_is_void =
GetIRContext()->get_type_mgr()->GetType(function->type_id())->AsVoid();
@@ -209,8 +210,8 @@
// Apply the transformation if it is applicable (it could be inapplicable if
// adding new predecessors to merge blocks breaks dominance rules).
MaybeApplyTransformation(TransformationMergeFunctionReturns(
- function->result_id(), outer_header_id, outer_return_id, return_val_id,
- returnable_val_id, merge_blocks_info));
+ function->result_id(), outer_header_id, unreachable_continue_id,
+ outer_return_id, return_val_id, returnable_val_id, merge_blocks_info));
}
}
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
index 2ca03db..eadf824 100644
--- a/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -1634,6 +1634,9 @@
// A fresh id for the header of the new outer loop.
uint32 outer_header_id = 2;
+ // A fresh id for an unreachable continue construct for the new outer loop.
+ uint32 unreachable_continue_id = 7;
+
// A fresh id for the new return block of the function,
// i.e. the merge block of the new outer loop.
uint32 outer_return_id = 3;
diff --git a/source/fuzz/transformation_merge_function_returns.cpp b/source/fuzz/transformation_merge_function_returns.cpp
index 1aefedc..022e1b6 100644
--- a/source/fuzz/transformation_merge_function_returns.cpp
+++ b/source/fuzz/transformation_merge_function_returns.cpp
@@ -25,11 +25,13 @@
: message_(std::move(message)) {}
TransformationMergeFunctionReturns::TransformationMergeFunctionReturns(
- uint32_t function_id, uint32_t outer_header_id, uint32_t outer_return_id,
+ uint32_t function_id, uint32_t outer_header_id,
+ uint32_t unreachable_continue_id, uint32_t outer_return_id,
uint32_t return_val_id, uint32_t any_returnable_val_id,
const std::vector<protobufs::ReturnMergingInfo>& returns_merging_info) {
message_.set_function_id(function_id);
message_.set_outer_header_id(outer_header_id);
+ message_.set_unreachable_continue_id(unreachable_continue_id);
message_.set_outer_return_id(outer_return_id);
message_.set_return_val_id(return_val_id);
message_.set_any_returnable_val_id(any_returnable_val_id);
@@ -66,7 +68,9 @@
// Check that the fresh ids provided are fresh and distinct.
std::set<uint32_t> used_fresh_ids;
- for (uint32_t id : {message_.outer_header_id(), message_.outer_return_id()}) {
+ for (uint32_t id :
+ {message_.outer_header_id(), message_.unreachable_continue_id(),
+ message_.outer_return_id()}) {
if (!id || !CheckIdIsFreshAndNotUsedByThisTransformation(id, ir_context,
&used_fresh_ids)) {
return false;
@@ -499,25 +503,20 @@
fuzzerutil::UpdateModuleIdBound(ir_context, message_.outer_header_id());
- // Add the instruction: OpLoopMerge %outer_return_id %outer_header_id None
- // The header is the continue block of the outer loop.
+ // Add the instruction:
+ // OpLoopMerge %outer_return_id %unreachable_continue_id None
outer_loop_header->AddInstruction(MakeUnique<opt::Instruction>(
ir_context, SpvOpLoopMerge, 0, 0,
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {message_.outer_return_id()}},
- {SPV_OPERAND_TYPE_ID, {message_.outer_header_id()}},
+ {SPV_OPERAND_TYPE_ID, {message_.unreachable_continue_id()}},
{SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}}));
- // Add conditional branch:
- // OpBranchConditional %true %block_after_entry %outer_header_id
- // This will always branch to %block_after_entry, but it also creates a back
- // edge for the loop (which is never traversed).
+ // Add unconditional branch to %block_after_entry.
outer_loop_header->AddInstruction(MakeUnique<opt::Instruction>(
- ir_context, SpvOpBranchConditional, 0, 0,
+ ir_context, SpvOpBranch, 0, 0,
opt::Instruction::OperandList{
- {SPV_OPERAND_TYPE_ID, {constant_true}},
- {SPV_OPERAND_TYPE_ID, {block_after_entry}},
- {SPV_OPERAND_TYPE_ID, {message_.outer_header_id()}}}));
+ {SPV_OPERAND_TYPE_ID, {block_after_entry}}}));
// Insert the header right after the entry block.
function->InsertBasicBlockAfter(std::move(outer_loop_header),
@@ -581,6 +580,24 @@
// Insert the new return block at the end of the function.
function->AddBasicBlock(std::move(outer_return_block));
+ // Create the unreachable continue block associated with the enclosing loop.
+ auto unreachable_continue_block =
+ MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
+ ir_context, SpvOpLabel, 0, message_.unreachable_continue_id(),
+ opt::Instruction::OperandList()));
+
+ fuzzerutil::UpdateModuleIdBound(ir_context,
+ message_.unreachable_continue_id());
+
+ // Insert an branch back to the loop header, to create a back edge.
+ unreachable_continue_block->AddInstruction(MakeUnique<opt::Instruction>(
+ ir_context, SpvOpBranch, 0, 0,
+ opt::Instruction::OperandList{
+ {SPV_OPERAND_TYPE_ID, {message_.outer_header_id()}}}));
+
+ // Insert the unreachable continue block at the end of the function.
+ function->AddBasicBlock(std::move(unreachable_continue_block));
+
// All analyses must be invalidated because the structure of the module was
// changed.
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
@@ -590,13 +607,14 @@
const {
std::unordered_set<uint32_t> result;
result.emplace(message_.outer_header_id());
+ result.emplace(message_.unreachable_continue_id());
result.emplace(message_.outer_return_id());
// |message_.return_val_info| can be 0 if the function is void.
if (message_.return_val_id()) {
result.emplace(message_.return_val_id());
}
- for (auto merging_info : message_.return_merging_info()) {
+ for (const auto& merging_info : message_.return_merging_info()) {
result.emplace(merging_info.is_returning_id());
// |maybe_return_val_id| can be 0 if the function is void.
if (merging_info.maybe_return_val_id()) {
diff --git a/source/fuzz/transformation_merge_function_returns.h b/source/fuzz/transformation_merge_function_returns.h
index 8f0937c..b3208ac 100644
--- a/source/fuzz/transformation_merge_function_returns.h
+++ b/source/fuzz/transformation_merge_function_returns.h
@@ -25,7 +25,8 @@
protobufs::TransformationMergeFunctionReturns message);
TransformationMergeFunctionReturns(
- uint32_t function_id, uint32_t outer_header_id, uint32_t outer_return_id,
+ uint32_t function_id, uint32_t outer_header_id,
+ uint32_t unreachable_continue_id, uint32_t outer_return_id,
uint32_t return_val_id, uint32_t any_returnable_val_id,
const std::vector<protobufs::ReturnMergingInfo>& returns_merging_info);
@@ -40,7 +41,7 @@
// statements, this id will be ignored.
// - Merge blocks of reachable loops that contain return statements only
// consist of OpLabel, OpPhi or OpBranch instructions.
- // - The model contains OpConstantTrue and OpConstantFalse instructions.
+ // - The module contains OpConstantTrue and OpConstantFalse instructions.
// - For all merge blocks of reachable loops that contain return statements,
// either:
// - a mapping is provided in |message_.return_merging_info|, all of the
diff --git a/test/fuzz/transformation_merge_function_returns_test.cpp b/test/fuzz/transformation_merge_function_returns_test.cpp
index e60d345..400d49a 100644
--- a/test/fuzz/transformation_merge_function_returns_test.cpp
+++ b/test/fuzz/transformation_merge_function_returns_test.cpp
@@ -147,12 +147,12 @@
MakeUnique<FactManager>(context.get()), validator_options);
// Function %1 does not exist.
- ASSERT_FALSE(TransformationMergeFunctionReturns(1, 100, 101, 0, 0, {{}})
+ ASSERT_FALSE(TransformationMergeFunctionReturns(1, 100, 200, 101, 0, 0, {{}})
.IsApplicable(context.get(), transformation_context));
// The entry block (%22) of function %15 does not branch unconditionally to
// the following block.
- ASSERT_FALSE(TransformationMergeFunctionReturns(16, 100, 101, 0, 0, {{}})
+ ASSERT_FALSE(TransformationMergeFunctionReturns(16, 100, 200, 101, 0, 0, {{}})
.IsApplicable(context.get(), transformation_context));
// Block %28 is the merge block of a loop containing a return instruction, but
@@ -160,7 +160,7 @@
// not OpLabel, OpPhi or OpBranch).
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 18, 100, 101, 0, 0, {{MakeReturnMergingInfo(29, 102, 0, {{}})}})
+ 18, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(29, 102, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// Block %34 is the merge block of a loop containing a return instruction, but
@@ -168,21 +168,24 @@
// that are not OpLabel, OpPhi or OpBranch).
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 20, 100, 101, 0, 0, {{MakeReturnMergingInfo(35, 102, 0, {{}})}})
+ 20, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(35, 102, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// Id %1000 cannot be found in the module and there is no id of the correct
// type (float) available at the end of the entry block of function %21.
- ASSERT_FALSE(TransformationMergeFunctionReturns(22, 100, 101, 102, 1000, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(22, 100, 200, 101, 102, 1000, {{}})
+ .IsApplicable(context.get(), transformation_context));
// Id %47 is of type float, while function %45 has return type int.
- ASSERT_FALSE(TransformationMergeFunctionReturns(45, 100, 101, 102, 47, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(45, 100, 200, 101, 102, 47, {{}})
+ .IsApplicable(context.get(), transformation_context));
// Id %50 is not available at the end of the entry block of function %45.
- ASSERT_FALSE(TransformationMergeFunctionReturns(45, 100, 101, 102, 50, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(45, 100, 200, 101, 102, 50, {{}})
+ .IsApplicable(context.get(), transformation_context));
}
TEST(TransformationMergeFunctionReturnsTest, MissingBooleans) {
@@ -235,8 +238,9 @@
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
- ASSERT_FALSE(TransformationMergeFunctionReturns(3, 100, 101, 0, 0, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(3, 100, 200, 101, 0, 0, {{}})
+ .IsApplicable(context.get(), transformation_context));
}
{
// OpConstantFalse is missing.
@@ -287,8 +291,9 @@
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
- ASSERT_FALSE(TransformationMergeFunctionReturns(3, 100, 101, 0, 0, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(3, 100, 200, 101, 0, 0, {{}})
+ .IsApplicable(context.get(), transformation_context));
}
}
@@ -386,59 +391,65 @@
// Fresh id %100 is used twice.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 17, 100, 100, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
+ 17, 100, 200, 100, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// Fresh id %100 is used twice.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 17, 100, 101, 0, 0, {{MakeReturnMergingInfo(20, 100, 0, {{}})}})
+ 17, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(20, 100, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// %0 cannot be a fresh id for the new merge block.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 17, 100, 0, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
+ 17, 100, 200, 0, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
+
+ // %0 cannot be a fresh id for the new continue block.
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(
+ 17, 100, 0, 200, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// %0 cannot be a fresh id for the new header block.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 17, 0, 100, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
+ 17, 0, 200, 100, 0, 0, {{MakeReturnMergingInfo(20, 101, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// %0 cannot be a fresh id for the new |is_returning| instruction in an
// existing merge block.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 17, 100, 101, 0, 0, {{MakeReturnMergingInfo(20, 0, 0, {{}})}})
+ 17, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(20, 0, 0, {{}})}})
.IsApplicable(context.get(), transformation_context));
// %0 cannot be a fresh id for the new |return_val| instruction in the new
// return block.
- ASSERT_FALSE(
- TransformationMergeFunctionReturns(
- 14, 100, 101, 0, 10, {{MakeReturnMergingInfo(27, 102, 103, {{}})}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(TransformationMergeFunctionReturns(
+ 14, 100, 200, 101, 0, 10,
+ {{MakeReturnMergingInfo(27, 102, 103, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
// %0 cannot be a fresh id for the new |maybe_return_val| instruction in an
// existing merge block, inside a non-void function.
- ASSERT_FALSE(
- TransformationMergeFunctionReturns(
- 14, 100, 101, 102, 10, {{MakeReturnMergingInfo(27, 103, 0, {{}})}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(TransformationMergeFunctionReturns(
+ 14, 100, 200, 101, 102, 10,
+ {{MakeReturnMergingInfo(27, 103, 0, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
// Fresh id %102 is repeated.
- ASSERT_FALSE(
- TransformationMergeFunctionReturns(
- 14, 100, 101, 102, 10, {{MakeReturnMergingInfo(27, 102, 104, {{}})}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(TransformationMergeFunctionReturns(
+ 14, 100, 200, 101, 102, 10,
+ {{MakeReturnMergingInfo(27, 102, 104, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
// Id %11 (type int) does not have the correct type (float) for OpPhi
// instruction %31.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 16, 100, 101, 0, 0,
+ 16, 100, 200, 101, 0, 0,
{{MakeReturnMergingInfo(36, 103, 104, {{{31, 11}, {32, 11}}})}})
.IsApplicable(context.get(), transformation_context));
@@ -446,21 +457,21 @@
// instruction %31.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 16, 100, 101, 0, 0,
+ 16, 100, 200, 101, 0, 0,
{{MakeReturnMergingInfo(36, 102, 0, {{{31, 11}, {32, 11}}})}})
.IsApplicable(context.get(), transformation_context));
// Id %43 is not available at the end of the entry block.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 16, 100, 101, 0, 0,
+ 16, 100, 200, 101, 0, 0,
{{MakeReturnMergingInfo(36, 102, 0, {{{31, 44}, {32, 11}}})}})
.IsApplicable(context.get(), transformation_context));
// There is not a mapping for id %31 (float OpPhi instruction in a loop merge
// block) and no suitable id is available at the end of the entry block.
ASSERT_FALSE(TransformationMergeFunctionReturns(
- 16, 100, 101, 0, 0,
+ 16, 100, 200, 101, 0, 0,
{{MakeReturnMergingInfo(36, 102, 0, {{{32, 11}}})}})
.IsApplicable(context.get(), transformation_context));
@@ -468,7 +479,7 @@
// available at the end of the entry block.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 16, 100, 101, 0, 0,
+ 16, 100, 200, 101, 0, 0,
{{MakeReturnMergingInfo(36, 102, 0, {{{31, 1000}, {32, 11}}})}})
.IsApplicable(context.get(), transformation_context));
}
@@ -560,7 +571,7 @@
// The 0s are allowed because the function's return type is void.
auto transformation1 =
- TransformationMergeFunctionReturns(14, 100, 101, 0, 0, {{}});
+ TransformationMergeFunctionReturns(14, 100, 200, 101, 0, 0, {{}});
ASSERT_TRUE(
transformation1.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation1, context.get(),
@@ -570,13 +581,14 @@
// %12 is available at the end of the entry block of %19 (it is a global
// variable).
- ASSERT_TRUE(TransformationMergeFunctionReturns(19, 110, 111, 112, 12, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ TransformationMergeFunctionReturns(19, 110, 210, 111, 112, 12, {{}})
+ .IsApplicable(context.get(), transformation_context));
// %1000 cannot be found in the module, but there is a suitable id available
// at the end of the entry block (%12).
auto transformation2 =
- TransformationMergeFunctionReturns(19, 110, 111, 112, 1000, {{}});
+ TransformationMergeFunctionReturns(19, 110, 210, 111, 112, 1000, {{}});
ASSERT_TRUE(
transformation2.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation2, context.get(),
@@ -586,13 +598,14 @@
// %27 is available at the end of the entry block of %26 (it is a function
// parameter).
- ASSERT_TRUE(TransformationMergeFunctionReturns(26, 120, 121, 122, 27, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ TransformationMergeFunctionReturns(26, 120, 220, 121, 122, 27, {{}})
+ .IsApplicable(context.get(), transformation_context));
// %1000 cannot be found in the module, but there is a suitable id available
// at the end of the entry block (%27).
auto transformation3 =
- TransformationMergeFunctionReturns(26, 120, 121, 122, 1000, {{}});
+ TransformationMergeFunctionReturns(26, 120, 220, 121, 122, 1000, {{}});
ASSERT_TRUE(
transformation3.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation3, context.get(),
@@ -602,13 +615,14 @@
// %35 is available at the end of the entry block of %33 (it is in the entry
// block).
- ASSERT_TRUE(TransformationMergeFunctionReturns(26, 130, 131, 132, 27, {{}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ TransformationMergeFunctionReturns(26, 130, 230, 131, 132, 27, {{}})
+ .IsApplicable(context.get(), transformation_context));
// %1000 cannot be found in the module, but there is a suitable id available
// at the end of the entry block (%35).
auto transformation4 =
- TransformationMergeFunctionReturns(33, 130, 131, 132, 1000, {{}});
+ TransformationMergeFunctionReturns(33, 130, 230, 131, 132, 1000, {{}});
ASSERT_TRUE(
transformation4.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation4, context.get(),
@@ -642,8 +656,8 @@
%15 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %11 %16 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %16
%16 = OpLabel
OpSelectionMerge %17 None
OpBranchConditional %11 %18 %17
@@ -653,13 +667,15 @@
OpBranch %101
%101 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
%19 = OpFunction %5 None %6
%20 = OpLabel
OpBranch %110
%110 = OpLabel
- OpLoopMerge %111 %110 None
- OpBranchConditional %11 %21 %110
+ OpLoopMerge %111 %210 None
+ OpBranch %21
%21 = OpLabel
OpSelectionMerge %22 None
OpBranchConditional %11 %23 %24
@@ -673,14 +689,16 @@
%111 = OpLabel
%112 = OpPhi %5 %12 %23 %25 %24
OpReturnValue %112
+ %210 = OpLabel
+ OpBranch %110
OpFunctionEnd
%26 = OpFunction %7 None %8
%27 = OpFunctionParameter %7
%28 = OpLabel
OpBranch %120
%120 = OpLabel
- OpLoopMerge %121 %120 None
- OpBranchConditional %11 %29 %120
+ OpLoopMerge %121 %220 None
+ OpBranch %29
%29 = OpLabel
OpSelectionMerge %30 None
OpBranchConditional %11 %31 %30
@@ -692,14 +710,16 @@
%121 = OpLabel
%122 = OpPhi %7 %27 %30 %32 %31
OpReturnValue %122
+ %220 = OpLabel
+ OpBranch %120
OpFunctionEnd
%33 = OpFunction %7 None %9
%34 = OpLabel
%35 = OpConvertSToF %7 %12
OpBranch %130
%130 = OpLabel
- OpLoopMerge %131 %130 None
- OpBranchConditional %11 %36 %130
+ OpLoopMerge %131 %230 None
+ OpBranch %36
%36 = OpLabel
OpSelectionMerge %37 None
OpBranchConditional %11 %38 %37
@@ -711,6 +731,8 @@
%131 = OpLabel
%132 = OpPhi %7 %35 %37 %39 %38
OpReturnValue %132
+ %230 = OpLabel
+ OpBranch %130
OpFunctionEnd
)";
@@ -743,8 +765,8 @@
%15 = OpLabel
OpBranch %16
%16 = OpLabel
- OpLoopMerge %17 %16 None
- OpBranchConditional %8 %18 %16
+ OpLoopMerge %17 %916 None
+ OpBranch %18
%18 = OpLabel
OpLoopMerge %19 %20 None
OpBranchConditional %8 %19 %21
@@ -767,8 +789,8 @@
%28 = OpLabel
OpBranch %29
%29 = OpLabel
- OpLoopMerge %30 %29 None
- OpBranchConditional %8 %30 %29
+ OpLoopMerge %30 %929 None
+ OpBranch %30
%30 = OpLabel
OpLoopMerge %31 %32 None
OpBranch %33
@@ -792,6 +814,10 @@
OpBranch %38
%38 = OpLabel
OpReturnValue %12
+ %916 = OpLabel
+ OpBranch %16
+ %929 = OpLabel
+ OpBranch %29
OpFunctionEnd
)";
@@ -805,7 +831,7 @@
MakeUnique<FactManager>(context.get()), validator_options);
auto transformation = TransformationMergeFunctionReturns(
- 14, 100, 101, 102, 11,
+ 14, 100, 200, 101, 102, 11,
{{MakeReturnMergingInfo(19, 103, 104, {{}}),
MakeReturnMergingInfo(17, 105, 106, {{}}),
MakeReturnMergingInfo(31, 107, 108, {{{35, 10}, {36, 12}}}),
@@ -841,11 +867,11 @@
%15 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %8 %16 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %16
%16 = OpLabel
- OpLoopMerge %17 %16 None
- OpBranchConditional %8 %18 %16
+ OpLoopMerge %17 %916 None
+ OpBranch %18
%18 = OpLabel
OpLoopMerge %19 %20 None
OpBranchConditional %8 %19 %21
@@ -872,8 +898,8 @@
%28 = OpLabel
OpBranch %29
%29 = OpLabel
- OpLoopMerge %30 %29 None
- OpBranchConditional %8 %30 %29
+ OpLoopMerge %30 %929 None
+ OpBranch %30
%30 = OpLabel
OpLoopMerge %31 %32 None
OpBranch %33
@@ -901,9 +927,15 @@
OpBranchConditional %109 %101 %38
%38 = OpLabel
OpBranch %101
+ %916 = OpLabel
+ OpBranch %16
+ %929 = OpLabel
+ OpBranch %29
%101 = OpLabel
%102 = OpPhi %5 %106 %17 %110 %23 %12 %38
OpReturnValue %102
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
)";
@@ -997,7 +1029,7 @@
// No mapping from merge block %16 to fresh ids is given, so overflow ids are
// needed.
auto transformation1 =
- TransformationMergeFunctionReturns(12, 100, 101, 102, 10, {{}});
+ TransformationMergeFunctionReturns(12, 100, 200, 101, 102, 10, {{}});
#ifndef NDEBUG
ASSERT_DEATH(
@@ -1016,7 +1048,7 @@
// No mapping from merge block %27 to fresh ids is given, so overflow ids are
// needed.
auto transformation2 =
- TransformationMergeFunctionReturns(24, 110, 111, 0, 0, {{}});
+ TransformationMergeFunctionReturns(24, 110, 210, 111, 0, 0, {{}});
#ifndef NDEBUG
ASSERT_DEATH(
@@ -1054,8 +1086,8 @@
%13 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %8 %14 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %14
%14 = OpLabel
%15 = OpIAdd %5 %10 %10
OpLoopMerge %16 %17 None
@@ -1081,13 +1113,15 @@
%101 = OpLabel
%102 = OpPhi %5 %1001 %16 %22 %23
OpReturnValue %102
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
%24 = OpFunction %3 None %4
%25 = OpLabel
OpBranch %110
%110 = OpLabel
- OpLoopMerge %111 %110 None
- OpBranchConditional %8 %26 %110
+ OpLoopMerge %111 %210 None
+ OpBranch %26
%26 = OpLabel
OpLoopMerge %27 %28 None
OpBranch %29
@@ -1110,6 +1144,8 @@
OpBranch %111
%111 = OpLabel
OpReturn
+ %210 = OpLabel
+ OpBranch %110
OpFunctionEnd
)";
@@ -1179,7 +1215,7 @@
// corresponding mapping.
auto transformation = TransformationMergeFunctionReturns(
- 12, 101, 102, 0, 0,
+ 12, 101, 200, 102, 0, 0,
{{MakeReturnMergingInfo(17, 103, 0, {{{25, 7}, {35, 8}}})}});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
@@ -1212,8 +1248,8 @@
%15 = OpConvertSToF %10 %13
OpBranch %101
%101 = OpLabel
- OpLoopMerge %102 %101 None
- OpBranchConditional %6 %16 %101
+ OpLoopMerge %102 %200 None
+ OpBranch %16
%16 = OpLabel
OpLoopMerge %17 %18 None
OpBranch %19
@@ -1238,6 +1274,8 @@
OpBranch %102
%102 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %101
OpFunctionEnd
)";
@@ -1324,14 +1362,14 @@
// block %14 is added.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 2, 100, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}})
+ 2, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}})
.IsApplicable(context.get(), transformation_context));
// In function %18, The definition of id %26 will still dominate its use in
// instruction %27 (inside merge block %21), because %27 is an OpPhi
// instruction.
auto transformation = TransformationMergeFunctionReturns(
- 18, 100, 101, 0, 0, {{MakeReturnMergingInfo(21, 102, 103, {{}})}});
+ 18, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(21, 102, 103, {{}})}});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
@@ -1376,8 +1414,8 @@
%19 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %6 %20 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %20
%20 = OpLabel
OpLoopMerge %21 %22 None
OpBranch %23
@@ -1399,6 +1437,8 @@
OpBranch %101
%101 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
)";
@@ -1482,17 +1522,17 @@
// block %14 to merge block %10 is added.
ASSERT_FALSE(
TransformationMergeFunctionReturns(
- 2, 100, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}})
+ 2, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}})
.IsApplicable(context.get(), transformation_context));
// In function %18, the definition of id %26 will not dominate its use in
// instruction %28 (inside block %27) after a new branch from return
// block %25 to merge block %21 is added.
- ASSERT_FALSE(TransformationMergeFunctionReturns(
- 2, 100, 101, 0, 0,
- {{MakeReturnMergingInfo(10, 102, 0, {{}}),
- MakeReturnMergingInfo(21, 103, 0, {{}})}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(
+ TransformationMergeFunctionReturns(
+ 2, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 0, {{}}),
+ MakeReturnMergingInfo(21, 103, 0, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
}
TEST(TransformationMergeFunctionReturnsTest, RespectDominanceRules3) {
@@ -1556,7 +1596,7 @@
// fact that the id definition dominates the uses does not depend on it
// dominating the merge block.
auto transformation = TransformationMergeFunctionReturns(
- 2, 100, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}});
+ 2, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
@@ -1579,8 +1619,8 @@
%8 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %6 %9 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %9
%9 = OpLabel
OpLoopMerge %10 %11 None
OpBranch %12
@@ -1608,6 +1648,8 @@
OpBranch %101
%101 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
)";
@@ -1700,7 +1742,7 @@
// instruction %19 after the transformation is applied, because %13 dominates
// all of the return blocks.
auto transformation = TransformationMergeFunctionReturns(
- 2, 100, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}});
+ 2, 100, 200, 101, 0, 0, {{MakeReturnMergingInfo(10, 102, 103, {{}})}});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
@@ -1710,10 +1752,10 @@
// In function %20, the definition of id %28 will not dominate its use in
// instruction %32 after the transformation is applied, because %28 dominates
// only one of the return blocks.
- ASSERT_FALSE(
- TransformationMergeFunctionReturns(
- 20, 100, 101, 0, 0, {{MakeReturnMergingInfo(23, 102, 103, {{}})}})
- .IsApplicable(context.get(), transformation_context));
+ ASSERT_FALSE(TransformationMergeFunctionReturns(
+ 20, 100, 200, 101, 0, 0,
+ {{MakeReturnMergingInfo(23, 102, 103, {{}})}})
+ .IsApplicable(context.get(), transformation_context));
std::string after_transformation = R"(
OpCapability Shader
@@ -1731,8 +1773,8 @@
%8 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %6 %9 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %9
%9 = OpLabel
OpLoopMerge %10 %11 None
OpBranch %12
@@ -1759,6 +1801,8 @@
OpBranch %101
%101 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
%20 = OpFunction %3 None %4
%21 = OpLabel
@@ -1830,7 +1874,7 @@
MakeUnique<FactManager>(context.get()), validator_options);
auto transformation =
- TransformationMergeFunctionReturns(2, 100, 101, 0, 0, {});
+ TransformationMergeFunctionReturns(2, 100, 200, 101, 0, 0, {});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
@@ -1863,8 +1907,8 @@
%8 = OpLabel
OpBranch %100
%100 = OpLabel
- OpLoopMerge %101 %100 None
- OpBranchConditional %6 %9 %100
+ OpLoopMerge %101 %200 None
+ OpBranch %9
%9 = OpLabel
%10 = OpPhi %5 %6 %100
OpSelectionMerge %11 None
@@ -1875,6 +1919,8 @@
OpBranch %101
%101 = OpLabel
OpReturn
+ %200 = OpLabel
+ OpBranch %100
OpFunctionEnd
)";