spirv-fuzz: Add fuzzer pass to change selection controls (#2944)
A new pass that allows the fuzzer to change the 'selection control' operand of OpSelectionControl instructions. Fixes #2937.
This commit is contained in:
Родитель
3c7ff8d4f0
Коммит
26dba32c43
|
@ -38,6 +38,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
fuzzer_pass_add_dead_breaks.h
|
||||
fuzzer_pass_add_dead_continues.h
|
||||
fuzzer_pass_add_useful_constructs.h
|
||||
fuzzer_pass_adjust_selection_controls.h
|
||||
fuzzer_pass_apply_id_synonyms.h
|
||||
fuzzer_pass_copy_objects.h
|
||||
fuzzer_pass_obfuscate_constants.h
|
||||
|
@ -64,6 +65,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
transformation_replace_constant_with_uniform.h
|
||||
transformation_replace_id_with_synonym.h
|
||||
transformation_set_selection_control.h
|
||||
transformation_split_block.h
|
||||
uniform_buffer_element_descriptor.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
|
||||
|
@ -77,6 +79,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
fuzzer_pass_add_dead_breaks.cpp
|
||||
fuzzer_pass_add_dead_continues.cpp
|
||||
fuzzer_pass_add_useful_constructs.cpp
|
||||
fuzzer_pass_adjust_selection_controls.cpp
|
||||
fuzzer_pass_apply_id_synonyms.cpp
|
||||
fuzzer_pass_copy_objects.cpp
|
||||
fuzzer_pass_obfuscate_constants.cpp
|
||||
|
@ -102,6 +105,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
transformation_replace_constant_with_uniform.cpp
|
||||
transformation_replace_id_with_synonym.cpp
|
||||
transformation_set_selection_control.cpp
|
||||
transformation_split_block.cpp
|
||||
uniform_buffer_element_descriptor.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_dead_continues.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||
#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
|
||||
#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
|
||||
#include "source/fuzz/fuzzer_pass_copy_objects.h"
|
||||
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
||||
|
@ -162,6 +163,15 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
|||
passes[fuzzer_context.RandomIndex(passes)]->Apply();
|
||||
}
|
||||
|
||||
// Now apply some passes that it does not make sense to apply repeatedly,
|
||||
// as they do not unlock other passes.
|
||||
if (fuzzer_context.ChooseEven()) {
|
||||
FuzzerPassAdjustSelectionControls(ir_context.get(), &fact_manager,
|
||||
&fuzzer_context,
|
||||
transformation_sequence_out)
|
||||
.Apply();
|
||||
}
|
||||
|
||||
// Encode the module as a binary.
|
||||
ir_context->module()->ToBinary(binary_out, false);
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace {
|
|||
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBreak = {5, 80};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
|
||||
90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfMovingBlockDown = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfObfuscatingConstant = {10, 90};
|
||||
|
@ -53,6 +55,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
|||
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
|
||||
chance_of_adding_dead_continue_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
|
||||
chance_of_adjusting_selection_control_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
|
||||
chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
|
||||
chance_of_moving_block_down_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfMovingBlockDown);
|
||||
|
|
|
@ -62,6 +62,9 @@ class FuzzerContext {
|
|||
uint32_t GetChanceOfAddingDeadContinue() {
|
||||
return chance_of_adding_dead_continue_;
|
||||
}
|
||||
uint32_t GetChanceOfAdjustingSelectionControl() {
|
||||
return chance_of_adjusting_selection_control_;
|
||||
}
|
||||
uint32_t GetChanceOfCopyingObject() { return chance_of_copying_object_; }
|
||||
uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; }
|
||||
uint32_t GetChanceOfObfuscatingConstant() {
|
||||
|
@ -88,6 +91,7 @@ class FuzzerContext {
|
|||
// Keep them in alphabetical order.
|
||||
uint32_t chance_of_adding_dead_break_;
|
||||
uint32_t chance_of_adding_dead_continue_;
|
||||
uint32_t chance_of_adjusting_selection_control_;
|
||||
uint32_t chance_of_copying_object_;
|
||||
uint32_t chance_of_moving_block_down_;
|
||||
uint32_t chance_of_obfuscating_constant_;
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
using opt::IRContext;
|
||||
|
||||
FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2019 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_adjust_selection_controls.h"
|
||||
|
||||
#include "source/fuzz/transformation_set_selection_control.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
|
||||
|
||||
FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() =
|
||||
default;
|
||||
|
||||
void FuzzerPassAdjustSelectionControls::Apply() {
|
||||
// Consider every merge instruction in the module (via looking through all
|
||||
// functions and blocks).
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
for (auto& block : function) {
|
||||
if (auto merge_inst = block.GetMergeInst()) {
|
||||
// Ignore the instruction if it is not a selection merge.
|
||||
if (merge_inst->opcode() != SpvOpSelectionMerge) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Choose randomly whether to change the selection control for this
|
||||
// instruction.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAdjustingSelectionControl())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The choices to change the selection control to are the set of valid
|
||||
// controls, minus the current control.
|
||||
std::vector<uint32_t> choices;
|
||||
for (auto control :
|
||||
{SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask,
|
||||
SpvSelectionControlDontFlattenMask}) {
|
||||
if (control == merge_inst->GetSingleWordOperand(1)) {
|
||||
continue;
|
||||
}
|
||||
choices.push_back(control);
|
||||
}
|
||||
|
||||
// Apply the transformation and add it to the output transformation
|
||||
// sequence.
|
||||
TransformationSetSelectionControl transformation(
|
||||
block.id(), choices[GetFuzzerContext()->RandomIndex(choices)]);
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Transformation should be applicable by construction.");
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
transformation.ToMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2019 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// A pass that adjusts the selection controls on OpSelectionMerge instructions.
|
||||
class FuzzerPassAdjustSelectionControls : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAdjustSelectionControls(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAdjustSelectionControls() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_
|
|
@ -173,6 +173,7 @@ message Transformation {
|
|||
TransformationAddDeadContinue add_dead_continue = 12;
|
||||
TransformationCopyObject copy_object = 13;
|
||||
TransformationReplaceIdWithSynonym replace_id_with_synonym = 14;
|
||||
TransformationSetSelectionControl set_selection_control = 15;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
|
@ -384,6 +385,22 @@ message TransformationReplaceIdWithSynonym {
|
|||
uint32 fresh_id_for_temporary = 3;
|
||||
}
|
||||
|
||||
message TransformationSetSelectionControl {
|
||||
|
||||
// A transformation that sets the selection control operand of an
|
||||
// OpSelectionMerge instruction.
|
||||
|
||||
// The id of a basic block that should contain OpSelectionMerge.
|
||||
uint32 block_id = 1;
|
||||
|
||||
// The value to which the 'selection control' operand should be set.
|
||||
// Although technically 'selection control' is a literal mask that can be
|
||||
// some combination of 'None', 'Flatten' and 'DontFlatten', the combination
|
||||
// 'Flatten | DontFlatten' does not make sense.
|
||||
uint32 selection_control = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationSplitBlock {
|
||||
|
||||
// A transformation that splits a basic block into two basic blocks
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "transformation_replace_constant_with_uniform.h"
|
||||
#include "transformation_replace_id_with_synonym.h"
|
||||
#include "transformation_set_selection_control.h"
|
||||
#include "transformation_split_block.h"
|
||||
|
||||
namespace spvtools {
|
||||
|
@ -76,6 +77,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
|||
case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
|
||||
return MakeUnique<TransformationReplaceIdWithSynonym>(
|
||||
message.replace_id_with_synonym());
|
||||
case protobufs::Transformation::TransformationCase::kSetSelectionControl:
|
||||
return MakeUnique<TransformationSetSelectionControl>(
|
||||
message.set_selection_control());
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
return MakeUnique<TransformationSplitBlock>(message.split_block());
|
||||
case protobufs::Transformation::TRANSFORMATION_NOT_SET:
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2019 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/transformation_set_selection_control.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationSetSelectionControl::TransformationSetSelectionControl(
|
||||
const spvtools::fuzz::protobufs::TransformationSetSelectionControl& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationSetSelectionControl::TransformationSetSelectionControl(
|
||||
uint32_t block_id, uint32_t selection_control) {
|
||||
message_.set_block_id(block_id);
|
||||
message_.set_selection_control(selection_control);
|
||||
}
|
||||
|
||||
bool TransformationSetSelectionControl::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
assert((message_.selection_control() == SpvSelectionControlMaskNone ||
|
||||
message_.selection_control() == SpvSelectionControlFlattenMask ||
|
||||
message_.selection_control() == SpvSelectionControlDontFlattenMask) &&
|
||||
"Selection control should never be set to something other than "
|
||||
"'None', 'Flatten' or 'DontFlatten'");
|
||||
if (auto block = context->get_instr_block(message_.block_id())) {
|
||||
if (auto merge_inst = block->GetMergeInst()) {
|
||||
return merge_inst->opcode() == SpvOpSelectionMerge;
|
||||
}
|
||||
}
|
||||
// Either the block did not exit, or did not end with OpSelectionMerge.
|
||||
return false;
|
||||
}
|
||||
|
||||
void TransformationSetSelectionControl::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
context->get_instr_block(message_.block_id())
|
||||
->GetMergeInst()
|
||||
->SetInOperand(1, {message_.selection_control()});
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationSetSelectionControl::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_set_selection_control() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2019 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationSetSelectionControl : public Transformation {
|
||||
public:
|
||||
explicit TransformationSetSelectionControl(
|
||||
const protobufs::TransformationSetSelectionControl& message);
|
||||
|
||||
TransformationSetSelectionControl(uint32_t block_id,
|
||||
uint32_t selection_control);
|
||||
|
||||
// - |message_.block_id| must be a block containing an OpSelectionMerge
|
||||
// instruction.
|
||||
// - |message_.selection_control| must be one of None, Flatten or
|
||||
// DontFlatten.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// - The selection control operand of the OpSelectionMergeInstruction in
|
||||
// |message_.block_id| is overwritten with |message_.selection_control|.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationSetSelectionControl message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_
|
|
@ -33,6 +33,7 @@ if (${SPIRV_BUILD_FUZZER})
|
|||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
transformation_replace_constant_with_uniform_test.cpp
|
||||
transformation_replace_id_with_synonym_test.cpp
|
||||
transformation_set_selection_control_test.cpp
|
||||
transformation_split_block_test.cpp
|
||||
uniform_buffer_element_descriptor_test.cpp)
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
// Copyright (c) 2019 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/transformation_set_selection_control.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetSelectionControlTest, VariousScenarios) {
|
||||
// This is a simple transformation; this test captures the important things
|
||||
// to check for.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 3
|
||||
%25 = OpConstant %6 1
|
||||
%28 = OpConstant %6 2
|
||||
%38 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpLoad %6 %8
|
||||
%18 = OpSLessThan %17 %15 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%19 = OpLoad %6 %8
|
||||
%21 = OpSGreaterThan %17 %19 %20
|
||||
OpSelectionMerge %23 Flatten
|
||||
OpBranchConditional %21 %22 %23
|
||||
%22 = OpLabel
|
||||
%24 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %24 %25
|
||||
OpStore %8 %26
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%27 = OpLoad %6 %8
|
||||
%29 = OpSLessThan %17 %27 %28
|
||||
OpSelectionMerge %31 DontFlatten
|
||||
OpBranchConditional %29 %30 %31
|
||||
%30 = OpLabel
|
||||
%32 = OpLoad %6 %8
|
||||
%33 = OpISub %6 %32 %25
|
||||
OpStore %8 %33
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpLoad %6 %8
|
||||
OpSelectionMerge %37 None
|
||||
OpSwitch %34 %36 0 %35
|
||||
%36 = OpLabel
|
||||
OpBranch %37
|
||||
%35 = OpLabel
|
||||
%39 = OpLoad %6 %8
|
||||
%40 = OpIAdd %6 %39 %38
|
||||
OpStore %8 %40
|
||||
OpBranch %36
|
||||
%37 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%43 = OpLoad %6 %8
|
||||
%44 = OpIAdd %6 %43 %25
|
||||
OpStore %8 %44
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// %44 is not a block
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(44, SpvSelectionControlFlattenMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// %13 does not end with OpSelectionMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(13, SpvSelectionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// %10 ends in OpLoopMerge, not OpSelectionMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(10, SpvSelectionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationSetSelectionControl transformation1(
|
||||
11, SpvSelectionControlDontFlattenMask);
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation2(
|
||||
23, SpvSelectionControlFlattenMask);
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation3(
|
||||
31, SpvSelectionControlMaskNone);
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation4(
|
||||
31, SpvSelectionControlFlattenMask);
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 3
|
||||
%25 = OpConstant %6 1
|
||||
%28 = OpConstant %6 2
|
||||
%38 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpLoad %6 %8
|
||||
%18 = OpSLessThan %17 %15 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%19 = OpLoad %6 %8
|
||||
%21 = OpSGreaterThan %17 %19 %20
|
||||
OpSelectionMerge %23 DontFlatten
|
||||
OpBranchConditional %21 %22 %23
|
||||
%22 = OpLabel
|
||||
%24 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %24 %25
|
||||
OpStore %8 %26
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%27 = OpLoad %6 %8
|
||||
%29 = OpSLessThan %17 %27 %28
|
||||
OpSelectionMerge %31 Flatten
|
||||
OpBranchConditional %29 %30 %31
|
||||
%30 = OpLabel
|
||||
%32 = OpLoad %6 %8
|
||||
%33 = OpISub %6 %32 %25
|
||||
OpStore %8 %33
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpLoad %6 %8
|
||||
OpSelectionMerge %37 Flatten
|
||||
OpSwitch %34 %36 0 %35
|
||||
%36 = OpLabel
|
||||
OpBranch %37
|
||||
%35 = OpLabel
|
||||
%39 = OpLoad %6 %8
|
||||
%40 = OpIAdd %6 %39 %38
|
||||
OpStore %8 %40
|
||||
OpBranch %36
|
||||
%37 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%43 = OpLoad %6 %8
|
||||
%44 = OpIAdd %6 %43 %25
|
||||
OpStore %8 %44
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Загрузка…
Ссылка в новой задаче