mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-11 09:00:06 +00:00
spirv-fuzz: Add fuzzer pass to change function controls (#2951)
A new pass that allows the fuzzer to change the 'function control' operand of OpFunction instructions. Fixes #2939.
This commit is contained in:
parent
feb1549213
commit
91232f7f75
@ -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_function_controls.h
|
||||
fuzzer_pass_adjust_loop_controls.h
|
||||
fuzzer_pass_adjust_selection_controls.h
|
||||
fuzzer_pass_apply_id_synonyms.h
|
||||
@ -68,6 +69,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_function_control.h
|
||||
transformation_set_loop_control.h
|
||||
transformation_set_selection_control.h
|
||||
transformation_split_block.h
|
||||
@ -83,6 +85,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_function_controls.cpp
|
||||
fuzzer_pass_adjust_loop_controls.cpp
|
||||
fuzzer_pass_adjust_selection_controls.cpp
|
||||
fuzzer_pass_apply_id_synonyms.cpp
|
||||
@ -112,6 +115,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_function_control.cpp
|
||||
transformation_set_loop_control.cpp
|
||||
transformation_set_selection_control.cpp
|
||||
transformation_split_block.cpp
|
||||
|
@ -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_function_controls.h"
|
||||
#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
|
||||
#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
|
||||
#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
|
||||
@ -170,16 +171,18 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
|
||||
// Now apply some passes that it does not make sense to apply repeatedly,
|
||||
// as they do not unlock other passes.
|
||||
if (fuzzer_context.ChooseEven()) {
|
||||
FuzzerPassAdjustLoopControls(ir_context.get(), &fact_manager,
|
||||
&fuzzer_context, transformation_sequence_out)
|
||||
.Apply();
|
||||
}
|
||||
if (fuzzer_context.ChooseEven()) {
|
||||
FuzzerPassAdjustSelectionControls(ir_context.get(), &fact_manager,
|
||||
&fuzzer_context,
|
||||
transformation_sequence_out)
|
||||
.Apply();
|
||||
std::vector<std::unique_ptr<FuzzerPass>> final_passes;
|
||||
MaybeAddPass<FuzzerPassAdjustFunctionControls>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAdjustLoopControls>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAdjustSelectionControls>(
|
||||
&passes, ir_context.get(), &fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
for (auto& pass : final_passes) {
|
||||
pass->Apply();
|
||||
}
|
||||
|
||||
// Encode the module as a binary.
|
||||
|
@ -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> kChanceOfAdjustingFunctionControl = {20,
|
||||
70};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingLoopControl = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
|
||||
90};
|
||||
@ -62,6 +64,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
|
||||
chance_of_adding_dead_continue_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
|
||||
chance_of_adjusting_function_control_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl);
|
||||
chance_of_adjusting_loop_control_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl);
|
||||
chance_of_adjusting_selection_control_ =
|
||||
|
@ -62,6 +62,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfAddingDeadContinue() {
|
||||
return chance_of_adding_dead_continue_;
|
||||
}
|
||||
uint32_t GetChanceOfAdjustingFunctionControl() {
|
||||
return chance_of_adjusting_function_control_;
|
||||
}
|
||||
uint32_t GetChanceOfAdjustingLoopControl() {
|
||||
return chance_of_adjusting_loop_control_;
|
||||
}
|
||||
@ -103,6 +106,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_function_control_;
|
||||
uint32_t chance_of_adjusting_loop_control_;
|
||||
uint32_t chance_of_adjusting_selection_control_;
|
||||
uint32_t chance_of_constructing_composite_;
|
||||
|
73
source/fuzz/fuzzer_pass_adjust_function_controls.cpp
Normal file
73
source/fuzz/fuzzer_pass_adjust_function_controls.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// 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_function_controls.h"
|
||||
|
||||
#include "source/fuzz/transformation_set_function_control.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
|
||||
|
||||
FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default;
|
||||
|
||||
void FuzzerPassAdjustFunctionControls::Apply() {
|
||||
// Consider every function in the module.
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
// Randomly decide whether to adjust this function's controls.
|
||||
if (GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAdjustingFunctionControl())) {
|
||||
// Grab the function control mask for the function in its present form.
|
||||
uint32_t existing_function_control_mask =
|
||||
function.DefInst().GetSingleWordInOperand(0);
|
||||
|
||||
// For the new mask, we first randomly select one of three basic masks:
|
||||
// None, Inline or DontInline. These are always valid (and are mutually
|
||||
// exclusive).
|
||||
std::vector<uint32_t> basic_function_control_masks = {
|
||||
SpvFunctionControlMaskNone, SpvFunctionControlInlineMask,
|
||||
SpvFunctionControlDontInlineMask};
|
||||
uint32_t new_function_control_mask =
|
||||
basic_function_control_masks[GetFuzzerContext()->RandomIndex(
|
||||
basic_function_control_masks)];
|
||||
|
||||
// We now consider the Pure and Const mask bits. If these are already
|
||||
// set on the function then it's OK to keep them, but also interesting
|
||||
// to consider dropping them, so we decide randomly in each case.
|
||||
for (auto mask_bit :
|
||||
{SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
|
||||
if ((existing_function_control_mask & mask_bit) &&
|
||||
GetFuzzerContext()->ChooseEven()) {
|
||||
new_function_control_mask |= mask_bit;
|
||||
}
|
||||
}
|
||||
|
||||
// Create and add a transformation.
|
||||
TransformationSetFunctionControl transformation(
|
||||
function.DefInst().result_id(), new_function_control_mask);
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Transformation should be applicable by construction.");
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
39
source/fuzz/fuzzer_pass_adjust_function_controls.h
Normal file
39
source/fuzz/fuzzer_pass_adjust_function_controls.h
Normal file
@ -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_FUNCTION_CONTROLS_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// A pass that adjusts the function controls on OpFunction instructions.
|
||||
class FuzzerPassAdjustFunctionControls : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAdjustFunctionControls(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAdjustFunctionControls() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_
|
@ -177,6 +177,7 @@ message Transformation {
|
||||
TransformationSetSelectionControl set_selection_control = 15;
|
||||
TransformationConstructComposite construct_composite = 16;
|
||||
TransformationSetLoopControl set_loop_control = 17;
|
||||
TransformationSetFunctionControl set_function_control = 18;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@ -412,6 +413,19 @@ message TransformationReplaceIdWithSynonym {
|
||||
uint32 fresh_id_for_temporary = 3;
|
||||
}
|
||||
|
||||
message TransformationSetFunctionControl {
|
||||
|
||||
// A transformation that sets the function control operand of an OpFunction
|
||||
// instruction.
|
||||
|
||||
// The result id of an OpFunction instruction
|
||||
uint32 function_id = 1;
|
||||
|
||||
// The value to which the 'function control' operand should be set.
|
||||
uint32 function_control = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationSetLoopControl {
|
||||
|
||||
// A transformation that sets the loop control operand of an OpLoopMerge
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/fuzz/transformation_replace_id_with_synonym.h"
|
||||
#include "source/fuzz/transformation_set_function_control.h"
|
||||
#include "source/fuzz/transformation_set_loop_control.h"
|
||||
#include "source/fuzz/transformation_set_selection_control.h"
|
||||
#include "source/fuzz/transformation_split_block.h"
|
||||
@ -82,6 +83,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
|
||||
return MakeUnique<TransformationReplaceIdWithSynonym>(
|
||||
message.replace_id_with_synonym());
|
||||
case protobufs::Transformation::TransformationCase::kSetFunctionControl:
|
||||
return MakeUnique<TransformationSetFunctionControl>(
|
||||
message.set_function_control());
|
||||
case protobufs::Transformation::TransformationCase::kSetLoopControl:
|
||||
return MakeUnique<TransformationSetLoopControl>(
|
||||
message.set_loop_control());
|
||||
|
100
source/fuzz/transformation_set_function_control.cpp
Normal file
100
source/fuzz/transformation_set_function_control.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
// 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_function_control.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationSetFunctionControl::TransformationSetFunctionControl(
|
||||
const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationSetFunctionControl::TransformationSetFunctionControl(
|
||||
uint32_t function_id, uint32_t function_control) {
|
||||
message_.set_function_id(function_id);
|
||||
message_.set_function_control(function_control);
|
||||
}
|
||||
|
||||
bool TransformationSetFunctionControl::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
opt::Instruction* function_def_instruction =
|
||||
FindFunctionDefInstruction(context);
|
||||
if (!function_def_instruction) {
|
||||
// The given function id does not correspond to any function.
|
||||
return false;
|
||||
}
|
||||
uint32_t existing_function_control_mask =
|
||||
function_def_instruction->GetSingleWordInOperand(0);
|
||||
|
||||
// Check (via an assertion) that function control mask doesn't have any bad
|
||||
// bits set.
|
||||
uint32_t acceptable_function_control_bits =
|
||||
SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask |
|
||||
SpvFunctionControlPureMask | SpvFunctionControlConstMask;
|
||||
// The following is to keep release-mode compilers happy as this variable is
|
||||
// only used in an assertion.
|
||||
(void)(acceptable_function_control_bits);
|
||||
assert(!(message_.function_control() & ~acceptable_function_control_bits) &&
|
||||
"Nonsensical loop control bits were found.");
|
||||
|
||||
// Check (via an assertion) that function control mask does not have both
|
||||
// Inline and DontInline bits set.
|
||||
assert(!((message_.function_control() & SpvFunctionControlInlineMask) &&
|
||||
(message_.function_control() & SpvFunctionControlDontInlineMask)) &&
|
||||
"It is not OK to set both the 'Inline' and 'DontInline' bits of a "
|
||||
"function control mask");
|
||||
|
||||
// Check that Const and Pure are only present if they were present on the
|
||||
// original function
|
||||
for (auto mask_bit :
|
||||
{SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
|
||||
if ((message_.function_control() & mask_bit) &&
|
||||
!(existing_function_control_mask & mask_bit)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransformationSetFunctionControl::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
opt::Instruction* function_def_instruction =
|
||||
FindFunctionDefInstruction(context);
|
||||
function_def_instruction->SetInOperand(0, {message_.function_control()});
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationSetFunctionControl::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_set_function_control() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
opt::Instruction* TransformationSetFunctionControl ::FindFunctionDefInstruction(
|
||||
opt::IRContext* context) const {
|
||||
// Look through all functions for a function whose defining instruction's
|
||||
// result id matches |message_.function_id|, returning the defining
|
||||
// instruction if found.
|
||||
for (auto& function : *context->module()) {
|
||||
if (function.DefInst().result_id() == message_.function_id()) {
|
||||
return &function.DefInst();
|
||||
}
|
||||
}
|
||||
// A nullptr result indicates that no match was found.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
58
source/fuzz/transformation_set_function_control.h
Normal file
58
source/fuzz/transformation_set_function_control.h
Normal file
@ -0,0 +1,58 @@
|
||||
// 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_FUNCTION_CONTROL_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_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 TransformationSetFunctionControl : public Transformation {
|
||||
public:
|
||||
explicit TransformationSetFunctionControl(
|
||||
const protobufs::TransformationSetFunctionControl& message);
|
||||
|
||||
TransformationSetFunctionControl(uint32_t function_id,
|
||||
uint32_t function_control);
|
||||
|
||||
// - |message_.function_id| must be the result id of an OpFunction
|
||||
// instruction.
|
||||
// - |message_.function_control| must be a function control mask that sets
|
||||
// at most one of 'Inline' or 'DontInline', and that may not contain 'Pure'
|
||||
// (respectively 'Const') unless the existing function control mask contains
|
||||
// 'Pure' (respectively 'Const').
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// The function control operand of instruction |message_.function_id| is
|
||||
// over-written with |message_.function_control|.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
opt::Instruction* FindFunctionDefInstruction(opt::IRContext* context) const;
|
||||
|
||||
protobufs::TransformationSetFunctionControl message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_
|
@ -34,6 +34,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_function_control_test.cpp
|
||||
transformation_set_loop_control_test.cpp
|
||||
transformation_set_selection_control_test.cpp
|
||||
transformation_split_block_test.cpp
|
||||
|
251
test/fuzz/transformation_set_function_control_test.cpp
Normal file
251
test/fuzz/transformation_set_function_control_test.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
// 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_function_control.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetFunctionControlTest, 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" %54
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %11 "foo(i1;i1;"
|
||||
OpName %9 "a"
|
||||
OpName %10 "b"
|
||||
OpName %13 "bar("
|
||||
OpName %17 "baz(i1;"
|
||||
OpName %16 "x"
|
||||
OpName %21 "boo(i1;i1;"
|
||||
OpName %19 "a"
|
||||
OpName %20 "b"
|
||||
OpName %29 "g"
|
||||
OpName %42 "param"
|
||||
OpName %44 "param"
|
||||
OpName %45 "param"
|
||||
OpName %48 "param"
|
||||
OpName %49 "param"
|
||||
OpName %54 "color"
|
||||
OpDecorate %54 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpTypeFunction %6 %7 %7
|
||||
%15 = OpTypeFunction %6 %7
|
||||
%28 = OpTypePointer Private %6
|
||||
%29 = OpVariable %28 Private
|
||||
%30 = OpConstant %6 2
|
||||
%31 = OpConstant %6 5
|
||||
%51 = OpTypeFloat 32
|
||||
%52 = OpTypeVector %51 4
|
||||
%53 = OpTypePointer Output %52
|
||||
%54 = OpVariable %53 Output
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%42 = OpVariable %7 Function
|
||||
%44 = OpVariable %7 Function
|
||||
%45 = OpVariable %7 Function
|
||||
%48 = OpVariable %7 Function
|
||||
%49 = OpVariable %7 Function
|
||||
%41 = OpFunctionCall %2 %13
|
||||
OpStore %42 %30
|
||||
%43 = OpFunctionCall %6 %17 %42
|
||||
OpStore %44 %31
|
||||
%46 = OpLoad %6 %29
|
||||
OpStore %45 %46
|
||||
%47 = OpFunctionCall %6 %21 %44 %45
|
||||
OpStore %48 %43
|
||||
OpStore %49 %47
|
||||
%50 = OpFunctionCall %6 %11 %48 %49
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%11 = OpFunction %6 Const %8
|
||||
%9 = OpFunctionParameter %7
|
||||
%10 = OpFunctionParameter %7
|
||||
%12 = OpLabel
|
||||
%23 = OpLoad %6 %9
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpIAdd %6 %23 %24
|
||||
OpReturnValue %25
|
||||
OpFunctionEnd
|
||||
%13 = OpFunction %2 Inline %3
|
||||
%14 = OpLabel
|
||||
OpStore %29 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%17 = OpFunction %6 Pure|DontInline %15
|
||||
%16 = OpFunctionParameter %7
|
||||
%18 = OpLabel
|
||||
%32 = OpLoad %6 %16
|
||||
%33 = OpIAdd %6 %31 %32
|
||||
OpReturnValue %33
|
||||
OpFunctionEnd
|
||||
%21 = OpFunction %6 DontInline %8
|
||||
%19 = OpFunctionParameter %7
|
||||
%20 = OpFunctionParameter %7
|
||||
%22 = OpLabel
|
||||
%36 = OpLoad %6 %19
|
||||
%37 = OpLoad %6 %20
|
||||
%38 = OpIMul %6 %36 %37
|
||||
OpReturnValue %38
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// %36 is not a function
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(36, SpvFunctionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Cannot add the Pure function control to %4 as it did not already have it
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(4, SpvFunctionControlPureMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Cannot add the Const function control to %21 as it did not already
|
||||
// have it
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(21, SpvFunctionControlConstMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Set to None, removing Const
|
||||
TransformationSetFunctionControl transformation1(11,
|
||||
SpvFunctionControlMaskNone);
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Set to Inline; silly to do it on an entry point, but it is allowed
|
||||
TransformationSetFunctionControl transformation2(
|
||||
4, SpvFunctionControlInlineMask);
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Set to Pure, removing DontInline
|
||||
TransformationSetFunctionControl transformation3(17,
|
||||
SpvFunctionControlPureMask);
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Change from Inline to DontInline
|
||||
TransformationSetFunctionControl transformation4(
|
||||
13, SpvFunctionControlDontInlineMask);
|
||||
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" %54
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %11 "foo(i1;i1;"
|
||||
OpName %9 "a"
|
||||
OpName %10 "b"
|
||||
OpName %13 "bar("
|
||||
OpName %17 "baz(i1;"
|
||||
OpName %16 "x"
|
||||
OpName %21 "boo(i1;i1;"
|
||||
OpName %19 "a"
|
||||
OpName %20 "b"
|
||||
OpName %29 "g"
|
||||
OpName %42 "param"
|
||||
OpName %44 "param"
|
||||
OpName %45 "param"
|
||||
OpName %48 "param"
|
||||
OpName %49 "param"
|
||||
OpName %54 "color"
|
||||
OpDecorate %54 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpTypeFunction %6 %7 %7
|
||||
%15 = OpTypeFunction %6 %7
|
||||
%28 = OpTypePointer Private %6
|
||||
%29 = OpVariable %28 Private
|
||||
%30 = OpConstant %6 2
|
||||
%31 = OpConstant %6 5
|
||||
%51 = OpTypeFloat 32
|
||||
%52 = OpTypeVector %51 4
|
||||
%53 = OpTypePointer Output %52
|
||||
%54 = OpVariable %53 Output
|
||||
%4 = OpFunction %2 Inline %3
|
||||
%5 = OpLabel
|
||||
%42 = OpVariable %7 Function
|
||||
%44 = OpVariable %7 Function
|
||||
%45 = OpVariable %7 Function
|
||||
%48 = OpVariable %7 Function
|
||||
%49 = OpVariable %7 Function
|
||||
%41 = OpFunctionCall %2 %13
|
||||
OpStore %42 %30
|
||||
%43 = OpFunctionCall %6 %17 %42
|
||||
OpStore %44 %31
|
||||
%46 = OpLoad %6 %29
|
||||
OpStore %45 %46
|
||||
%47 = OpFunctionCall %6 %21 %44 %45
|
||||
OpStore %48 %43
|
||||
OpStore %49 %47
|
||||
%50 = OpFunctionCall %6 %11 %48 %49
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%11 = OpFunction %6 None %8
|
||||
%9 = OpFunctionParameter %7
|
||||
%10 = OpFunctionParameter %7
|
||||
%12 = OpLabel
|
||||
%23 = OpLoad %6 %9
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpIAdd %6 %23 %24
|
||||
OpReturnValue %25
|
||||
OpFunctionEnd
|
||||
%13 = OpFunction %2 DontInline %3
|
||||
%14 = OpLabel
|
||||
OpStore %29 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%17 = OpFunction %6 Pure %15
|
||||
%16 = OpFunctionParameter %7
|
||||
%18 = OpLabel
|
||||
%32 = OpLoad %6 %16
|
||||
%33 = OpIAdd %6 %31 %32
|
||||
OpReturnValue %33
|
||||
OpFunctionEnd
|
||||
%21 = OpFunction %6 DontInline %8
|
||||
%19 = OpFunctionParameter %7
|
||||
%20 = OpFunctionParameter %7
|
||||
%22 = OpLabel
|
||||
%36 = OpLoad %6 %19
|
||||
%37 = OpLoad %6 %20
|
||||
%38 = OpIMul %6 %36 %37
|
||||
OpReturnValue %38
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user