mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-25 04:50:04 +00:00
spirv-fuzz: Fuzzer passes to add local and global variables (#3175)
Adds two new fuzzer passes to add variables to a module: one that adds Private storage class global variables, another that adds Function storage class local variables.
This commit is contained in:
parent
9e52bc0d0c
commit
1f03ac1027
@ -40,6 +40,8 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_add_dead_blocks.h
|
||||
fuzzer_pass_add_dead_breaks.h
|
||||
fuzzer_pass_add_dead_continues.h
|
||||
fuzzer_pass_add_global_variables.h
|
||||
fuzzer_pass_add_local_variables.h
|
||||
fuzzer_pass_add_no_contraction_decorations.h
|
||||
fuzzer_pass_add_useful_constructs.h
|
||||
fuzzer_pass_adjust_function_controls.h
|
||||
@ -74,6 +76,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_function.h
|
||||
transformation_add_global_undef.h
|
||||
transformation_add_global_variable.h
|
||||
transformation_add_local_variable.h
|
||||
transformation_add_no_contraction_decoration.h
|
||||
transformation_add_type_array.h
|
||||
transformation_add_type_boolean.h
|
||||
@ -112,6 +115,8 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_add_dead_blocks.cpp
|
||||
fuzzer_pass_add_dead_breaks.cpp
|
||||
fuzzer_pass_add_dead_continues.cpp
|
||||
fuzzer_pass_add_global_variables.cpp
|
||||
fuzzer_pass_add_local_variables.cpp
|
||||
fuzzer_pass_add_no_contraction_decorations.cpp
|
||||
fuzzer_pass_add_useful_constructs.cpp
|
||||
fuzzer_pass_adjust_function_controls.cpp
|
||||
@ -145,6 +150,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_function.cpp
|
||||
transformation_add_global_undef.cpp
|
||||
transformation_add_global_variable.cpp
|
||||
transformation_add_local_variable.cpp
|
||||
transformation_add_no_contraction_decoration.cpp
|
||||
transformation_add_type_array.cpp
|
||||
transformation_add_type_boolean.cpp
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "source/fuzz/fuzzer_pass_add_dead_blocks.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_global_variables.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_local_variables.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||
#include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
|
||||
@ -191,6 +193,12 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassAddDeadContinues>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddGlobalVariables>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddLocalVariables>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassApplyIdSynonyms>(&passes, ir_context.get(),
|
||||
&fact_manager, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
|
@ -29,6 +29,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBlock = {20, 90};
|
||||
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> kChanceOfAddingGlobalVariable = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
|
||||
5, 70};
|
||||
@ -88,6 +90,10 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
|
||||
chance_of_adding_dead_continue_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
|
||||
chance_of_adding_global_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
|
||||
chance_of_adding_local_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
|
||||
chance_of_adding_matrix_type_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingMatrixType);
|
||||
chance_of_adding_no_contraction_decoration_ =
|
||||
|
@ -69,6 +69,12 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfAddingDeadContinue() {
|
||||
return chance_of_adding_dead_continue_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingGlobalVariable() {
|
||||
return chance_of_adding_global_variable_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingLocalVariable() {
|
||||
return chance_of_adding_local_variable_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingMatrixType() {
|
||||
return chance_of_adding_matrix_type_;
|
||||
}
|
||||
@ -148,6 +154,8 @@ class FuzzerContext {
|
||||
uint32_t chance_of_adding_dead_block_;
|
||||
uint32_t chance_of_adding_dead_break_;
|
||||
uint32_t chance_of_adding_dead_continue_;
|
||||
uint32_t chance_of_adding_global_variable_;
|
||||
uint32_t chance_of_adding_local_variable_;
|
||||
uint32_t chance_of_adding_matrix_type_;
|
||||
uint32_t chance_of_adding_no_contraction_decoration_;
|
||||
uint32_t chance_of_adding_vector_type_;
|
||||
|
@ -14,7 +14,10 @@
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_add_constant_boolean.h"
|
||||
#include "source/fuzz/transformation_add_constant_composite.h"
|
||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
||||
#include "source/fuzz/transformation_add_global_undef.h"
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
@ -243,6 +246,42 @@ uint32_t FuzzerPass::FindOrCreate32BitIntegerConstant(uint32_t word,
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreate32BitFloatConstant(uint32_t word) {
|
||||
auto float_type_id = FindOrCreate32BitFloatType();
|
||||
opt::analysis::FloatConstant float_constant(
|
||||
GetIRContext()->get_type_mgr()->GetType(float_type_id)->AsFloat(),
|
||||
{word});
|
||||
auto existing_constant =
|
||||
GetIRContext()->get_constant_mgr()->FindConstant(&float_constant);
|
||||
if (existing_constant) {
|
||||
return GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->GetDefiningInstruction(existing_constant)
|
||||
->result_id();
|
||||
}
|
||||
auto result = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(
|
||||
TransformationAddConstantScalar(result, float_type_id, {word}));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateBoolConstant(bool value) {
|
||||
auto bool_type_id = FindOrCreateBoolType();
|
||||
opt::analysis::BoolConstant bool_constant(
|
||||
GetIRContext()->get_type_mgr()->GetType(bool_type_id)->AsBool(), value);
|
||||
auto existing_constant =
|
||||
GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant);
|
||||
if (existing_constant) {
|
||||
return GetIRContext()
|
||||
->get_constant_mgr()
|
||||
->GetDefiningInstruction(existing_constant)
|
||||
->result_id();
|
||||
}
|
||||
auto result = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddConstantBoolean(result, value));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
|
||||
for (auto& inst : GetIRContext()->types_values()) {
|
||||
if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
|
||||
@ -254,5 +293,147 @@ uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
|
||||
FuzzerPass::GetAvailableBaseTypesAndPointers(
|
||||
SpvStorageClass storage_class) const {
|
||||
// Records all of the base types available in the module.
|
||||
std::vector<uint32_t> base_types;
|
||||
|
||||
// For each base type, records all the associated pointer types that target
|
||||
// that base type and that have |storage_class| as their storage class.
|
||||
std::map<uint32_t, std::vector<uint32_t>> base_type_to_pointers;
|
||||
|
||||
for (auto& inst : GetIRContext()->types_values()) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeStruct:
|
||||
case SpvOpTypeVector:
|
||||
// These types are suitable as pointer base types. Record the type,
|
||||
// and the fact that we cannot yet have seen any pointers that use this
|
||||
// as its base type.
|
||||
base_types.push_back(inst.result_id());
|
||||
base_type_to_pointers.insert({inst.result_id(), {}});
|
||||
break;
|
||||
case SpvOpTypePointer:
|
||||
if (inst.GetSingleWordInOperand(0) == storage_class) {
|
||||
// The pointer has the desired storage class, so we are interested in
|
||||
// it. Associate it with its base type.
|
||||
base_type_to_pointers.at(inst.GetSingleWordInOperand(1))
|
||||
.push_back(inst.result_id());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {base_types, base_type_to_pointers};
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateZeroConstant(
|
||||
uint32_t scalar_or_composite_type_id) {
|
||||
auto type_instruction =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(scalar_or_composite_type_id);
|
||||
assert(type_instruction && "The type instruction must exist.");
|
||||
switch (type_instruction->opcode()) {
|
||||
case SpvOpTypeBool:
|
||||
return FindOrCreateBoolConstant(false);
|
||||
case SpvOpTypeFloat:
|
||||
return FindOrCreate32BitFloatConstant(0);
|
||||
case SpvOpTypeInt:
|
||||
return FindOrCreate32BitIntegerConstant(
|
||||
0, type_instruction->GetSingleWordInOperand(1) != 0);
|
||||
case SpvOpTypeArray: {
|
||||
return GetZeroConstantForHomogeneousComposite(
|
||||
*type_instruction, type_instruction->GetSingleWordInOperand(0),
|
||||
fuzzerutil::GetArraySize(*type_instruction, GetIRContext()));
|
||||
}
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector: {
|
||||
return GetZeroConstantForHomogeneousComposite(
|
||||
*type_instruction, type_instruction->GetSingleWordInOperand(0),
|
||||
type_instruction->GetSingleWordInOperand(1));
|
||||
}
|
||||
case SpvOpTypeStruct: {
|
||||
std::vector<const opt::analysis::Constant*> field_zero_constants;
|
||||
std::vector<uint32_t> field_zero_ids;
|
||||
for (uint32_t index = 0; index < type_instruction->NumInOperands();
|
||||
index++) {
|
||||
uint32_t field_constant_id = FindOrCreateZeroConstant(
|
||||
type_instruction->GetSingleWordInOperand(index));
|
||||
field_zero_ids.push_back(field_constant_id);
|
||||
field_zero_constants.push_back(
|
||||
GetIRContext()->get_constant_mgr()->FindDeclaredConstant(
|
||||
field_constant_id));
|
||||
}
|
||||
return FindOrCreateCompositeConstant(
|
||||
*type_instruction, field_zero_constants, field_zero_ids);
|
||||
}
|
||||
default:
|
||||
assert(false && "Unknown type.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateCompositeConstant(
|
||||
const opt::Instruction& composite_type_instruction,
|
||||
const std::vector<const opt::analysis::Constant*>& constants,
|
||||
const std::vector<uint32_t>& constant_ids) {
|
||||
assert(constants.size() == constant_ids.size() &&
|
||||
"Precondition: |constants| and |constant_ids| must be in "
|
||||
"correspondence.");
|
||||
|
||||
opt::analysis::Type* composite_type = GetIRContext()->get_type_mgr()->GetType(
|
||||
composite_type_instruction.result_id());
|
||||
std::unique_ptr<opt::analysis::Constant> composite_constant;
|
||||
if (composite_type->AsArray()) {
|
||||
composite_constant = MakeUnique<opt::analysis::ArrayConstant>(
|
||||
composite_type->AsArray(), constants);
|
||||
} else if (composite_type->AsMatrix()) {
|
||||
composite_constant = MakeUnique<opt::analysis::MatrixConstant>(
|
||||
composite_type->AsMatrix(), constants);
|
||||
} else if (composite_type->AsStruct()) {
|
||||
composite_constant = MakeUnique<opt::analysis::StructConstant>(
|
||||
composite_type->AsStruct(), constants);
|
||||
} else if (composite_type->AsVector()) {
|
||||
composite_constant = MakeUnique<opt::analysis::VectorConstant>(
|
||||
composite_type->AsVector(), constants);
|
||||
} else {
|
||||
assert(false &&
|
||||
"Precondition: |composite_type| must declare a composite type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t existing_constant =
|
||||
GetIRContext()->get_constant_mgr()->FindDeclaredConstant(
|
||||
composite_constant.get(), composite_type_instruction.result_id());
|
||||
if (existing_constant) {
|
||||
return existing_constant;
|
||||
}
|
||||
uint32_t result = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddConstantComposite(
|
||||
result, composite_type_instruction.result_id(), constant_ids));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::GetZeroConstantForHomogeneousComposite(
|
||||
const opt::Instruction& composite_type_instruction,
|
||||
uint32_t component_type_id, uint32_t num_components) {
|
||||
std::vector<const opt::analysis::Constant*> zero_constants;
|
||||
std::vector<uint32_t> zero_ids;
|
||||
uint32_t zero_component = FindOrCreateZeroConstant(component_type_id);
|
||||
const opt::analysis::Constant* registered_zero_component =
|
||||
GetIRContext()->get_constant_mgr()->FindDeclaredConstant(zero_component);
|
||||
for (uint32_t i = 0; i < num_components; i++) {
|
||||
zero_constants.push_back(registered_zero_component);
|
||||
zero_ids.push_back(zero_component);
|
||||
}
|
||||
return FindOrCreateCompositeConstant(composite_type_instruction,
|
||||
zero_constants, zero_ids);
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -138,12 +138,85 @@ class FuzzerPass {
|
||||
// applied to add them.
|
||||
uint32_t FindOrCreate32BitIntegerConstant(uint32_t word, bool is_signed);
|
||||
|
||||
// Returns the id of an OpConstant instruction, with 32-bit floating-point
|
||||
// type, with |word| as its value. If either the required floating-point type
|
||||
// or the constant do not exist, transformations are applied to add them.
|
||||
uint32_t FindOrCreate32BitFloatConstant(uint32_t word);
|
||||
|
||||
// Returns the id of an OpConstantTrue or OpConstantFalse instruction,
|
||||
// according to |value|. If either the required instruction or the bool
|
||||
// type do not exist, transformations are applied to add them.
|
||||
uint32_t FindOrCreateBoolConstant(bool value);
|
||||
|
||||
// Returns the result id of an instruction of the form:
|
||||
// %id = OpUndef %|type_id|
|
||||
// If no such instruction exists, a transformation is applied to add it.
|
||||
uint32_t FindOrCreateGlobalUndef(uint32_t type_id);
|
||||
|
||||
// Yields a pair, (base_type_ids, base_type_ids_to_pointers), such that:
|
||||
// - base_type_ids captures every scalar or composite type declared in the
|
||||
// module (i.e., all int, bool, float, vector, matrix, struct and array
|
||||
// types
|
||||
// - base_type_ids_to_pointers maps every such base type to the sequence
|
||||
// of all pointer types that have storage class |storage_class| and the
|
||||
// given base type as their pointee type. The sequence may be empty for
|
||||
// some base types if no pointers to those types are defined for the given
|
||||
// storage class, and the sequence will have multiple elements if there are
|
||||
// repeated pointer declarations for the same base type and storage class.
|
||||
std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
|
||||
GetAvailableBaseTypesAndPointers(SpvStorageClass storage_class) const;
|
||||
|
||||
// Given a type id, |scalar_or_composite_type_id|, which must correspond to
|
||||
// some scalar or composite type, returns the result id of an instruction
|
||||
// defining a constant of the given type that is zero or false at everywhere.
|
||||
// If such an instruction does not yet exist, transformations are applied to
|
||||
// add it.
|
||||
//
|
||||
// Examples:
|
||||
// --------------+-------------------------------
|
||||
// TYPE | RESULT is id corresponding to
|
||||
// --------------+-------------------------------
|
||||
// bool | false
|
||||
// --------------+-------------------------------
|
||||
// bvec4 | (false, false, false, false)
|
||||
// --------------+-------------------------------
|
||||
// float | 0.0
|
||||
// --------------+-------------------------------
|
||||
// vec2 | (0.0, 0.0)
|
||||
// --------------+-------------------------------
|
||||
// int[3] | [0, 0, 0]
|
||||
// --------------+-------------------------------
|
||||
// struct S { |
|
||||
// int i; | S(0, false, (0u, 0u))
|
||||
// bool b; |
|
||||
// uint2 u; |
|
||||
// } |
|
||||
// --------------+-------------------------------
|
||||
uint32_t FindOrCreateZeroConstant(uint32_t scalar_or_composite_type_id);
|
||||
|
||||
private:
|
||||
// Array, matrix and vector are *homogeneous* composite types in the sense
|
||||
// that every component of one of these types has the same type. Given a
|
||||
// homogeneous composite type instruction, |composite_type_instruction|,
|
||||
// returns the id of a composite constant instruction for which every element
|
||||
// is zero/false. If such an instruction does not yet exist, transformations
|
||||
// are applied to add it.
|
||||
uint32_t GetZeroConstantForHomogeneousComposite(
|
||||
const opt::Instruction& composite_type_instruction,
|
||||
uint32_t component_type_id, uint32_t num_components);
|
||||
|
||||
// Helper to find an existing composite constant instruction of the given
|
||||
// composite type with the given constant components, or to apply
|
||||
// transformations to create such an instruction if it does not yet exist.
|
||||
// Parameter |composite_type_instruction| must be a composite type
|
||||
// instruction. The parameters |constants| and |constant_ids| must have the
|
||||
// same size, and it must be the case that for each i, |constant_ids[i]| is
|
||||
// the result id of an instruction that defines |constants[i]|.
|
||||
uint32_t FindOrCreateCompositeConstant(
|
||||
const opt::Instruction& composite_type_instruction,
|
||||
const std::vector<const opt::analysis::Constant*>& constants,
|
||||
const std::vector<uint32_t>& constant_ids);
|
||||
|
||||
opt::IRContext* ir_context_;
|
||||
FactManager* fact_manager_;
|
||||
FuzzerContext* fuzzer_context_;
|
||||
|
75
source/fuzz/fuzzer_pass_add_global_variables.cpp
Normal file
75
source/fuzz/fuzzer_pass_add_global_variables.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_add_global_variables.h"
|
||||
|
||||
#include "source/fuzz/transformation_add_global_variable.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
|
||||
|
||||
FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default;
|
||||
|
||||
void FuzzerPassAddGlobalVariables::Apply() {
|
||||
auto base_type_ids_and_pointers =
|
||||
GetAvailableBaseTypesAndPointers(SpvStorageClassPrivate);
|
||||
|
||||
// These are the base types that are available to this fuzzer pass.
|
||||
auto& base_types = base_type_ids_and_pointers.first;
|
||||
|
||||
// These are the pointers to those base types that are *initially* available
|
||||
// to the fuzzer pass. The fuzzer pass might add pointer types in cases where
|
||||
// none are available for a given base type.
|
||||
auto& base_type_to_pointers = base_type_ids_and_pointers.second;
|
||||
|
||||
// Probabilistically keep adding global variables.
|
||||
while (GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAddingGlobalVariable())) {
|
||||
// Choose a random base type; the new variable's type will be a pointer to
|
||||
// this base type.
|
||||
uint32_t base_type =
|
||||
base_types[GetFuzzerContext()->RandomIndex(base_types)];
|
||||
uint32_t pointer_type_id;
|
||||
std::vector<uint32_t>& available_pointers_to_base_type =
|
||||
base_type_to_pointers.at(base_type);
|
||||
// Determine whether there is at least one pointer to this base type.
|
||||
if (available_pointers_to_base_type.empty()) {
|
||||
// There is not. Make one, to use here, and add it to the available
|
||||
// pointers for the base type so that future variables can potentially
|
||||
// use it.
|
||||
pointer_type_id = GetFuzzerContext()->GetFreshId();
|
||||
available_pointers_to_base_type.push_back(pointer_type_id);
|
||||
ApplyTransformation(TransformationAddTypePointer(
|
||||
pointer_type_id, SpvStorageClassPrivate, base_type));
|
||||
} else {
|
||||
// There is - grab one.
|
||||
pointer_type_id =
|
||||
available_pointers_to_base_type[GetFuzzerContext()->RandomIndex(
|
||||
available_pointers_to_base_type)];
|
||||
}
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
GetFuzzerContext()->GetFreshId(), pointer_type_id,
|
||||
FindOrCreateZeroConstant(base_type), true));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
40
source/fuzz/fuzzer_pass_add_global_variables.h
Normal file
40
source/fuzz/fuzzer_pass_add_global_variables.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Fuzzer pass that randomly adds global variables, with Private storage class,
|
||||
// to the module.
|
||||
class FuzzerPassAddGlobalVariables : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAddGlobalVariables(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAddGlobalVariables();
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_GLOBAL_VARIABLES_H_
|
79
source/fuzz/fuzzer_pass_add_local_variables.cpp
Normal file
79
source/fuzz/fuzzer_pass_add_local_variables.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_add_local_variables.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_add_local_variable.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
|
||||
|
||||
FuzzerPassAddLocalVariables::~FuzzerPassAddLocalVariables() = default;
|
||||
|
||||
void FuzzerPassAddLocalVariables::Apply() {
|
||||
auto base_type_ids_and_pointers =
|
||||
GetAvailableBaseTypesAndPointers(SpvStorageClassFunction);
|
||||
|
||||
// These are the base types that are available to this fuzzer pass.
|
||||
auto& base_types = base_type_ids_and_pointers.first;
|
||||
|
||||
// These are the pointers to those base types that are *initially* available
|
||||
// to the fuzzer pass. The fuzzer pass might add pointer types in cases where
|
||||
// none are available for a given base type.
|
||||
auto& base_type_to_pointers = base_type_ids_and_pointers.second;
|
||||
|
||||
// Consider every function in the module.
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
// Probabilistically keep adding random variables to this function.
|
||||
while (GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAddingLocalVariable())) {
|
||||
// Choose a random base type; the new variable's type will be a pointer to
|
||||
// this base type.
|
||||
uint32_t base_type =
|
||||
base_types[GetFuzzerContext()->RandomIndex(base_types)];
|
||||
uint32_t pointer_type;
|
||||
std::vector<uint32_t>& available_pointers_to_base_type =
|
||||
base_type_to_pointers.at(base_type);
|
||||
// Determine whether there is at least one pointer to this base type.
|
||||
if (available_pointers_to_base_type.empty()) {
|
||||
// There is not. Make one, to use here, and add it to the available
|
||||
// pointers for the base type so that future variables can potentially
|
||||
// use it.
|
||||
pointer_type = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddTypePointer(
|
||||
pointer_type, SpvStorageClassFunction, base_type));
|
||||
available_pointers_to_base_type.push_back(pointer_type);
|
||||
} else {
|
||||
// There is - grab one.
|
||||
pointer_type =
|
||||
available_pointers_to_base_type[GetFuzzerContext()->RandomIndex(
|
||||
available_pointers_to_base_type)];
|
||||
}
|
||||
ApplyTransformation(TransformationAddLocalVariable(
|
||||
GetFuzzerContext()->GetFreshId(), pointer_type, function.result_id(),
|
||||
FindOrCreateZeroConstant(base_type), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
43
source/fuzz/fuzzer_pass_add_local_variables.h
Normal file
43
source/fuzz/fuzzer_pass_add_local_variables.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Fuzzer pass that randomly adds local variables, with Function storage class,
|
||||
// to the module.
|
||||
class FuzzerPassAddLocalVariables : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAddLocalVariables(
|
||||
opt::IRContext* ir_context, FactManager* fact_manager,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAddLocalVariables();
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_LOCAL_VARIABLES_H_
|
@ -391,6 +391,15 @@ uint32_t FindFunctionType(opt::IRContext* ir_context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
opt::Function* FindFunction(opt::IRContext* ir_context, uint32_t function_id) {
|
||||
for (auto& function : *ir_context->module()) {
|
||||
if (function.result_id() == function_id) {
|
||||
return &function;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
@ -137,6 +137,10 @@ bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id);
|
||||
uint32_t FindFunctionType(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& type_ids);
|
||||
|
||||
// Returns the function with result id |function_id|, or |nullptr| if no such
|
||||
// function exists.
|
||||
opt::Function* FindFunction(opt::IRContext* ir_context, uint32_t function_id);
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
@ -339,6 +339,7 @@ message Transformation {
|
||||
TransformationAddGlobalUndef add_global_undef = 32;
|
||||
TransformationAddFunction add_function = 33;
|
||||
TransformationAddDeadBlock add_dead_block = 34;
|
||||
TransformationAddLocalVariable add_local_variable = 35;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@ -507,15 +508,38 @@ message TransformationAddGlobalVariable {
|
||||
// Optional initializer; 0 if there is no initializer
|
||||
uint32 initializer_id = 3;
|
||||
|
||||
// True if and only if the value of the variable should be regarded, in
|
||||
// general, as totally unknown and subject to change (even if, due to an
|
||||
// initializer, the original value is known). This is the case for variables
|
||||
// added when a module is donated, for example, and means that stores to such
|
||||
// variables can be performed in an arbitrary fashion.
|
||||
// True if and only if the behaviour of the module should not depend on the
|
||||
// value of the variable, in which case stores to the variable can be
|
||||
// performed in an arbitrary fashion.
|
||||
bool value_is_arbitrary = 4;
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddLocalVariable {
|
||||
|
||||
// Adds a local variable of the given type (which must be a pointer with
|
||||
// Function storage class) to the given function, initialized to the given
|
||||
// id.
|
||||
|
||||
// Fresh id for the local variable
|
||||
uint32 fresh_id = 1;
|
||||
|
||||
// The type of the local variable
|
||||
uint32 type_id = 2;
|
||||
|
||||
// The id of the function to which the local variable should be added
|
||||
uint32 function_id = 3;
|
||||
|
||||
// Initial value of the variable
|
||||
uint32 initializer_id = 4;
|
||||
|
||||
// True if and only if the behaviour of the module should not depend on the
|
||||
// value of the variable, in which case stores to the variable can be
|
||||
// performed in an arbitrary fashion.
|
||||
bool value_is_arbitrary = 5;
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddNoContractionDecoration {
|
||||
|
||||
// Applies OpDecorate NoContraction to the given result id
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "source/fuzz/transformation_add_function.h"
|
||||
#include "source/fuzz/transformation_add_global_undef.h"
|
||||
#include "source/fuzz/transformation_add_global_variable.h"
|
||||
#include "source/fuzz/transformation_add_local_variable.h"
|
||||
#include "source/fuzz/transformation_add_no_contraction_decoration.h"
|
||||
#include "source/fuzz/transformation_add_type_array.h"
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
@ -85,6 +86,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kAddGlobalVariable:
|
||||
return MakeUnique<TransformationAddGlobalVariable>(
|
||||
message.add_global_variable());
|
||||
case protobufs::Transformation::TransformationCase::kAddLocalVariable:
|
||||
return MakeUnique<TransformationAddLocalVariable>(
|
||||
message.add_local_variable());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kAddNoContractionDecoration:
|
||||
return MakeUnique<TransformationAddNoContractionDecoration>(
|
||||
|
98
source/fuzz/transformation_add_local_variable.cpp
Normal file
98
source/fuzz/transformation_add_local_variable.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_local_variable.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationAddLocalVariable::TransformationAddLocalVariable(
|
||||
const spvtools::fuzz::protobufs::TransformationAddLocalVariable& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationAddLocalVariable::TransformationAddLocalVariable(
|
||||
uint32_t fresh_id, uint32_t type_id, uint32_t function_id,
|
||||
uint32_t initializer_id, bool value_is_arbitrary) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_type_id(type_id);
|
||||
message_.set_function_id(function_id);
|
||||
message_.set_initializer_id(initializer_id);
|
||||
message_.set_value_is_arbitrary(value_is_arbitrary);
|
||||
}
|
||||
|
||||
bool TransformationAddLocalVariable::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The provided id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
// The pointer type id must indeed correspond to a pointer, and it must have
|
||||
// function storage class.
|
||||
auto type_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.type_id());
|
||||
if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer ||
|
||||
type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) {
|
||||
return false;
|
||||
}
|
||||
// The initializer must...
|
||||
auto initializer_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.initializer_id());
|
||||
// ... exist, ...
|
||||
if (!initializer_instruction) {
|
||||
return false;
|
||||
}
|
||||
// ... be a constant, ...
|
||||
if (!spvOpcodeIsConstant(initializer_instruction->opcode())) {
|
||||
return false;
|
||||
}
|
||||
// ... and have the same type as the pointee type.
|
||||
if (initializer_instruction->type_id() !=
|
||||
type_instruction->GetSingleWordInOperand(1)) {
|
||||
return false;
|
||||
}
|
||||
// The function to which the local variable is to be added must exist.
|
||||
return fuzzerutil::FindFunction(context, message_.function_id());
|
||||
}
|
||||
|
||||
void TransformationAddLocalVariable::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
fuzzerutil::FindFunction(context, message_.function_id())
|
||||
->begin()
|
||||
->begin()
|
||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpVariable, message_.type_id(), message_.fresh_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_STORAGE_CLASS,
|
||||
{
|
||||
|
||||
SpvStorageClassFunction}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.initializer_id()}}})));
|
||||
if (message_.value_is_arbitrary()) {
|
||||
fact_manager->AddFactValueOfVariableIsArbitrary(message_.fresh_id());
|
||||
}
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationAddLocalVariable::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_local_variable() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
60
source/fuzz/transformation_add_local_variable.h
Normal file
60
source/fuzz/transformation_add_local_variable.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_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 TransformationAddLocalVariable : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddLocalVariable(
|
||||
const protobufs::TransformationAddLocalVariable& message);
|
||||
|
||||
TransformationAddLocalVariable(uint32_t fresh_id, uint32_t type_id,
|
||||
uint32_t function_id, uint32_t initializer_id,
|
||||
bool value_is_arbitrary);
|
||||
|
||||
// - |message_.fresh_id| must not be used by the module
|
||||
// - |message_.type_id| must be the id of a pointer type with Function
|
||||
// storage class
|
||||
// - |message_.initializer_id| must be the id of a constant with the same
|
||||
// type as the pointer's pointee type
|
||||
// - |message_.function_id| must be the id of a function
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds an instruction to the start of |message_.function_id|, of the form:
|
||||
// |message_.fresh_id| = OpVariable |message_.type_id| Function
|
||||
// |message_.initializer_id|
|
||||
// If |message_.value_is_arbitrary| holds, adds a corresponding fact to
|
||||
// |fact_manager|.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddLocalVariable message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_
|
@ -33,6 +33,7 @@ if (${SPIRV_BUILD_FUZZER})
|
||||
transformation_add_function_test.cpp
|
||||
transformation_add_global_undef_test.cpp
|
||||
transformation_add_global_variable_test.cpp
|
||||
transformation_add_local_variable_test.cpp
|
||||
transformation_add_no_contraction_decoration_test.cpp
|
||||
transformation_add_type_array_test.cpp
|
||||
transformation_add_type_boolean_test.cpp
|
||||
|
206
test/fuzz/transformation_add_local_variable_test.cpp
Normal file
206
test/fuzz/transformation_add_local_variable_test.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_local_variable.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddLocalVariableTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypePointer Function %7
|
||||
%10 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpConstantComposite %7 %10 %11
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeInt 32 0
|
||||
%15 = OpConstant %14 3
|
||||
%16 = OpTypeArray %13 %15
|
||||
%17 = OpTypeBool
|
||||
%18 = OpTypeStruct %16 %7 %17
|
||||
%19 = OpTypePointer Function %18
|
||||
%21 = OpConstant %13 1
|
||||
%22 = OpConstant %13 2
|
||||
%23 = OpConstant %13 4
|
||||
%24 = OpConstantComposite %16 %21 %22 %23
|
||||
%25 = OpConstant %6 5
|
||||
%26 = OpConstant %6 6
|
||||
%27 = OpConstantComposite %7 %25 %26
|
||||
%28 = OpConstantFalse %17
|
||||
%29 = OpConstantComposite %18 %24 %27 %28
|
||||
%30 = OpTypeVector %13 2
|
||||
%31 = OpTypePointer Function %30
|
||||
%33 = OpConstantComposite %30 %21 %21
|
||||
%34 = OpTypeVector %17 3
|
||||
%35 = OpTypePointer Function %34
|
||||
%37 = OpConstantTrue %17
|
||||
%38 = OpConstantComposite %34 %37 %28 %28
|
||||
%39 = OpTypeVector %13 4
|
||||
%40 = OpTypeMatrix %39 3
|
||||
%41 = OpTypePointer Function %40
|
||||
%43 = OpConstantComposite %39 %21 %22 %23 %21
|
||||
%44 = OpConstantComposite %39 %22 %23 %21 %22
|
||||
%45 = OpConstantComposite %39 %23 %21 %22 %23
|
||||
%46 = OpConstantComposite %40 %43 %44 %45
|
||||
%50 = OpTypePointer Function %14
|
||||
%51 = OpConstantNull %14
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = 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;
|
||||
|
||||
// A few cases of inapplicable transformations:
|
||||
// Id 4 is already in use
|
||||
ASSERT_FALSE(TransformationAddLocalVariable(4, 50, 4, 51, true)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Type mismatch between initializer and pointer
|
||||
ASSERT_FALSE(TransformationAddLocalVariable(105, 46, 4, 51, true)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Id 5 is not a function
|
||||
ASSERT_FALSE(TransformationAddLocalVariable(105, 50, 5, 51, true)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// %105 = OpVariable %50 Function %51
|
||||
{
|
||||
TransformationAddLocalVariable transformation(105, 50, 4, 51, true);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
// %104 = OpVariable %41 Function %46
|
||||
{
|
||||
TransformationAddLocalVariable transformation(104, 41, 4, 46, false);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
// %103 = OpVariable %35 Function %38
|
||||
{
|
||||
TransformationAddLocalVariable transformation(103, 35, 4, 38, true);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
// %102 = OpVariable %31 Function %33
|
||||
{
|
||||
TransformationAddLocalVariable transformation(102, 31, 4, 33, false);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
// %101 = OpVariable %19 Function %29
|
||||
{
|
||||
TransformationAddLocalVariable transformation(101, 19, 4, 29, true);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
// %100 = OpVariable %8 Function %12
|
||||
{
|
||||
TransformationAddLocalVariable transformation(100, 8, 4, 12, false);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(100));
|
||||
ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(101));
|
||||
ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(102));
|
||||
ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(103));
|
||||
ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(104));
|
||||
ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(105));
|
||||
|
||||
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
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypePointer Function %7
|
||||
%10 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpConstantComposite %7 %10 %11
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeInt 32 0
|
||||
%15 = OpConstant %14 3
|
||||
%16 = OpTypeArray %13 %15
|
||||
%17 = OpTypeBool
|
||||
%18 = OpTypeStruct %16 %7 %17
|
||||
%19 = OpTypePointer Function %18
|
||||
%21 = OpConstant %13 1
|
||||
%22 = OpConstant %13 2
|
||||
%23 = OpConstant %13 4
|
||||
%24 = OpConstantComposite %16 %21 %22 %23
|
||||
%25 = OpConstant %6 5
|
||||
%26 = OpConstant %6 6
|
||||
%27 = OpConstantComposite %7 %25 %26
|
||||
%28 = OpConstantFalse %17
|
||||
%29 = OpConstantComposite %18 %24 %27 %28
|
||||
%30 = OpTypeVector %13 2
|
||||
%31 = OpTypePointer Function %30
|
||||
%33 = OpConstantComposite %30 %21 %21
|
||||
%34 = OpTypeVector %17 3
|
||||
%35 = OpTypePointer Function %34
|
||||
%37 = OpConstantTrue %17
|
||||
%38 = OpConstantComposite %34 %37 %28 %28
|
||||
%39 = OpTypeVector %13 4
|
||||
%40 = OpTypeMatrix %39 3
|
||||
%41 = OpTypePointer Function %40
|
||||
%43 = OpConstantComposite %39 %21 %22 %23 %21
|
||||
%44 = OpConstantComposite %39 %22 %23 %21 %22
|
||||
%45 = OpConstantComposite %39 %23 %21 %22 %23
|
||||
%46 = OpConstantComposite %40 %43 %44 %45
|
||||
%50 = OpTypePointer Function %14
|
||||
%51 = OpConstantNull %14
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%100 = OpVariable %8 Function %12
|
||||
%101 = OpVariable %19 Function %29
|
||||
%102 = OpVariable %31 Function %33
|
||||
%103 = OpVariable %35 Function %38
|
||||
%104 = OpVariable %41 Function %46
|
||||
%105 = OpVariable %50 Function %51
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user