mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 19:20:05 +00:00
spirv-fuzz: Add fuzzer pass to change loop controls (#2949)
A new pass that allows the fuzzer to change the 'loop control' operand (and associated literal operands) of OpLoopMerge instructions. Fixes #2938. Fixes #2943.
This commit is contained in:
parent
1cea3b7853
commit
253806adc4
@ -38,6 +38,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
fuzzer_pass_add_dead_breaks.h
|
fuzzer_pass_add_dead_breaks.h
|
||||||
fuzzer_pass_add_dead_continues.h
|
fuzzer_pass_add_dead_continues.h
|
||||||
fuzzer_pass_add_useful_constructs.h
|
fuzzer_pass_add_useful_constructs.h
|
||||||
|
fuzzer_pass_adjust_loop_controls.h
|
||||||
fuzzer_pass_adjust_selection_controls.h
|
fuzzer_pass_adjust_selection_controls.h
|
||||||
fuzzer_pass_apply_id_synonyms.h
|
fuzzer_pass_apply_id_synonyms.h
|
||||||
fuzzer_pass_construct_composites.h
|
fuzzer_pass_construct_composites.h
|
||||||
@ -67,6 +68,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
transformation_replace_boolean_constant_with_constant_binary.h
|
transformation_replace_boolean_constant_with_constant_binary.h
|
||||||
transformation_replace_constant_with_uniform.h
|
transformation_replace_constant_with_uniform.h
|
||||||
transformation_replace_id_with_synonym.h
|
transformation_replace_id_with_synonym.h
|
||||||
|
transformation_set_loop_control.h
|
||||||
transformation_set_selection_control.h
|
transformation_set_selection_control.h
|
||||||
transformation_split_block.h
|
transformation_split_block.h
|
||||||
uniform_buffer_element_descriptor.h
|
uniform_buffer_element_descriptor.h
|
||||||
@ -81,6 +83,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
fuzzer_pass_add_dead_breaks.cpp
|
fuzzer_pass_add_dead_breaks.cpp
|
||||||
fuzzer_pass_add_dead_continues.cpp
|
fuzzer_pass_add_dead_continues.cpp
|
||||||
fuzzer_pass_add_useful_constructs.cpp
|
fuzzer_pass_add_useful_constructs.cpp
|
||||||
|
fuzzer_pass_adjust_loop_controls.cpp
|
||||||
fuzzer_pass_adjust_selection_controls.cpp
|
fuzzer_pass_adjust_selection_controls.cpp
|
||||||
fuzzer_pass_apply_id_synonyms.cpp
|
fuzzer_pass_apply_id_synonyms.cpp
|
||||||
fuzzer_pass_construct_composites.cpp
|
fuzzer_pass_construct_composites.cpp
|
||||||
@ -109,6 +112,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||||
transformation_replace_constant_with_uniform.cpp
|
transformation_replace_constant_with_uniform.cpp
|
||||||
transformation_replace_id_with_synonym.cpp
|
transformation_replace_id_with_synonym.cpp
|
||||||
|
transformation_set_loop_control.cpp
|
||||||
transformation_set_selection_control.cpp
|
transformation_set_selection_control.cpp
|
||||||
transformation_split_block.cpp
|
transformation_split_block.cpp
|
||||||
uniform_buffer_element_descriptor.cpp
|
uniform_buffer_element_descriptor.cpp
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
|
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
|
||||||
#include "source/fuzz/fuzzer_pass_add_dead_continues.h"
|
#include "source/fuzz/fuzzer_pass_add_dead_continues.h"
|
||||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||||
|
#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
|
||||||
#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
|
#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
|
||||||
#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
|
#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
|
||||||
#include "source/fuzz/fuzzer_pass_construct_composites.h"
|
#include "source/fuzz/fuzzer_pass_construct_composites.h"
|
||||||
@ -169,6 +170,11 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
|||||||
|
|
||||||
// Now apply some passes that it does not make sense to apply repeatedly,
|
// Now apply some passes that it does not make sense to apply repeatedly,
|
||||||
// as they do not unlock other passes.
|
// 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()) {
|
if (fuzzer_context.ChooseEven()) {
|
||||||
FuzzerPassAdjustSelectionControls(ir_context.get(), &fact_manager,
|
FuzzerPassAdjustSelectionControls(ir_context.get(), &fact_manager,
|
||||||
&fuzzer_context,
|
&fuzzer_context,
|
||||||
|
@ -25,6 +25,7 @@ namespace {
|
|||||||
|
|
||||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBreak = {5, 80};
|
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> kChanceOfAddingDeadContinue = {5, 80};
|
||||||
|
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingLoopControl = {20, 90};
|
||||||
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
|
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
|
||||||
90};
|
90};
|
||||||
const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
|
const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
|
||||||
@ -34,6 +35,11 @@ const std::pair<uint32_t, uint32_t> kChanceOfObfuscatingConstant = {10, 90};
|
|||||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
|
const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
|
||||||
const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
|
const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
|
||||||
|
|
||||||
|
// Default limits for various quantities that are chosen during fuzzing.
|
||||||
|
// Keep them in alphabetical order.
|
||||||
|
const uint32_t kDefaultMaxLoopControlPartialCount = 100;
|
||||||
|
const uint32_t kDefaultMaxLoopControlPeelCount = 100;
|
||||||
|
|
||||||
// Default functions for controlling how deep to go during recursive
|
// Default functions for controlling how deep to go during recursive
|
||||||
// generation/transformation. Keep them in alphabetical order.
|
// generation/transformation. Keep them in alphabetical order.
|
||||||
|
|
||||||
@ -56,6 +62,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
|||||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
|
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
|
||||||
chance_of_adding_dead_continue_ =
|
chance_of_adding_dead_continue_ =
|
||||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
|
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
|
||||||
|
chance_of_adjusting_loop_control_ =
|
||||||
|
ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl);
|
||||||
chance_of_adjusting_selection_control_ =
|
chance_of_adjusting_selection_control_ =
|
||||||
ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
|
ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
|
||||||
chance_of_constructing_composite_ =
|
chance_of_constructing_composite_ =
|
||||||
@ -68,6 +76,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
|||||||
chance_of_replacing_id_with_synonym_ =
|
chance_of_replacing_id_with_synonym_ =
|
||||||
ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
|
ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
|
||||||
chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
|
chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
|
||||||
|
max_loop_control_partial_count_ = kDefaultMaxLoopControlPartialCount;
|
||||||
|
max_loop_control_peel_count_ = kDefaultMaxLoopControlPeelCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuzzerContext::~FuzzerContext() = default;
|
FuzzerContext::~FuzzerContext() = default;
|
||||||
|
@ -62,6 +62,9 @@ class FuzzerContext {
|
|||||||
uint32_t GetChanceOfAddingDeadContinue() {
|
uint32_t GetChanceOfAddingDeadContinue() {
|
||||||
return chance_of_adding_dead_continue_;
|
return chance_of_adding_dead_continue_;
|
||||||
}
|
}
|
||||||
|
uint32_t GetChanceOfAdjustingLoopControl() {
|
||||||
|
return chance_of_adjusting_loop_control_;
|
||||||
|
}
|
||||||
uint32_t GetChanceOfAdjustingSelectionControl() {
|
uint32_t GetChanceOfAdjustingSelectionControl() {
|
||||||
return chance_of_adjusting_selection_control_;
|
return chance_of_adjusting_selection_control_;
|
||||||
}
|
}
|
||||||
@ -77,6 +80,12 @@ class FuzzerContext {
|
|||||||
return chance_of_replacing_id_with_synonym_;
|
return chance_of_replacing_id_with_synonym_;
|
||||||
}
|
}
|
||||||
uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
|
uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
|
||||||
|
uint32_t GetRandomLoopControlPeelCount() {
|
||||||
|
return random_generator_->RandomUint32(max_loop_control_peel_count_);
|
||||||
|
}
|
||||||
|
uint32_t GetRandomLoopControlPartialCount() {
|
||||||
|
return random_generator_->RandomUint32(max_loop_control_partial_count_);
|
||||||
|
}
|
||||||
|
|
||||||
// Functions to control how deeply to recurse.
|
// Functions to control how deeply to recurse.
|
||||||
// Keep them in alphabetical order.
|
// Keep them in alphabetical order.
|
||||||
@ -94,6 +103,7 @@ class FuzzerContext {
|
|||||||
// Keep them in alphabetical order.
|
// Keep them in alphabetical order.
|
||||||
uint32_t chance_of_adding_dead_break_;
|
uint32_t chance_of_adding_dead_break_;
|
||||||
uint32_t chance_of_adding_dead_continue_;
|
uint32_t chance_of_adding_dead_continue_;
|
||||||
|
uint32_t chance_of_adjusting_loop_control_;
|
||||||
uint32_t chance_of_adjusting_selection_control_;
|
uint32_t chance_of_adjusting_selection_control_;
|
||||||
uint32_t chance_of_constructing_composite_;
|
uint32_t chance_of_constructing_composite_;
|
||||||
uint32_t chance_of_copying_object_;
|
uint32_t chance_of_copying_object_;
|
||||||
@ -102,6 +112,12 @@ class FuzzerContext {
|
|||||||
uint32_t chance_of_replacing_id_with_synonym_;
|
uint32_t chance_of_replacing_id_with_synonym_;
|
||||||
uint32_t chance_of_splitting_block_;
|
uint32_t chance_of_splitting_block_;
|
||||||
|
|
||||||
|
// Limits associated with various quantities for which random values are
|
||||||
|
// chosen during fuzzing.
|
||||||
|
// Keep them in alphabetical order.
|
||||||
|
uint32_t max_loop_control_partial_count_;
|
||||||
|
uint32_t max_loop_control_peel_count_;
|
||||||
|
|
||||||
// Functions to determine with what probability to go deeper when generating
|
// Functions to determine with what probability to go deeper when generating
|
||||||
// or mutating constructs recursively.
|
// or mutating constructs recursively.
|
||||||
const std::function<bool(uint32_t, RandomGenerator*)>&
|
const std::function<bool(uint32_t, RandomGenerator*)>&
|
||||||
|
121
source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
Normal file
121
source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// 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_loop_controls.h"
|
||||||
|
|
||||||
|
#include "source/fuzz/transformation_set_loop_control.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace fuzz {
|
||||||
|
|
||||||
|
FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls(
|
||||||
|
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||||
|
FuzzerContext* fuzzer_context,
|
||||||
|
protobufs::TransformationSequence* transformations)
|
||||||
|
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
|
||||||
|
|
||||||
|
FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default;
|
||||||
|
|
||||||
|
void FuzzerPassAdjustLoopControls::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 loop merge.
|
||||||
|
if (merge_inst->opcode() != SpvOpLoopMerge) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide randomly whether to adjust this loop merge.
|
||||||
|
if (!GetFuzzerContext()->ChoosePercentage(
|
||||||
|
GetFuzzerContext()->GetChanceOfAdjustingLoopControl())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t existing_mask = merge_inst->GetSingleWordOperand(
|
||||||
|
TransformationSetLoopControl::kLoopControlMaskInOperandIndex);
|
||||||
|
|
||||||
|
// First, set the new mask to one of None, Unroll or DontUnroll.
|
||||||
|
std::vector<uint32_t> basic_masks = {SpvLoopControlMaskNone,
|
||||||
|
SpvLoopControlUnrollMask,
|
||||||
|
SpvLoopControlDontUnrollMask};
|
||||||
|
uint32_t new_mask =
|
||||||
|
basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)];
|
||||||
|
|
||||||
|
// For the loop controls that depend on guarantees about what the loop
|
||||||
|
// does, check which of these were present in the existing mask and
|
||||||
|
// randomly decide whether to keep them. They are just hints, so
|
||||||
|
// removing them should not change the semantics of the module.
|
||||||
|
for (auto mask_bit :
|
||||||
|
{SpvLoopControlDependencyInfiniteMask,
|
||||||
|
SpvLoopControlDependencyLengthMask,
|
||||||
|
SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask,
|
||||||
|
SpvLoopControlIterationMultipleMask}) {
|
||||||
|
if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) {
|
||||||
|
// The mask bits we are considering are not available in all SPIR-V
|
||||||
|
// versions. However, we only include a mask bit if it was present
|
||||||
|
// in the original loop control mask, and we work under the
|
||||||
|
// assumption that we are transforming a valid module, thus we don't
|
||||||
|
// need to actually check whether the SPIR-V version being used
|
||||||
|
// supports these loop control mask bits.
|
||||||
|
new_mask |= mask_bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use 0 for peel count and partial count in the case that we choose
|
||||||
|
// not to set these controls.
|
||||||
|
uint32_t peel_count = 0;
|
||||||
|
uint32_t partial_count = 0;
|
||||||
|
|
||||||
|
// PeelCount and PartialCount are not compatible with DontUnroll, so
|
||||||
|
// we check whether DontUnroll is set.
|
||||||
|
if (!(new_mask & SpvLoopControlDontUnrollMask)) {
|
||||||
|
// If PeelCount is supported by this SPIR-V version, randomly choose
|
||||||
|
// whether to set it. If it was set in the original mask and is not
|
||||||
|
// selected for setting here, that amounts to dropping it.
|
||||||
|
if (TransformationSetLoopControl::PeelCountIsSupported(
|
||||||
|
GetIRContext()) &&
|
||||||
|
GetFuzzerContext()->ChooseEven()) {
|
||||||
|
new_mask |= SpvLoopControlPeelCountMask;
|
||||||
|
// The peel count is chosen randomly - if PeelCount was already set
|
||||||
|
// this will overwrite whatever peel count was previously used.
|
||||||
|
peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount();
|
||||||
|
}
|
||||||
|
// Similar, but for PartialCount.
|
||||||
|
if (TransformationSetLoopControl::PartialCountIsSupported(
|
||||||
|
GetIRContext()) &&
|
||||||
|
GetFuzzerContext()->ChooseEven()) {
|
||||||
|
new_mask |= SpvLoopControlPartialCountMask;
|
||||||
|
partial_count =
|
||||||
|
GetFuzzerContext()->GetRandomLoopControlPartialCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the transformation and add it to the output transformation
|
||||||
|
// sequence.
|
||||||
|
TransformationSetLoopControl transformation(block.id(), new_mask,
|
||||||
|
peel_count, partial_count);
|
||||||
|
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_loop_controls.h
Normal file
39
source/fuzz/fuzzer_pass_adjust_loop_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_LOOP_CONTROLS_
|
||||||
|
#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_
|
||||||
|
|
||||||
|
#include "source/fuzz/fuzzer_pass.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace fuzz {
|
||||||
|
|
||||||
|
// A pass that adjusts the loop controls on OpLoopMerge instructions.
|
||||||
|
class FuzzerPassAdjustLoopControls : public FuzzerPass {
|
||||||
|
public:
|
||||||
|
FuzzerPassAdjustLoopControls(
|
||||||
|
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||||
|
FuzzerContext* fuzzer_context,
|
||||||
|
protobufs::TransformationSequence* transformations);
|
||||||
|
|
||||||
|
~FuzzerPassAdjustLoopControls() override;
|
||||||
|
|
||||||
|
void Apply() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fuzz
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_
|
@ -23,8 +23,8 @@ package spvtools.fuzz.protobufs;
|
|||||||
|
|
||||||
message IdUseDescriptor {
|
message IdUseDescriptor {
|
||||||
|
|
||||||
// Describes a use of an id as an input operand to an instruction in some block
|
// Describes a use of an id as an input operand to an instruction in some
|
||||||
// of a function.
|
// block of a function.
|
||||||
|
|
||||||
// Example:
|
// Example:
|
||||||
// - id_of_interest = 42
|
// - id_of_interest = 42
|
||||||
@ -167,7 +167,8 @@ message Transformation {
|
|||||||
TransformationAddTypeFloat add_type_float = 6;
|
TransformationAddTypeFloat add_type_float = 6;
|
||||||
TransformationAddTypeInt add_type_int = 7;
|
TransformationAddTypeInt add_type_int = 7;
|
||||||
TransformationAddDeadBreak add_dead_break = 8;
|
TransformationAddDeadBreak add_dead_break = 8;
|
||||||
TransformationReplaceBooleanConstantWithConstantBinary replace_boolean_constant_with_constant_binary = 9;
|
TransformationReplaceBooleanConstantWithConstantBinary
|
||||||
|
replace_boolean_constant_with_constant_binary = 9;
|
||||||
TransformationAddTypePointer add_type_pointer = 10;
|
TransformationAddTypePointer add_type_pointer = 10;
|
||||||
TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
|
TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
|
||||||
TransformationAddDeadContinue add_dead_continue = 12;
|
TransformationAddDeadContinue add_dead_continue = 12;
|
||||||
@ -175,6 +176,7 @@ message Transformation {
|
|||||||
TransformationReplaceIdWithSynonym replace_id_with_synonym = 14;
|
TransformationReplaceIdWithSynonym replace_id_with_synonym = 14;
|
||||||
TransformationSetSelectionControl set_selection_control = 15;
|
TransformationSetSelectionControl set_selection_control = 15;
|
||||||
TransformationConstructComposite construct_composite = 16;
|
TransformationConstructComposite construct_composite = 16;
|
||||||
|
TransformationSetLoopControl set_loop_control = 17;
|
||||||
// Add additional option using the next available number.
|
// Add additional option using the next available number.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,18 +412,42 @@ message TransformationReplaceIdWithSynonym {
|
|||||||
uint32 fresh_id_for_temporary = 3;
|
uint32 fresh_id_for_temporary = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TransformationSetLoopControl {
|
||||||
|
|
||||||
|
// A transformation that sets the loop control operand of an OpLoopMerge
|
||||||
|
// instruction.
|
||||||
|
|
||||||
|
// The id of a basic block that should contain OpLoopMerge
|
||||||
|
uint32 block_id = 1;
|
||||||
|
|
||||||
|
// The value to which the 'loop control' operand should be set.
|
||||||
|
// This must be a legal loop control mask.
|
||||||
|
uint32 loop_control = 2;
|
||||||
|
|
||||||
|
// Provides a peel count value for the loop. Used if and only if the
|
||||||
|
// PeelCount bit is set. Must be zero if the PeelCount bit is not set (can
|
||||||
|
// still be zero if this bit is set).
|
||||||
|
uint32 peel_count = 3;
|
||||||
|
|
||||||
|
// Provides a partial count value for the loop. Used if and only if the
|
||||||
|
// PartialCount bit is set. Must be zero if the PartialCount bit is not set
|
||||||
|
// (can still be zero if this bit is set).
|
||||||
|
uint32 partial_count = 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
message TransformationSetSelectionControl {
|
message TransformationSetSelectionControl {
|
||||||
|
|
||||||
// A transformation that sets the selection control operand of an
|
// A transformation that sets the selection control operand of an
|
||||||
// OpSelectionMerge instruction.
|
// OpSelectionMerge instruction.
|
||||||
|
|
||||||
// The id of a basic block that should contain OpSelectionMerge.
|
// The id of a basic block that should contain OpSelectionMerge
|
||||||
uint32 block_id = 1;
|
uint32 block_id = 1;
|
||||||
|
|
||||||
// The value to which the 'selection control' operand should be set.
|
// The value to which the 'selection control' operand should be set.
|
||||||
// Although technically 'selection control' is a literal mask that can be
|
// Although technically 'selection control' is a literal mask that can be
|
||||||
// some combination of 'None', 'Flatten' and 'DontFlatten', the combination
|
// some combination of 'None', 'Flatten' and 'DontFlatten', the combination
|
||||||
// 'Flatten | DontFlatten' does not make sense.
|
// 'Flatten | DontFlatten' does not make sense and is not allowed here.
|
||||||
uint32 selection_control = 2;
|
uint32 selection_control = 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
#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_constant_with_uniform.h"
|
||||||
#include "source/fuzz/transformation_replace_id_with_synonym.h"
|
#include "source/fuzz/transformation_replace_id_with_synonym.h"
|
||||||
|
#include "source/fuzz/transformation_set_loop_control.h"
|
||||||
#include "source/fuzz/transformation_set_selection_control.h"
|
#include "source/fuzz/transformation_set_selection_control.h"
|
||||||
#include "source/fuzz/transformation_split_block.h"
|
#include "source/fuzz/transformation_split_block.h"
|
||||||
#include "source/util/make_unique.h"
|
#include "source/util/make_unique.h"
|
||||||
@ -81,6 +82,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
|||||||
case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
|
case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
|
||||||
return MakeUnique<TransformationReplaceIdWithSynonym>(
|
return MakeUnique<TransformationReplaceIdWithSynonym>(
|
||||||
message.replace_id_with_synonym());
|
message.replace_id_with_synonym());
|
||||||
|
case protobufs::Transformation::TransformationCase::kSetLoopControl:
|
||||||
|
return MakeUnique<TransformationSetLoopControl>(
|
||||||
|
message.set_loop_control());
|
||||||
case protobufs::Transformation::TransformationCase::kSetSelectionControl:
|
case protobufs::Transformation::TransformationCase::kSetSelectionControl:
|
||||||
return MakeUnique<TransformationSetSelectionControl>(
|
return MakeUnique<TransformationSetSelectionControl>(
|
||||||
message.set_selection_control());
|
message.set_selection_control());
|
||||||
|
216
source/fuzz/transformation_set_loop_control.cpp
Normal file
216
source/fuzz/transformation_set_loop_control.cpp
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
// 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_loop_control.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace fuzz {
|
||||||
|
|
||||||
|
TransformationSetLoopControl::TransformationSetLoopControl(
|
||||||
|
const spvtools::fuzz::protobufs::TransformationSetLoopControl& message)
|
||||||
|
: message_(message) {}
|
||||||
|
|
||||||
|
TransformationSetLoopControl::TransformationSetLoopControl(
|
||||||
|
uint32_t block_id, uint32_t loop_control, uint32_t peel_count,
|
||||||
|
uint32_t partial_count) {
|
||||||
|
message_.set_block_id(block_id);
|
||||||
|
message_.set_loop_control(loop_control);
|
||||||
|
message_.set_peel_count(peel_count);
|
||||||
|
message_.set_partial_count(partial_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransformationSetLoopControl::IsApplicable(
|
||||||
|
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||||
|
// |message_.block_id| must identify a block that ends with OpLoopMerge.
|
||||||
|
auto block = context->get_instr_block(message_.block_id());
|
||||||
|
if (!block) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto merge_inst = block->GetMergeInst();
|
||||||
|
if (!merge_inst || merge_inst->opcode() != SpvOpLoopMerge) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We sanity-check that the transformation does not try to set any meaningless
|
||||||
|
// bits of the loop control mask.
|
||||||
|
uint32_t all_loop_control_mask_bits_set =
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlDontUnrollMask |
|
||||||
|
SpvLoopControlDependencyInfiniteMask |
|
||||||
|
SpvLoopControlDependencyLengthMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlMaxIterationsMask | SpvLoopControlIterationMultipleMask |
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask;
|
||||||
|
|
||||||
|
// The variable is only used in an assertion; the following keeps release-mode
|
||||||
|
// compilers happy.
|
||||||
|
(void)(all_loop_control_mask_bits_set);
|
||||||
|
|
||||||
|
// No additional bits should be set.
|
||||||
|
assert(!(message_.loop_control() & ~all_loop_control_mask_bits_set));
|
||||||
|
|
||||||
|
// Grab the loop control mask currently associated with the OpLoopMerge
|
||||||
|
// instruction.
|
||||||
|
auto existing_loop_control_mask =
|
||||||
|
merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex);
|
||||||
|
|
||||||
|
// Check that there is no attempt to set one of the loop controls that
|
||||||
|
// requires guarantees to hold.
|
||||||
|
for (SpvLoopControlMask mask :
|
||||||
|
{SpvLoopControlDependencyInfiniteMask,
|
||||||
|
SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
|
||||||
|
SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
|
||||||
|
// We have a problem if this loop control bit was not set in the original
|
||||||
|
// loop control mask but is set by the transformation.
|
||||||
|
if (LoopControlBitIsAddedByTransformation(mask,
|
||||||
|
existing_loop_control_mask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((message_.loop_control() &
|
||||||
|
(SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)) &&
|
||||||
|
!(PeelCountIsSupported(context) && PartialCountIsSupported(context))) {
|
||||||
|
// At least one of PeelCount or PartialCount is used, but the SPIR-V version
|
||||||
|
// in question does not support these loop controls.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message_.peel_count() > 0 &&
|
||||||
|
!(message_.loop_control() & SpvLoopControlPeelCountMask)) {
|
||||||
|
// Peel count provided, but peel count mask bit not set.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message_.partial_count() > 0 &&
|
||||||
|
!(message_.loop_control() & SpvLoopControlPartialCountMask)) {
|
||||||
|
// Partial count provided, but partial count mask bit not set.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must not set both 'don't unroll' and one of 'peel count' or 'partial
|
||||||
|
// count'.
|
||||||
|
return !((message_.loop_control() & SpvLoopControlDontUnrollMask) &&
|
||||||
|
(message_.loop_control() &
|
||||||
|
(SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransformationSetLoopControl::Apply(opt::IRContext* context,
|
||||||
|
FactManager* /*unused*/) const {
|
||||||
|
// Grab the loop merge instruction and its associated loop control mask.
|
||||||
|
auto merge_inst =
|
||||||
|
context->get_instr_block(message_.block_id())->GetMergeInst();
|
||||||
|
auto existing_loop_control_mask =
|
||||||
|
merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex);
|
||||||
|
|
||||||
|
// We are going to replace the OpLoopMerge's operands with this list.
|
||||||
|
opt::Instruction::OperandList new_operands;
|
||||||
|
// We add the existing merge block and continue target ids.
|
||||||
|
new_operands.push_back(merge_inst->GetInOperand(0));
|
||||||
|
new_operands.push_back(merge_inst->GetInOperand(1));
|
||||||
|
// We use the loop control mask from the transformation.
|
||||||
|
new_operands.push_back(
|
||||||
|
{SPV_OPERAND_TYPE_LOOP_CONTROL, {message_.loop_control()}});
|
||||||
|
|
||||||
|
// It remains to determine what literals to provide, in association with
|
||||||
|
// the new loop control mask.
|
||||||
|
//
|
||||||
|
// For the loop controls that require guarantees to hold about the number
|
||||||
|
// of loop iterations, we need to keep, from the original OpLoopMerge, any
|
||||||
|
// literals associated with loop control bits that are still set.
|
||||||
|
|
||||||
|
uint32_t literal_index = 0; // Indexes into the literals from the original
|
||||||
|
// instruction.
|
||||||
|
for (SpvLoopControlMask mask :
|
||||||
|
{SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
|
||||||
|
SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
|
||||||
|
// Check whether the bit was set in the original loop control mask.
|
||||||
|
if (existing_loop_control_mask & mask) {
|
||||||
|
// Check whether the bit is set in the new loop control mask.
|
||||||
|
if (message_.loop_control() & mask) {
|
||||||
|
// Add the associated literal to our sequence of replacement operands.
|
||||||
|
new_operands.push_back(
|
||||||
|
{SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||||
|
{merge_inst->GetSingleWordInOperand(
|
||||||
|
kLoopControlFirstLiteralInOperandIndex + literal_index)}});
|
||||||
|
}
|
||||||
|
// Increment our index into the original loop control mask's literals,
|
||||||
|
// whether or not the bit was set in the new mask.
|
||||||
|
literal_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If PeelCount is set in the new mask, |message_.peel_count| provides the
|
||||||
|
// associated peel count.
|
||||||
|
if (message_.loop_control() & SpvLoopControlPeelCountMask) {
|
||||||
|
new_operands.push_back(
|
||||||
|
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.peel_count()}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar, but for PartialCount.
|
||||||
|
if (message_.loop_control() & SpvLoopControlPartialCountMask) {
|
||||||
|
new_operands.push_back(
|
||||||
|
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.partial_count()}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the input operands of the OpLoopMerge with the new operands we have
|
||||||
|
// accumulated.
|
||||||
|
merge_inst->SetInOperands(std::move(new_operands));
|
||||||
|
}
|
||||||
|
|
||||||
|
protobufs::Transformation TransformationSetLoopControl::ToMessage() const {
|
||||||
|
protobufs::Transformation result;
|
||||||
|
*result.mutable_set_loop_control() = message_;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation(
|
||||||
|
SpvLoopControlMask loop_control_single_bit_mask,
|
||||||
|
uint32_t existing_loop_control_mask) const {
|
||||||
|
return !(loop_control_single_bit_mask & existing_loop_control_mask) &&
|
||||||
|
(loop_control_single_bit_mask & message_.loop_control());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransformationSetLoopControl::PartialCountIsSupported(
|
||||||
|
opt::IRContext* context) {
|
||||||
|
// TODO(afd): We capture the universal environments for which this loop
|
||||||
|
// control is definitely not supported. The check should be refined on
|
||||||
|
// demand for other target environments.
|
||||||
|
switch (context->grammar().target_env()) {
|
||||||
|
case SPV_ENV_UNIVERSAL_1_0:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_1:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_2:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_3:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransformationSetLoopControl::PeelCountIsSupported(
|
||||||
|
opt::IRContext* context) {
|
||||||
|
// TODO(afd): We capture the universal environments for which this loop
|
||||||
|
// control is definitely not supported. The check should be refined on
|
||||||
|
// demand for other target environments.
|
||||||
|
switch (context->grammar().target_env()) {
|
||||||
|
case SPV_ENV_UNIVERSAL_1_0:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_1:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_2:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_3:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fuzz
|
||||||
|
} // namespace spvtools
|
79
source/fuzz/transformation_set_loop_control.h
Normal file
79
source/fuzz/transformation_set_loop_control.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// 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_LOOP_CONTROL_H_
|
||||||
|
#define SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_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 TransformationSetLoopControl : public Transformation {
|
||||||
|
public:
|
||||||
|
const static uint32_t kLoopControlMaskInOperandIndex = 2;
|
||||||
|
const static uint32_t kLoopControlFirstLiteralInOperandIndex = 3;
|
||||||
|
|
||||||
|
explicit TransformationSetLoopControl(
|
||||||
|
const protobufs::TransformationSetLoopControl& message);
|
||||||
|
|
||||||
|
TransformationSetLoopControl(uint32_t block_id, uint32_t loop_control,
|
||||||
|
uint32_t peel_count, uint32_t partial_count);
|
||||||
|
|
||||||
|
// - |message_.block_id| must be a block containing an OpLoopMerge
|
||||||
|
// instruction.
|
||||||
|
// - |message_.loop_control| must be a legal loop control mask that
|
||||||
|
// only uses controls available in the SPIR-V version associated with
|
||||||
|
// |context|, and must not add loop controls that are only valid in the
|
||||||
|
// presence of guarantees about what the loop does (e.g. MinIterations).
|
||||||
|
// - |message_.peel_count| (respectively |message_.partial_count|) must be
|
||||||
|
// zero PeelCount (respectively PartialCount) is set in
|
||||||
|
// |message_.loop_control|.
|
||||||
|
bool IsApplicable(opt::IRContext* context,
|
||||||
|
const FactManager& fact_manager) const override;
|
||||||
|
|
||||||
|
// - The loop control operand of the OpLoopMergeInstruction in
|
||||||
|
// |message_.block_id| is overwritten with |message_.loop_control|.
|
||||||
|
// - The literals associated with the loop control are updated to reflect any
|
||||||
|
// controls with associated literals that have been removed (e.g.
|
||||||
|
// MinIterations), and any that have been added (PeelCount and/or
|
||||||
|
// PartialCount).
|
||||||
|
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||||
|
|
||||||
|
protobufs::Transformation ToMessage() const override;
|
||||||
|
|
||||||
|
// Does the version of SPIR-V being used support the PartialCount loop
|
||||||
|
// control?
|
||||||
|
static bool PartialCountIsSupported(opt::IRContext* context);
|
||||||
|
|
||||||
|
// Does the version of SPIR-V being used support the PeelCount loop control?
|
||||||
|
static bool PeelCountIsSupported(opt::IRContext* context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Returns true if and only if |loop_single_bit_mask| is *not* set in
|
||||||
|
// |existing_loop_control| but *is* set in |message_.loop_control|.
|
||||||
|
bool LoopControlBitIsAddedByTransformation(
|
||||||
|
SpvLoopControlMask loop_control_single_bit_mask,
|
||||||
|
uint32_t existing_loop_control_mask) const;
|
||||||
|
|
||||||
|
protobufs::TransformationSetLoopControl message_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fuzz
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_
|
@ -34,6 +34,7 @@ if (${SPIRV_BUILD_FUZZER})
|
|||||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||||
transformation_replace_constant_with_uniform_test.cpp
|
transformation_replace_constant_with_uniform_test.cpp
|
||||||
transformation_replace_id_with_synonym_test.cpp
|
transformation_replace_id_with_synonym_test.cpp
|
||||||
|
transformation_set_loop_control_test.cpp
|
||||||
transformation_set_selection_control_test.cpp
|
transformation_set_selection_control_test.cpp
|
||||||
transformation_split_block_test.cpp
|
transformation_split_block_test.cpp
|
||||||
uniform_buffer_element_descriptor_test.cpp)
|
uniform_buffer_element_descriptor_test.cpp)
|
||||||
|
@ -31,7 +31,7 @@ const uint32_t kNumFuzzerRuns = 20;
|
|||||||
void RunFuzzerAndReplayer(const std::string& shader,
|
void RunFuzzerAndReplayer(const std::string& shader,
|
||||||
const protobufs::FactSequence& initial_facts,
|
const protobufs::FactSequence& initial_facts,
|
||||||
uint32_t initial_seed, uint32_t num_runs) {
|
uint32_t initial_seed, uint32_t num_runs) {
|
||||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
const auto env = SPV_ENV_UNIVERSAL_1_5;
|
||||||
|
|
||||||
std::vector<uint32_t> binary_in;
|
std::vector<uint32_t> binary_in;
|
||||||
SpirvTools t(env);
|
SpirvTools t(env);
|
||||||
@ -305,7 +305,7 @@ TEST(FuzzerReplayerTest, Miscellaneous2) {
|
|||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint Fragment %4 "main" %16 %139
|
OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
OpSource ESSL 310
|
OpSource ESSL 310
|
||||||
OpName %4 "main"
|
OpName %4 "main"
|
||||||
@ -605,7 +605,7 @@ TEST(FuzzerReplayerTest, Miscellaneous3) {
|
|||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint Fragment %4 "main" %68 %100
|
OpEntryPoint Fragment %4 "main" %68 %100 %24
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
OpSource ESSL 310
|
OpSource ESSL 310
|
||||||
OpName %4 "main"
|
OpName %4 "main"
|
||||||
|
@ -154,7 +154,7 @@ void RunAndCheckShrinker(
|
|||||||
void RunFuzzerAndShrinker(const std::string& shader,
|
void RunFuzzerAndShrinker(const std::string& shader,
|
||||||
const protobufs::FactSequence& initial_facts,
|
const protobufs::FactSequence& initial_facts,
|
||||||
uint32_t seed) {
|
uint32_t seed) {
|
||||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
const auto env = SPV_ENV_UNIVERSAL_1_5;
|
||||||
|
|
||||||
std::vector<uint32_t> binary_in;
|
std::vector<uint32_t> binary_in;
|
||||||
SpirvTools t(env);
|
SpirvTools t(env);
|
||||||
@ -434,7 +434,7 @@ TEST(FuzzerShrinkerTest, Miscellaneous2) {
|
|||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint Fragment %4 "main" %16 %139
|
OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
OpSource ESSL 310
|
OpSource ESSL 310
|
||||||
OpName %4 "main"
|
OpName %4 "main"
|
||||||
@ -732,7 +732,7 @@ TEST(FuzzerShrinkerTest, Miscellaneous3) {
|
|||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint Fragment %4 "main" %68 %100
|
OpEntryPoint Fragment %4 "main" %68 %100 %24
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
OpSource ESSL 310
|
OpSource ESSL 310
|
||||||
OpName %4 "main"
|
OpName %4 "main"
|
||||||
|
968
test/fuzz/transformation_set_loop_control_test.cpp
Normal file
968
test/fuzz/transformation_set_loop_control_test.cpp
Normal file
@ -0,0 +1,968 @@
|
|||||||
|
// 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_loop_control.h"
|
||||||
|
#include "test/fuzz/fuzz_test_util.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace fuzz {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(TransformationSetLoopControlTest, VariousScenarios) {
|
||||||
|
// This test features loops with various different controls, and goes through
|
||||||
|
// a number of acceptable and unacceptable transformations to those controls.
|
||||||
|
|
||||||
|
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"
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%6 = OpTypeInt 32 1
|
||||||
|
%7 = OpTypePointer Function %6
|
||||||
|
%9 = OpConstant %6 0
|
||||||
|
%16 = OpConstant %6 100
|
||||||
|
%17 = OpTypeBool
|
||||||
|
%20 = OpConstant %6 1
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%8 = OpVariable %7 Function
|
||||||
|
%22 = OpVariable %7 Function
|
||||||
|
%32 = OpVariable %7 Function
|
||||||
|
%42 = OpVariable %7 Function
|
||||||
|
%52 = OpVariable %7 Function
|
||||||
|
%62 = OpVariable %7 Function
|
||||||
|
%72 = OpVariable %7 Function
|
||||||
|
%82 = OpVariable %7 Function
|
||||||
|
%92 = OpVariable %7 Function
|
||||||
|
%102 = OpVariable %7 Function
|
||||||
|
%112 = OpVariable %7 Function
|
||||||
|
%122 = OpVariable %7 Function
|
||||||
|
OpStore %8 %9
|
||||||
|
OpBranch %10
|
||||||
|
%10 = OpLabel
|
||||||
|
%132 = OpPhi %6 %9 %5 %21 %13
|
||||||
|
OpLoopMerge %12 %13 None
|
||||||
|
OpBranch %14
|
||||||
|
%14 = OpLabel
|
||||||
|
%18 = OpSLessThan %17 %132 %16
|
||||||
|
OpBranchConditional %18 %11 %12
|
||||||
|
%11 = OpLabel
|
||||||
|
OpBranch %13
|
||||||
|
%13 = OpLabel
|
||||||
|
%21 = OpIAdd %6 %132 %20
|
||||||
|
OpStore %8 %21
|
||||||
|
OpBranch %10
|
||||||
|
%12 = OpLabel
|
||||||
|
OpStore %22 %9
|
||||||
|
OpBranch %23
|
||||||
|
%23 = OpLabel
|
||||||
|
%133 = OpPhi %6 %9 %12 %31 %26
|
||||||
|
OpLoopMerge %25 %26 Unroll
|
||||||
|
OpBranch %27
|
||||||
|
%27 = OpLabel
|
||||||
|
%29 = OpSLessThan %17 %133 %16
|
||||||
|
OpBranchConditional %29 %24 %25
|
||||||
|
%24 = OpLabel
|
||||||
|
OpBranch %26
|
||||||
|
%26 = OpLabel
|
||||||
|
%31 = OpIAdd %6 %133 %20
|
||||||
|
OpStore %22 %31
|
||||||
|
OpBranch %23
|
||||||
|
%25 = OpLabel
|
||||||
|
OpStore %32 %9
|
||||||
|
OpBranch %33
|
||||||
|
%33 = OpLabel
|
||||||
|
%134 = OpPhi %6 %9 %25 %41 %36
|
||||||
|
OpLoopMerge %35 %36 DontUnroll
|
||||||
|
OpBranch %37
|
||||||
|
%37 = OpLabel
|
||||||
|
%39 = OpSLessThan %17 %134 %16
|
||||||
|
OpBranchConditional %39 %34 %35
|
||||||
|
%34 = OpLabel
|
||||||
|
OpBranch %36
|
||||||
|
%36 = OpLabel
|
||||||
|
%41 = OpIAdd %6 %134 %20
|
||||||
|
OpStore %32 %41
|
||||||
|
OpBranch %33
|
||||||
|
%35 = OpLabel
|
||||||
|
OpStore %42 %9
|
||||||
|
OpBranch %43
|
||||||
|
%43 = OpLabel
|
||||||
|
%135 = OpPhi %6 %9 %35 %51 %46
|
||||||
|
OpLoopMerge %45 %46 DependencyInfinite
|
||||||
|
OpBranch %47
|
||||||
|
%47 = OpLabel
|
||||||
|
%49 = OpSLessThan %17 %135 %16
|
||||||
|
OpBranchConditional %49 %44 %45
|
||||||
|
%44 = OpLabel
|
||||||
|
OpBranch %46
|
||||||
|
%46 = OpLabel
|
||||||
|
%51 = OpIAdd %6 %135 %20
|
||||||
|
OpStore %42 %51
|
||||||
|
OpBranch %43
|
||||||
|
%45 = OpLabel
|
||||||
|
OpStore %52 %9
|
||||||
|
OpBranch %53
|
||||||
|
%53 = OpLabel
|
||||||
|
%136 = OpPhi %6 %9 %45 %61 %56
|
||||||
|
OpLoopMerge %55 %56 DependencyLength 3
|
||||||
|
OpBranch %57
|
||||||
|
%57 = OpLabel
|
||||||
|
%59 = OpSLessThan %17 %136 %16
|
||||||
|
OpBranchConditional %59 %54 %55
|
||||||
|
%54 = OpLabel
|
||||||
|
OpBranch %56
|
||||||
|
%56 = OpLabel
|
||||||
|
%61 = OpIAdd %6 %136 %20
|
||||||
|
OpStore %52 %61
|
||||||
|
OpBranch %53
|
||||||
|
%55 = OpLabel
|
||||||
|
OpStore %62 %9
|
||||||
|
OpBranch %63
|
||||||
|
%63 = OpLabel
|
||||||
|
%137 = OpPhi %6 %9 %55 %71 %66
|
||||||
|
OpLoopMerge %65 %66 MinIterations 10
|
||||||
|
OpBranch %67
|
||||||
|
%67 = OpLabel
|
||||||
|
%69 = OpSLessThan %17 %137 %16
|
||||||
|
OpBranchConditional %69 %64 %65
|
||||||
|
%64 = OpLabel
|
||||||
|
OpBranch %66
|
||||||
|
%66 = OpLabel
|
||||||
|
%71 = OpIAdd %6 %137 %20
|
||||||
|
OpStore %62 %71
|
||||||
|
OpBranch %63
|
||||||
|
%65 = OpLabel
|
||||||
|
OpStore %72 %9
|
||||||
|
OpBranch %73
|
||||||
|
%73 = OpLabel
|
||||||
|
%138 = OpPhi %6 %9 %65 %81 %76
|
||||||
|
OpLoopMerge %75 %76 MaxIterations 50
|
||||||
|
OpBranch %77
|
||||||
|
%77 = OpLabel
|
||||||
|
%79 = OpSLessThan %17 %138 %16
|
||||||
|
OpBranchConditional %79 %74 %75
|
||||||
|
%74 = OpLabel
|
||||||
|
OpBranch %76
|
||||||
|
%76 = OpLabel
|
||||||
|
%81 = OpIAdd %6 %138 %20
|
||||||
|
OpStore %72 %81
|
||||||
|
OpBranch %73
|
||||||
|
%75 = OpLabel
|
||||||
|
OpStore %82 %9
|
||||||
|
OpBranch %83
|
||||||
|
%83 = OpLabel
|
||||||
|
%139 = OpPhi %6 %9 %75 %91 %86
|
||||||
|
OpLoopMerge %85 %86 IterationMultiple 4
|
||||||
|
OpBranch %87
|
||||||
|
%87 = OpLabel
|
||||||
|
%89 = OpSLessThan %17 %139 %16
|
||||||
|
OpBranchConditional %89 %84 %85
|
||||||
|
%84 = OpLabel
|
||||||
|
OpBranch %86
|
||||||
|
%86 = OpLabel
|
||||||
|
%91 = OpIAdd %6 %139 %20
|
||||||
|
OpStore %82 %91
|
||||||
|
OpBranch %83
|
||||||
|
%85 = OpLabel
|
||||||
|
OpStore %92 %9
|
||||||
|
OpBranch %93
|
||||||
|
%93 = OpLabel
|
||||||
|
%140 = OpPhi %6 %9 %85 %101 %96
|
||||||
|
OpLoopMerge %95 %96 PeelCount 2
|
||||||
|
OpBranch %97
|
||||||
|
%97 = OpLabel
|
||||||
|
%99 = OpSLessThan %17 %140 %16
|
||||||
|
OpBranchConditional %99 %94 %95
|
||||||
|
%94 = OpLabel
|
||||||
|
OpBranch %96
|
||||||
|
%96 = OpLabel
|
||||||
|
%101 = OpIAdd %6 %140 %20
|
||||||
|
OpStore %92 %101
|
||||||
|
OpBranch %93
|
||||||
|
%95 = OpLabel
|
||||||
|
OpStore %102 %9
|
||||||
|
OpBranch %103
|
||||||
|
%103 = OpLabel
|
||||||
|
%141 = OpPhi %6 %9 %95 %111 %106
|
||||||
|
OpLoopMerge %105 %106 PartialCount 3
|
||||||
|
OpBranch %107
|
||||||
|
%107 = OpLabel
|
||||||
|
%109 = OpSLessThan %17 %141 %16
|
||||||
|
OpBranchConditional %109 %104 %105
|
||||||
|
%104 = OpLabel
|
||||||
|
OpBranch %106
|
||||||
|
%106 = OpLabel
|
||||||
|
%111 = OpIAdd %6 %141 %20
|
||||||
|
OpStore %102 %111
|
||||||
|
OpBranch %103
|
||||||
|
%105 = OpLabel
|
||||||
|
OpStore %112 %9
|
||||||
|
OpBranch %113
|
||||||
|
%113 = OpLabel
|
||||||
|
%142 = OpPhi %6 %9 %105 %121 %116
|
||||||
|
OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
|
||||||
|
OpBranch %117
|
||||||
|
%117 = OpLabel
|
||||||
|
%119 = OpSLessThan %17 %142 %16
|
||||||
|
OpBranchConditional %119 %114 %115
|
||||||
|
%114 = OpLabel
|
||||||
|
OpBranch %116
|
||||||
|
%116 = OpLabel
|
||||||
|
%121 = OpIAdd %6 %142 %20
|
||||||
|
OpStore %112 %121
|
||||||
|
OpBranch %113
|
||||||
|
%115 = OpLabel
|
||||||
|
OpStore %122 %9
|
||||||
|
OpBranch %123
|
||||||
|
%123 = OpLabel
|
||||||
|
%143 = OpPhi %6 %9 %115 %131 %126
|
||||||
|
OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
|
||||||
|
OpBranch %127
|
||||||
|
%127 = OpLabel
|
||||||
|
%129 = OpSLessThan %17 %143 %16
|
||||||
|
OpBranchConditional %129 %124 %125
|
||||||
|
%124 = OpLabel
|
||||||
|
OpBranch %126
|
||||||
|
%126 = OpLabel
|
||||||
|
%131 = OpIAdd %6 %143 %20
|
||||||
|
OpStore %122 %131
|
||||||
|
OpBranch %123
|
||||||
|
%125 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||||
|
const auto consumer = nullptr;
|
||||||
|
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||||
|
|
||||||
|
ASSERT_TRUE(IsValid(env, context.get()));
|
||||||
|
|
||||||
|
FactManager fact_manager;
|
||||||
|
|
||||||
|
// These are the loop headers together with the selection controls of their
|
||||||
|
// merge instructions:
|
||||||
|
// %10 None
|
||||||
|
// %23 Unroll
|
||||||
|
// %33 DontUnroll
|
||||||
|
// %43 DependencyInfinite
|
||||||
|
// %53 DependencyLength 3
|
||||||
|
// %63 MinIterations 10
|
||||||
|
// %73 MaxIterations 50
|
||||||
|
// %83 IterationMultiple 4
|
||||||
|
// %93 PeelCount 2
|
||||||
|
// %103 PartialCount 3
|
||||||
|
// %113 Unroll|PeelCount|PartialCount 3 4
|
||||||
|
// %123
|
||||||
|
// DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
|
||||||
|
// 2 5 90 4 7 14
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
10, SpvLoopControlDependencyInfiniteMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlDependencyLengthMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlMinIterationsMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlMaxIterationsMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
10, SpvLoopControlIterationMultipleMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 0, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(
|
||||||
|
10,
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||||
|
3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(10,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(10,
|
||||||
|
SpvLoopControlDontUnrollMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(
|
||||||
|
23,
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||||
|
3, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(23, SpvLoopControlMaxIterationsMask, 2, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(33, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(33, SpvLoopControlMinIterationsMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
33, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(33,
|
||||||
|
SpvLoopControlDontUnrollMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
0, 10)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(43, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(
|
||||||
|
43,
|
||||||
|
SpvLoopControlMaskNone | SpvLoopControlDependencyInfiniteMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
43, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
43,
|
||||||
|
SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(43,
|
||||||
|
SpvLoopControlDependencyInfiniteMask |
|
||||||
|
SpvLoopControlDependencyLengthMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
43, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(53, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(53, SpvLoopControlMaxIterationsMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
53, SpvLoopControlMaskNone | SpvLoopControlDependencyLengthMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
53, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
53, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyLengthMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(53,
|
||||||
|
SpvLoopControlDependencyInfiniteMask |
|
||||||
|
SpvLoopControlDependencyLengthMask,
|
||||||
|
0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
53,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlDependencyLengthMask |
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||||
|
5, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(63, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(63,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
5, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(63,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
23, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
63,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
2, 23)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(73, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
73,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
5, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(73,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
23, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
73,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
2, 23)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
83,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
5, 3)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(83,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlIterationMultipleMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
23, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(83,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlIterationMultipleMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
2, 23)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(93, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 8)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(93, SpvLoopControlPartialCountMask, 0, 8)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(
|
||||||
|
93,
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||||
|
16, 8)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(103, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(103,
|
||||||
|
SpvLoopControlDontUnrollMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
0, 60)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(113, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
113,
|
||||||
|
SpvLoopControlIterationMultipleMask | SpvLoopControlPeelCountMask, 12,
|
||||||
|
0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(123, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
123,
|
||||||
|
SpvLoopControlMinIterationsMask | SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlIterationMultipleMask |
|
||||||
|
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||||
|
7, 8)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(TransformationSetLoopControl(123,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
0, 9)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(TransformationSetLoopControl(
|
||||||
|
123,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
7, 9)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
123,
|
||||||
|
SpvLoopControlDontUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
|
||||||
|
7, 9)
|
||||||
|
.IsApplicable(context.get(), fact_manager));
|
||||||
|
|
||||||
|
TransformationSetLoopControl(10,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlPeelCountMask |
|
||||||
|
SpvLoopControlPartialCountMask,
|
||||||
|
3, 3)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
43, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||||
|
0, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(63,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
23, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(73,
|
||||||
|
SpvLoopControlUnrollMask |
|
||||||
|
SpvLoopControlMaxIterationsMask |
|
||||||
|
SpvLoopControlPeelCountMask,
|
||||||
|
23, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
93, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 16, 8)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
|
||||||
|
.Apply(context.get(), &fact_manager);
|
||||||
|
TransformationSetLoopControl(
|
||||||
|
123,
|
||||||
|
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||||
|
SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
|
||||||
|
0, 9)
|
||||||
|
.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"
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%6 = OpTypeInt 32 1
|
||||||
|
%7 = OpTypePointer Function %6
|
||||||
|
%9 = OpConstant %6 0
|
||||||
|
%16 = OpConstant %6 100
|
||||||
|
%17 = OpTypeBool
|
||||||
|
%20 = OpConstant %6 1
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%8 = OpVariable %7 Function
|
||||||
|
%22 = OpVariable %7 Function
|
||||||
|
%32 = OpVariable %7 Function
|
||||||
|
%42 = OpVariable %7 Function
|
||||||
|
%52 = OpVariable %7 Function
|
||||||
|
%62 = OpVariable %7 Function
|
||||||
|
%72 = OpVariable %7 Function
|
||||||
|
%82 = OpVariable %7 Function
|
||||||
|
%92 = OpVariable %7 Function
|
||||||
|
%102 = OpVariable %7 Function
|
||||||
|
%112 = OpVariable %7 Function
|
||||||
|
%122 = OpVariable %7 Function
|
||||||
|
OpStore %8 %9
|
||||||
|
OpBranch %10
|
||||||
|
%10 = OpLabel
|
||||||
|
%132 = OpPhi %6 %9 %5 %21 %13
|
||||||
|
OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
|
||||||
|
OpBranch %14
|
||||||
|
%14 = OpLabel
|
||||||
|
%18 = OpSLessThan %17 %132 %16
|
||||||
|
OpBranchConditional %18 %11 %12
|
||||||
|
%11 = OpLabel
|
||||||
|
OpBranch %13
|
||||||
|
%13 = OpLabel
|
||||||
|
%21 = OpIAdd %6 %132 %20
|
||||||
|
OpStore %8 %21
|
||||||
|
OpBranch %10
|
||||||
|
%12 = OpLabel
|
||||||
|
OpStore %22 %9
|
||||||
|
OpBranch %23
|
||||||
|
%23 = OpLabel
|
||||||
|
%133 = OpPhi %6 %9 %12 %31 %26
|
||||||
|
OpLoopMerge %25 %26 DontUnroll
|
||||||
|
OpBranch %27
|
||||||
|
%27 = OpLabel
|
||||||
|
%29 = OpSLessThan %17 %133 %16
|
||||||
|
OpBranchConditional %29 %24 %25
|
||||||
|
%24 = OpLabel
|
||||||
|
OpBranch %26
|
||||||
|
%26 = OpLabel
|
||||||
|
%31 = OpIAdd %6 %133 %20
|
||||||
|
OpStore %22 %31
|
||||||
|
OpBranch %23
|
||||||
|
%25 = OpLabel
|
||||||
|
OpStore %32 %9
|
||||||
|
OpBranch %33
|
||||||
|
%33 = OpLabel
|
||||||
|
%134 = OpPhi %6 %9 %25 %41 %36
|
||||||
|
OpLoopMerge %35 %36 Unroll
|
||||||
|
OpBranch %37
|
||||||
|
%37 = OpLabel
|
||||||
|
%39 = OpSLessThan %17 %134 %16
|
||||||
|
OpBranchConditional %39 %34 %35
|
||||||
|
%34 = OpLabel
|
||||||
|
OpBranch %36
|
||||||
|
%36 = OpLabel
|
||||||
|
%41 = OpIAdd %6 %134 %20
|
||||||
|
OpStore %32 %41
|
||||||
|
OpBranch %33
|
||||||
|
%35 = OpLabel
|
||||||
|
OpStore %42 %9
|
||||||
|
OpBranch %43
|
||||||
|
%43 = OpLabel
|
||||||
|
%135 = OpPhi %6 %9 %35 %51 %46
|
||||||
|
OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
|
||||||
|
OpBranch %47
|
||||||
|
%47 = OpLabel
|
||||||
|
%49 = OpSLessThan %17 %135 %16
|
||||||
|
OpBranchConditional %49 %44 %45
|
||||||
|
%44 = OpLabel
|
||||||
|
OpBranch %46
|
||||||
|
%46 = OpLabel
|
||||||
|
%51 = OpIAdd %6 %135 %20
|
||||||
|
OpStore %42 %51
|
||||||
|
OpBranch %43
|
||||||
|
%45 = OpLabel
|
||||||
|
OpStore %52 %9
|
||||||
|
OpBranch %53
|
||||||
|
%53 = OpLabel
|
||||||
|
%136 = OpPhi %6 %9 %45 %61 %56
|
||||||
|
OpLoopMerge %55 %56 None
|
||||||
|
OpBranch %57
|
||||||
|
%57 = OpLabel
|
||||||
|
%59 = OpSLessThan %17 %136 %16
|
||||||
|
OpBranchConditional %59 %54 %55
|
||||||
|
%54 = OpLabel
|
||||||
|
OpBranch %56
|
||||||
|
%56 = OpLabel
|
||||||
|
%61 = OpIAdd %6 %136 %20
|
||||||
|
OpStore %52 %61
|
||||||
|
OpBranch %53
|
||||||
|
%55 = OpLabel
|
||||||
|
OpStore %62 %9
|
||||||
|
OpBranch %63
|
||||||
|
%63 = OpLabel
|
||||||
|
%137 = OpPhi %6 %9 %55 %71 %66
|
||||||
|
OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
|
||||||
|
OpBranch %67
|
||||||
|
%67 = OpLabel
|
||||||
|
%69 = OpSLessThan %17 %137 %16
|
||||||
|
OpBranchConditional %69 %64 %65
|
||||||
|
%64 = OpLabel
|
||||||
|
OpBranch %66
|
||||||
|
%66 = OpLabel
|
||||||
|
%71 = OpIAdd %6 %137 %20
|
||||||
|
OpStore %62 %71
|
||||||
|
OpBranch %63
|
||||||
|
%65 = OpLabel
|
||||||
|
OpStore %72 %9
|
||||||
|
OpBranch %73
|
||||||
|
%73 = OpLabel
|
||||||
|
%138 = OpPhi %6 %9 %65 %81 %76
|
||||||
|
OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
|
||||||
|
OpBranch %77
|
||||||
|
%77 = OpLabel
|
||||||
|
%79 = OpSLessThan %17 %138 %16
|
||||||
|
OpBranchConditional %79 %74 %75
|
||||||
|
%74 = OpLabel
|
||||||
|
OpBranch %76
|
||||||
|
%76 = OpLabel
|
||||||
|
%81 = OpIAdd %6 %138 %20
|
||||||
|
OpStore %72 %81
|
||||||
|
OpBranch %73
|
||||||
|
%75 = OpLabel
|
||||||
|
OpStore %82 %9
|
||||||
|
OpBranch %83
|
||||||
|
%83 = OpLabel
|
||||||
|
%139 = OpPhi %6 %9 %75 %91 %86
|
||||||
|
OpLoopMerge %85 %86 DontUnroll
|
||||||
|
OpBranch %87
|
||||||
|
%87 = OpLabel
|
||||||
|
%89 = OpSLessThan %17 %139 %16
|
||||||
|
OpBranchConditional %89 %84 %85
|
||||||
|
%84 = OpLabel
|
||||||
|
OpBranch %86
|
||||||
|
%86 = OpLabel
|
||||||
|
%91 = OpIAdd %6 %139 %20
|
||||||
|
OpStore %82 %91
|
||||||
|
OpBranch %83
|
||||||
|
%85 = OpLabel
|
||||||
|
OpStore %92 %9
|
||||||
|
OpBranch %93
|
||||||
|
%93 = OpLabel
|
||||||
|
%140 = OpPhi %6 %9 %85 %101 %96
|
||||||
|
OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
|
||||||
|
OpBranch %97
|
||||||
|
%97 = OpLabel
|
||||||
|
%99 = OpSLessThan %17 %140 %16
|
||||||
|
OpBranchConditional %99 %94 %95
|
||||||
|
%94 = OpLabel
|
||||||
|
OpBranch %96
|
||||||
|
%96 = OpLabel
|
||||||
|
%101 = OpIAdd %6 %140 %20
|
||||||
|
OpStore %92 %101
|
||||||
|
OpBranch %93
|
||||||
|
%95 = OpLabel
|
||||||
|
OpStore %102 %9
|
||||||
|
OpBranch %103
|
||||||
|
%103 = OpLabel
|
||||||
|
%141 = OpPhi %6 %9 %95 %111 %106
|
||||||
|
OpLoopMerge %105 %106 PartialCount 60
|
||||||
|
OpBranch %107
|
||||||
|
%107 = OpLabel
|
||||||
|
%109 = OpSLessThan %17 %141 %16
|
||||||
|
OpBranchConditional %109 %104 %105
|
||||||
|
%104 = OpLabel
|
||||||
|
OpBranch %106
|
||||||
|
%106 = OpLabel
|
||||||
|
%111 = OpIAdd %6 %141 %20
|
||||||
|
OpStore %102 %111
|
||||||
|
OpBranch %103
|
||||||
|
%105 = OpLabel
|
||||||
|
OpStore %112 %9
|
||||||
|
OpBranch %113
|
||||||
|
%113 = OpLabel
|
||||||
|
%142 = OpPhi %6 %9 %105 %121 %116
|
||||||
|
OpLoopMerge %115 %116 PeelCount 12
|
||||||
|
OpBranch %117
|
||||||
|
%117 = OpLabel
|
||||||
|
%119 = OpSLessThan %17 %142 %16
|
||||||
|
OpBranchConditional %119 %114 %115
|
||||||
|
%114 = OpLabel
|
||||||
|
OpBranch %116
|
||||||
|
%116 = OpLabel
|
||||||
|
%121 = OpIAdd %6 %142 %20
|
||||||
|
OpStore %112 %121
|
||||||
|
OpBranch %113
|
||||||
|
%115 = OpLabel
|
||||||
|
OpStore %122 %9
|
||||||
|
OpBranch %123
|
||||||
|
%123 = OpLabel
|
||||||
|
%143 = OpPhi %6 %9 %115 %131 %126
|
||||||
|
OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
|
||||||
|
OpBranch %127
|
||||||
|
%127 = OpLabel
|
||||||
|
%129 = OpSLessThan %17 %143 %16
|
||||||
|
OpBranchConditional %129 %124 %125
|
||||||
|
%124 = OpLabel
|
||||||
|
OpBranch %126
|
||||||
|
%126 = OpLabel
|
||||||
|
%131 = OpIAdd %6 %143 %20
|
||||||
|
OpStore %122 %131
|
||||||
|
OpBranch %123
|
||||||
|
%125 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
|
||||||
|
// This test checks that we do not allow introducing PeelCount and
|
||||||
|
// PartialCount loop controls if the SPIR-V version being used does not
|
||||||
|
// support them.
|
||||||
|
|
||||||
|
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 1
|
||||||
|
%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
|
||||||
|
OpBranch %13
|
||||||
|
%13 = OpLabel
|
||||||
|
%19 = OpLoad %6 %8
|
||||||
|
%21 = OpIAdd %6 %19 %20
|
||||||
|
OpStore %8 %21
|
||||||
|
OpBranch %10
|
||||||
|
%12 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
const auto consumer = nullptr;
|
||||||
|
const auto context_1_0 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_0, consumer, shader, kFuzzAssembleOption);
|
||||||
|
const auto context_1_1 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, shader, kFuzzAssembleOption);
|
||||||
|
const auto context_1_2 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer, shader, kFuzzAssembleOption);
|
||||||
|
const auto context_1_3 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer, shader, kFuzzAssembleOption);
|
||||||
|
const auto context_1_4 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_4, consumer, shader, kFuzzAssembleOption);
|
||||||
|
const auto context_1_5 =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_5, consumer, shader, kFuzzAssembleOption);
|
||||||
|
|
||||||
|
FactManager fact_manager;
|
||||||
|
|
||||||
|
TransformationSetLoopControl set_peel_and_partial(
|
||||||
|
10, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 4, 4);
|
||||||
|
|
||||||
|
// PeelCount and PartialCount were introduced in SPIRV 1.4, so are not valid
|
||||||
|
// in the context of older versions.
|
||||||
|
ASSERT_FALSE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_0.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_1.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_2.get(), fact_manager));
|
||||||
|
ASSERT_FALSE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_3.get(), fact_manager));
|
||||||
|
|
||||||
|
ASSERT_TRUE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_4.get(), fact_manager));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
set_peel_and_partial.IsApplicable(context_1_5.get(), fact_manager));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace fuzz
|
||||||
|
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user