| // Copyright (c) 2020 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "source/fuzz/fuzzer_pass_outline_functions.h" | |
| #include "gtest/gtest.h" | |
| #include "source/fuzz/fuzzer_util.h" | |
| #include "source/fuzz/pseudo_random_generator.h" | |
| #include "test/fuzz/fuzz_test_util.h" | |
| namespace spvtools { | |
| namespace fuzz { | |
| namespace { | |
| std::string shader = R"( | |
| OpCapability Shader | |
| %1 = OpExtInstImport "GLSL.std.450" | |
| OpMemoryModel Logical GLSL450 | |
| OpEntryPoint Fragment %2 "main" | |
| OpExecutionMode %2 OriginUpperLeft | |
| OpSource ESSL 310 | |
| OpName %2 "main" | |
| OpName %3 "a" | |
| OpName %4 "b" | |
| OpDecorate %3 RelaxedPrecision | |
| OpDecorate %4 RelaxedPrecision | |
| OpDecorate %5 RelaxedPrecision | |
| OpDecorate %6 RelaxedPrecision | |
| OpDecorate %7 RelaxedPrecision | |
| OpDecorate %8 RelaxedPrecision | |
| OpDecorate %9 RelaxedPrecision | |
| %10 = OpTypeVoid | |
| %11 = OpTypeFunction %10 | |
| %12 = OpTypeInt 32 1 | |
| %13 = OpTypePointer Function %12 | |
| %14 = OpConstant %12 8 | |
| %15 = OpConstant %12 23 | |
| %16 = OpTypeBool | |
| %17 = OpConstantTrue %16 | |
| %18 = OpConstant %12 0 | |
| %19 = OpConstant %12 1 | |
| %2 = OpFunction %10 None %11 | |
| %20 = OpLabel | |
| %3 = OpVariable %13 Function | |
| %4 = OpVariable %13 Function | |
| OpStore %3 %14 | |
| OpStore %4 %15 | |
| OpBranch %21 | |
| %21 = OpLabel | |
| OpLoopMerge %22 %23 None | |
| OpBranch %24 | |
| %24 = OpLabel | |
| %25 = OpPhi %12 %19 %21 %18 %26 | |
| OpLoopMerge %27 %26 None | |
| OpBranch %28 | |
| %28 = OpLabel | |
| %5 = OpLoad %12 %3 | |
| %29 = OpSGreaterThan %16 %5 %18 | |
| OpBranchConditional %29 %30 %27 | |
| %30 = OpLabel | |
| %6 = OpLoad %12 %4 | |
| %7 = OpISub %12 %6 %19 | |
| OpStore %4 %7 | |
| OpBranch %26 | |
| %26 = OpLabel | |
| %8 = OpLoad %12 %3 | |
| %9 = OpISub %12 %8 %19 | |
| OpStore %3 %9 | |
| OpBranch %24 | |
| %27 = OpLabel | |
| OpBranch %23 | |
| %23 = OpLabel | |
| OpBranch %21 | |
| %22 = OpLabel | |
| OpBranch %31 | |
| %31 = OpLabel | |
| OpLoopMerge %32 %31 None | |
| OpBranchConditional %17 %31 %32 | |
| %32 = OpLabel | |
| OpSelectionMerge %33 None | |
| OpBranchConditional %17 %34 %35 | |
| %34 = OpLabel | |
| OpBranch %33 | |
| %35 = OpLabel | |
| OpBranch %33 | |
| %33 = OpLabel | |
| %42 = OpPhi %12 %19 %33 %18 %34 %18 %35 | |
| OpLoopMerge %36 %33 None | |
| OpBranchConditional %17 %36 %33 | |
| %36 = OpLabel | |
| %43 = OpPhi %12 %18 %33 %18 %41 | |
| OpReturn | |
| %37 = OpLabel | |
| OpLoopMerge %38 %39 None | |
| OpBranch %40 | |
| %40 = OpLabel | |
| OpBranchConditional %17 %41 %38 | |
| %41 = OpLabel | |
| OpBranchConditional %17 %36 %39 | |
| %39 = OpLabel | |
| OpBranch %37 | |
| %38 = OpLabel | |
| OpReturn | |
| OpFunctionEnd | |
| )"; | |
| TEST(FuzzerPassOutlineFunctionsTest, EntryIsAlreadySuitable) { | |
| const auto env = SPV_ENV_UNIVERSAL_1_5; | |
| 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); | |
| FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100, | |
| false); | |
| protobufs::TransformationSequence transformation_sequence; | |
| FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, | |
| &fuzzer_context, | |
| &transformation_sequence, false); | |
| // Block 28 | |
| auto suitable_entry_block = | |
| fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(28)); | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 28); | |
| // Block 32 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(32)); | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 32); | |
| // Block 41 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(41)); | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 41); | |
| // The module should not have been changed. | |
| ASSERT_TRUE(IsEqual(env, shader, context.get())); | |
| } | |
| TEST(FuzzerPassOutlineFunctionsTest, EntryHasOpVariable) { | |
| const auto env = SPV_ENV_UNIVERSAL_1_5; | |
| 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); | |
| FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100, | |
| false); | |
| protobufs::TransformationSequence transformation_sequence; | |
| FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, | |
| &fuzzer_context, | |
| &transformation_sequence, false); | |
| // Block 20 | |
| auto suitable_entry_block = | |
| fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(20)); | |
| // The block should have been split, the new entry block being the block | |
| // generated by the splitting. | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 100); | |
| std::string after_adjustment = R"( | |
| OpCapability Shader | |
| %1 = OpExtInstImport "GLSL.std.450" | |
| OpMemoryModel Logical GLSL450 | |
| OpEntryPoint Fragment %2 "main" | |
| OpExecutionMode %2 OriginUpperLeft | |
| OpSource ESSL 310 | |
| OpName %2 "main" | |
| OpName %3 "a" | |
| OpName %4 "b" | |
| OpDecorate %3 RelaxedPrecision | |
| OpDecorate %4 RelaxedPrecision | |
| OpDecorate %5 RelaxedPrecision | |
| OpDecorate %6 RelaxedPrecision | |
| OpDecorate %7 RelaxedPrecision | |
| OpDecorate %8 RelaxedPrecision | |
| OpDecorate %9 RelaxedPrecision | |
| %10 = OpTypeVoid | |
| %11 = OpTypeFunction %10 | |
| %12 = OpTypeInt 32 1 | |
| %13 = OpTypePointer Function %12 | |
| %14 = OpConstant %12 8 | |
| %15 = OpConstant %12 23 | |
| %16 = OpTypeBool | |
| %17 = OpConstantTrue %16 | |
| %18 = OpConstant %12 0 | |
| %19 = OpConstant %12 1 | |
| %2 = OpFunction %10 None %11 | |
| %20 = OpLabel | |
| %3 = OpVariable %13 Function | |
| %4 = OpVariable %13 Function | |
| OpBranch %100 | |
| %100 = OpLabel | |
| OpStore %3 %14 | |
| OpStore %4 %15 | |
| OpBranch %21 | |
| %21 = OpLabel | |
| OpLoopMerge %22 %23 None | |
| OpBranch %24 | |
| %24 = OpLabel | |
| %25 = OpPhi %12 %19 %21 %18 %26 | |
| OpLoopMerge %27 %26 None | |
| OpBranch %28 | |
| %28 = OpLabel | |
| %5 = OpLoad %12 %3 | |
| %29 = OpSGreaterThan %16 %5 %18 | |
| OpBranchConditional %29 %30 %27 | |
| %30 = OpLabel | |
| %6 = OpLoad %12 %4 | |
| %7 = OpISub %12 %6 %19 | |
| OpStore %4 %7 | |
| OpBranch %26 | |
| %26 = OpLabel | |
| %8 = OpLoad %12 %3 | |
| %9 = OpISub %12 %8 %19 | |
| OpStore %3 %9 | |
| OpBranch %24 | |
| %27 = OpLabel | |
| OpBranch %23 | |
| %23 = OpLabel | |
| OpBranch %21 | |
| %22 = OpLabel | |
| OpBranch %31 | |
| %31 = OpLabel | |
| OpLoopMerge %32 %31 None | |
| OpBranchConditional %17 %31 %32 | |
| %32 = OpLabel | |
| OpSelectionMerge %33 None | |
| OpBranchConditional %17 %34 %35 | |
| %34 = OpLabel | |
| OpBranch %33 | |
| %35 = OpLabel | |
| OpBranch %33 | |
| %33 = OpLabel | |
| %42 = OpPhi %12 %19 %33 %18 %34 %18 %35 | |
| OpLoopMerge %36 %33 None | |
| OpBranchConditional %17 %36 %33 | |
| %36 = OpLabel | |
| %43 = OpPhi %12 %18 %33 %18 %41 | |
| OpReturn | |
| %37 = OpLabel | |
| OpLoopMerge %38 %39 None | |
| OpBranch %40 | |
| %40 = OpLabel | |
| OpBranchConditional %17 %41 %38 | |
| %41 = OpLabel | |
| OpBranchConditional %17 %36 %39 | |
| %39 = OpLabel | |
| OpBranch %37 | |
| %38 = OpLabel | |
| OpReturn | |
| OpFunctionEnd | |
| )"; | |
| ASSERT_TRUE(IsEqual(env, after_adjustment, context.get())); | |
| } | |
| TEST(FuzzerPassOutlineFunctionsTest, EntryBlockIsHeader) { | |
| const auto env = SPV_ENV_UNIVERSAL_1_5; | |
| 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); | |
| FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100, | |
| false); | |
| protobufs::TransformationSequence transformation_sequence; | |
| FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, | |
| &fuzzer_context, | |
| &transformation_sequence, false); | |
| // Block 21 | |
| auto suitable_entry_block = | |
| fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(21)); | |
| // A suitable entry block should have been found by finding the preheader | |
| // (%20) and then splitting it. | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 100); | |
| // Block 24 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(24)); | |
| // A preheader should have been created, because the current one is a loop | |
| // header. | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 101); | |
| // Block 31 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(31)); | |
| // An existing suitable entry block should have been found by finding the | |
| // preheader (%22), which is already suitable. | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 22); | |
| // Block 33 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(33)); | |
| // An existing suitable entry block should have been found by creating a new | |
| // preheader (there is not one already), and then splitting it (as it contains | |
| // OpPhi). | |
| ASSERT_TRUE(suitable_entry_block); | |
| ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 104); | |
| // Block 37 | |
| suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining( | |
| context->get_instr_block(37)); | |
| // No suitable entry block can be found for block 37, since it is a loop | |
| // header with only one predecessor (the back-edge block). | |
| ASSERT_FALSE(suitable_entry_block); | |
| std::string after_adjustments = R"( | |
| OpCapability Shader | |
| %1 = OpExtInstImport "GLSL.std.450" | |
| OpMemoryModel Logical GLSL450 | |
| OpEntryPoint Fragment %2 "main" | |
| OpExecutionMode %2 OriginUpperLeft | |
| OpSource ESSL 310 | |
| OpName %2 "main" | |
| OpName %3 "a" | |
| OpName %4 "b" | |
| OpDecorate %3 RelaxedPrecision | |
| OpDecorate %4 RelaxedPrecision | |
| OpDecorate %5 RelaxedPrecision | |
| OpDecorate %6 RelaxedPrecision | |
| OpDecorate %7 RelaxedPrecision | |
| OpDecorate %8 RelaxedPrecision | |
| OpDecorate %9 RelaxedPrecision | |
| %10 = OpTypeVoid | |
| %11 = OpTypeFunction %10 | |
| %12 = OpTypeInt 32 1 | |
| %13 = OpTypePointer Function %12 | |
| %14 = OpConstant %12 8 | |
| %15 = OpConstant %12 23 | |
| %16 = OpTypeBool | |
| %17 = OpConstantTrue %16 | |
| %18 = OpConstant %12 0 | |
| %19 = OpConstant %12 1 | |
| %2 = OpFunction %10 None %11 | |
| %20 = OpLabel | |
| %3 = OpVariable %13 Function | |
| %4 = OpVariable %13 Function | |
| OpBranch %100 | |
| %100 = OpLabel | |
| OpStore %3 %14 | |
| OpStore %4 %15 | |
| OpBranch %21 | |
| %21 = OpLabel | |
| OpLoopMerge %22 %23 None | |
| OpBranch %101 | |
| %101 = OpLabel | |
| OpBranch %24 | |
| %24 = OpLabel | |
| %25 = OpPhi %12 %19 %101 %18 %26 | |
| OpLoopMerge %27 %26 None | |
| OpBranch %28 | |
| %28 = OpLabel | |
| %5 = OpLoad %12 %3 | |
| %29 = OpSGreaterThan %16 %5 %18 | |
| OpBranchConditional %29 %30 %27 | |
| %30 = OpLabel | |
| %6 = OpLoad %12 %4 | |
| %7 = OpISub %12 %6 %19 | |
| OpStore %4 %7 | |
| OpBranch %26 | |
| %26 = OpLabel | |
| %8 = OpLoad %12 %3 | |
| %9 = OpISub %12 %8 %19 | |
| OpStore %3 %9 | |
| OpBranch %24 | |
| %27 = OpLabel | |
| OpBranch %23 | |
| %23 = OpLabel | |
| OpBranch %21 | |
| %22 = OpLabel | |
| OpBranch %31 | |
| %31 = OpLabel | |
| OpLoopMerge %32 %31 None | |
| OpBranchConditional %17 %31 %32 | |
| %32 = OpLabel | |
| OpSelectionMerge %102 None | |
| OpBranchConditional %17 %34 %35 | |
| %34 = OpLabel | |
| OpBranch %102 | |
| %35 = OpLabel | |
| OpBranch %102 | |
| %102 = OpLabel | |
| %103 = OpPhi %12 %18 %34 %18 %35 | |
| OpBranch %104 | |
| %104 = OpLabel | |
| OpBranch %33 | |
| %33 = OpLabel | |
| %42 = OpPhi %12 %103 %104 %19 %33 | |
| OpLoopMerge %36 %33 None | |
| OpBranchConditional %17 %36 %33 | |
| %36 = OpLabel | |
| %43 = OpPhi %12 %18 %33 %18 %41 | |
| OpReturn | |
| %37 = OpLabel | |
| OpLoopMerge %38 %39 None | |
| OpBranch %40 | |
| %40 = OpLabel | |
| OpBranchConditional %17 %41 %38 | |
| %41 = OpLabel | |
| OpBranchConditional %17 %36 %39 | |
| %39 = OpLabel | |
| OpBranch %37 | |
| %38 = OpLabel | |
| OpReturn | |
| OpFunctionEnd | |
| )"; | |
| ASSERT_TRUE(IsEqual(env, after_adjustments, context.get())); | |
| } | |
| TEST(FuzzerPassOutlineFunctionsTest, ExitBlock) { | |
| const auto env = SPV_ENV_UNIVERSAL_1_5; | |
| 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); | |
| FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100, | |
| false); | |
| protobufs::TransformationSequence transformation_sequence; | |
| FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context, | |
| &fuzzer_context, | |
| &transformation_sequence, false); | |
| // Block 39 is not a merge block, so it is already suitable. | |
| auto suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining( | |
| context->get_instr_block(39)); | |
| ASSERT_TRUE(suitable_exit_block); | |
| ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 39); | |
| // The following are merge blocks and, thus, they will need to be split. | |
| // Block 22 | |
| suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining( | |
| context->get_instr_block(22)); | |
| ASSERT_TRUE(suitable_exit_block); | |
| ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 100); | |
| // Block 27 | |
| suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining( | |
| context->get_instr_block(27)); | |
| ASSERT_TRUE(suitable_exit_block); | |
| ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 101); | |
| // Block 36 | |
| suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining( | |
| context->get_instr_block(36)); | |
| ASSERT_TRUE(suitable_exit_block); | |
| ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 102); | |
| std::string after_adjustments = R"( | |
| OpCapability Shader | |
| %1 = OpExtInstImport "GLSL.std.450" | |
| OpMemoryModel Logical GLSL450 | |
| OpEntryPoint Fragment %2 "main" | |
| OpExecutionMode %2 OriginUpperLeft | |
| OpSource ESSL 310 | |
| OpName %2 "main" | |
| OpName %3 "a" | |
| OpName %4 "b" | |
| OpDecorate %3 RelaxedPrecision | |
| OpDecorate %4 RelaxedPrecision | |
| OpDecorate %5 RelaxedPrecision | |
| OpDecorate %6 RelaxedPrecision | |
| OpDecorate %7 RelaxedPrecision | |
| OpDecorate %8 RelaxedPrecision | |
| OpDecorate %9 RelaxedPrecision | |
| %10 = OpTypeVoid | |
| %11 = OpTypeFunction %10 | |
| %12 = OpTypeInt 32 1 | |
| %13 = OpTypePointer Function %12 | |
| %14 = OpConstant %12 8 | |
| %15 = OpConstant %12 23 | |
| %16 = OpTypeBool | |
| %17 = OpConstantTrue %16 | |
| %18 = OpConstant %12 0 | |
| %19 = OpConstant %12 1 | |
| %2 = OpFunction %10 None %11 | |
| %20 = OpLabel | |
| %3 = OpVariable %13 Function | |
| %4 = OpVariable %13 Function | |
| OpStore %3 %14 | |
| OpStore %4 %15 | |
| OpBranch %21 | |
| %21 = OpLabel | |
| OpLoopMerge %22 %23 None | |
| OpBranch %24 | |
| %24 = OpLabel | |
| %25 = OpPhi %12 %19 %21 %18 %26 | |
| OpLoopMerge %27 %26 None | |
| OpBranch %28 | |
| %28 = OpLabel | |
| %5 = OpLoad %12 %3 | |
| %29 = OpSGreaterThan %16 %5 %18 | |
| OpBranchConditional %29 %30 %27 | |
| %30 = OpLabel | |
| %6 = OpLoad %12 %4 | |
| %7 = OpISub %12 %6 %19 | |
| OpStore %4 %7 | |
| OpBranch %26 | |
| %26 = OpLabel | |
| %8 = OpLoad %12 %3 | |
| %9 = OpISub %12 %8 %19 | |
| OpStore %3 %9 | |
| OpBranch %24 | |
| %27 = OpLabel | |
| OpBranch %101 | |
| %101 = OpLabel | |
| OpBranch %23 | |
| %23 = OpLabel | |
| OpBranch %21 | |
| %22 = OpLabel | |
| OpBranch %100 | |
| %100 = OpLabel | |
| OpBranch %31 | |
| %31 = OpLabel | |
| OpLoopMerge %32 %31 None | |
| OpBranchConditional %17 %31 %32 | |
| %32 = OpLabel | |
| OpSelectionMerge %33 None | |
| OpBranchConditional %17 %34 %35 | |
| %34 = OpLabel | |
| OpBranch %33 | |
| %35 = OpLabel | |
| OpBranch %33 | |
| %33 = OpLabel | |
| %42 = OpPhi %12 %19 %33 %18 %34 %18 %35 | |
| OpLoopMerge %36 %33 None | |
| OpBranchConditional %17 %36 %33 | |
| %36 = OpLabel | |
| %43 = OpPhi %12 %18 %33 %18 %41 | |
| OpBranch %102 | |
| %102 = OpLabel | |
| OpReturn | |
| %37 = OpLabel | |
| OpLoopMerge %38 %39 None | |
| OpBranch %40 | |
| %40 = OpLabel | |
| OpBranchConditional %17 %41 %38 | |
| %41 = OpLabel | |
| OpBranchConditional %17 %36 %39 | |
| %39 = OpLabel | |
| OpBranch %37 | |
| %38 = OpLabel | |
| OpReturn | |
| OpFunctionEnd | |
| )"; | |
| ASSERT_TRUE(IsEqual(env, after_adjustments, context.get())); | |
| } | |
| } // namespace | |
| } // namespace fuzz | |
| } // namespace spvtools |