mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 11:40:05 +00:00
parent
522561619a
commit
2f69ea849a
@ -49,7 +49,6 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
fuzzer_pass_add_local_variables.h
|
fuzzer_pass_add_local_variables.h
|
||||||
fuzzer_pass_add_no_contraction_decorations.h
|
fuzzer_pass_add_no_contraction_decorations.h
|
||||||
fuzzer_pass_add_stores.h
|
fuzzer_pass_add_stores.h
|
||||||
fuzzer_pass_add_useful_constructs.h
|
|
||||||
fuzzer_pass_adjust_branch_weights.h
|
fuzzer_pass_adjust_branch_weights.h
|
||||||
fuzzer_pass_adjust_function_controls.h
|
fuzzer_pass_adjust_function_controls.h
|
||||||
fuzzer_pass_adjust_loop_controls.h
|
fuzzer_pass_adjust_loop_controls.h
|
||||||
@ -146,7 +145,6 @@ if(SPIRV_BUILD_FUZZER)
|
|||||||
fuzzer_pass_add_local_variables.cpp
|
fuzzer_pass_add_local_variables.cpp
|
||||||
fuzzer_pass_add_no_contraction_decorations.cpp
|
fuzzer_pass_add_no_contraction_decorations.cpp
|
||||||
fuzzer_pass_add_stores.cpp
|
fuzzer_pass_add_stores.cpp
|
||||||
fuzzer_pass_add_useful_constructs.cpp
|
|
||||||
fuzzer_pass_adjust_branch_weights.cpp
|
fuzzer_pass_adjust_branch_weights.cpp
|
||||||
fuzzer_pass_adjust_function_controls.cpp
|
fuzzer_pass_adjust_function_controls.cpp
|
||||||
fuzzer_pass_adjust_loop_controls.cpp
|
fuzzer_pass_adjust_loop_controls.cpp
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "source/fuzz/fuzzer_pass_add_local_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_no_contraction_decorations.h"
|
||||||
#include "source/fuzz/fuzzer_pass_add_stores.h"
|
#include "source/fuzz/fuzzer_pass_add_stores.h"
|
||||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
|
||||||
#include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
|
#include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
|
||||||
#include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
|
#include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
|
||||||
#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
|
#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
|
||||||
@ -187,16 +186,6 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
|||||||
TransformationContext transformation_context(&fact_manager,
|
TransformationContext transformation_context(&fact_manager,
|
||||||
impl_->validator_options);
|
impl_->validator_options);
|
||||||
|
|
||||||
// Add some essential ingredients to the module if they are not already
|
|
||||||
// present, such as boolean constants.
|
|
||||||
FuzzerPassAddUsefulConstructs add_useful_constructs(
|
|
||||||
ir_context.get(), &transformation_context, &fuzzer_context,
|
|
||||||
transformation_sequence_out);
|
|
||||||
if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context,
|
|
||||||
tools)) {
|
|
||||||
return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply some semantics-preserving passes.
|
// Apply some semantics-preserving passes.
|
||||||
std::vector<std::unique_ptr<FuzzerPass>> passes;
|
std::vector<std::unique_ptr<FuzzerPass>> passes;
|
||||||
while (passes.empty()) {
|
while (passes.empty()) {
|
||||||
|
@ -319,6 +319,35 @@ uint32_t FuzzerPass::FindOrCreateBoolConstant(bool value) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t FuzzerPass::FindOrCreateConstant(const std::vector<uint32_t>& words,
|
||||||
|
uint32_t type_id) {
|
||||||
|
assert(type_id && "Constant's type id can't be 0.");
|
||||||
|
|
||||||
|
const auto* type = GetIRContext()->get_type_mgr()->GetType(type_id);
|
||||||
|
assert(type && "Type does not exist.");
|
||||||
|
|
||||||
|
if (type->AsBool()) {
|
||||||
|
assert(words.size() == 1);
|
||||||
|
return FindOrCreateBoolConstant(words[0]);
|
||||||
|
} else if (const auto* integer = type->AsInteger()) {
|
||||||
|
assert(integer->width() == 32 && words.size() == 1 &&
|
||||||
|
"Integer must have 32-bit width");
|
||||||
|
return FindOrCreate32BitIntegerConstant(words[0], integer->IsSigned());
|
||||||
|
} else if (const auto* floating = type->AsFloat()) {
|
||||||
|
// Assertions are not evaluated in release builds so |floating|
|
||||||
|
// variable will be unused.
|
||||||
|
(void)floating;
|
||||||
|
assert(floating->width() == 32 && words.size() == 1 &&
|
||||||
|
"Floating point number must have 32-bit width");
|
||||||
|
return FindOrCreate32BitFloatConstant(words[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This assertion will fail in debug build but not in release build
|
||||||
|
// so we return 0 to make compiler happy.
|
||||||
|
assert(false && "Constant type is not supported");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
|
uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
|
||||||
for (auto& inst : GetIRContext()->types_values()) {
|
for (auto& inst : GetIRContext()->types_values()) {
|
||||||
if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
|
if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
|
||||||
|
@ -164,6 +164,14 @@ class FuzzerPass {
|
|||||||
// type do not exist, transformations are applied to add them.
|
// type do not exist, transformations are applied to add them.
|
||||||
uint32_t FindOrCreateBoolConstant(bool value);
|
uint32_t FindOrCreateBoolConstant(bool value);
|
||||||
|
|
||||||
|
// Returns the id of an OpConstant instruction of type with |type_id|
|
||||||
|
// that consists of |words|. If that instruction doesn't exist,
|
||||||
|
// transformations are applied to add it. |type_id| must be a valid
|
||||||
|
// result id of either scalar or boolean OpType* instruction that exists
|
||||||
|
// in the module.
|
||||||
|
uint32_t FindOrCreateConstant(const std::vector<uint32_t>& words,
|
||||||
|
uint32_t type_id);
|
||||||
|
|
||||||
// Returns the result id of an instruction of the form:
|
// Returns the result id of an instruction of the form:
|
||||||
// %id = OpUndef %|type_id|
|
// %id = OpUndef %|type_id|
|
||||||
// If no such instruction exists, a transformation is applied to add it.
|
// If no such instruction exists, a transformation is applied to add it.
|
||||||
|
@ -41,6 +41,12 @@ void FuzzerPassAddDeadBlocks::Apply() {
|
|||||||
GetFuzzerContext()->GetChanceOfAddingDeadBlock())) {
|
GetFuzzerContext()->GetChanceOfAddingDeadBlock())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the module contains a boolean constant equal to
|
||||||
|
// |condition_value|.
|
||||||
|
bool condition_value = GetFuzzerContext()->ChooseEven();
|
||||||
|
FindOrCreateBoolConstant(condition_value);
|
||||||
|
|
||||||
// We speculatively create a transformation, and then apply it (below) if
|
// We speculatively create a transformation, and then apply it (below) if
|
||||||
// it turns out to be applicable. This avoids duplicating the logic for
|
// it turns out to be applicable. This avoids duplicating the logic for
|
||||||
// applicability checking.
|
// applicability checking.
|
||||||
@ -48,8 +54,7 @@ void FuzzerPassAddDeadBlocks::Apply() {
|
|||||||
// It means that fresh ids for transformations that turn out not to be
|
// It means that fresh ids for transformations that turn out not to be
|
||||||
// applicable end up being unused.
|
// applicable end up being unused.
|
||||||
candidate_transformations.emplace_back(TransformationAddDeadBlock(
|
candidate_transformations.emplace_back(TransformationAddDeadBlock(
|
||||||
GetFuzzerContext()->GetFreshId(), block.id(),
|
GetFuzzerContext()->GetFreshId(), block.id(), condition_value));
|
||||||
GetFuzzerContext()->ChooseEven()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Apply all those transformations that are in fact applicable.
|
// Apply all those transformations that are in fact applicable.
|
||||||
|
@ -77,9 +77,13 @@ void FuzzerPassAddDeadBreaks::Apply() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the module has a required boolean constant to be used in
|
||||||
|
// OpBranchConditional instruction.
|
||||||
|
auto break_condition = GetFuzzerContext()->ChooseEven();
|
||||||
|
FindOrCreateBoolConstant(break_condition);
|
||||||
|
|
||||||
auto candidate_transformation = TransformationAddDeadBreak(
|
auto candidate_transformation = TransformationAddDeadBreak(
|
||||||
block.id(), merge_block->id(), GetFuzzerContext()->ChooseEven(),
|
block.id(), merge_block->id(), break_condition, std::move(phi_ids));
|
||||||
std::move(phi_ids));
|
|
||||||
if (candidate_transformation.IsApplicable(
|
if (candidate_transformation.IsApplicable(
|
||||||
GetIRContext(), *GetTransformationContext())) {
|
GetIRContext(), *GetTransformationContext())) {
|
||||||
// Only consider a transformation as a candidate if it is applicable.
|
// Only consider a transformation as a candidate if it is applicable.
|
||||||
|
@ -68,11 +68,16 @@ void FuzzerPassAddDeadContinues::Apply() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the module contains a boolean constant equal to
|
||||||
|
// |condition_value|.
|
||||||
|
bool condition_value = GetFuzzerContext()->ChooseEven();
|
||||||
|
FindOrCreateBoolConstant(condition_value);
|
||||||
|
|
||||||
// Make a transformation to add a dead continue from this node; if the
|
// Make a transformation to add a dead continue from this node; if the
|
||||||
// node turns out to be inappropriate (e.g. by not being in a loop) the
|
// node turns out to be inappropriate (e.g. by not being in a loop) the
|
||||||
// precondition for the transformation will fail and it will be ignored.
|
// precondition for the transformation will fail and it will be ignored.
|
||||||
auto candidate_transformation = TransformationAddDeadContinue(
|
auto candidate_transformation = TransformationAddDeadContinue(
|
||||||
block.id(), GetFuzzerContext()->ChooseEven(), std::move(phi_ids));
|
block.id(), condition_value, std::move(phi_ids));
|
||||||
// Probabilistically decide whether to apply the transformation in the
|
// Probabilistically decide whether to apply the transformation in the
|
||||||
// case that it is applicable.
|
// case that it is applicable.
|
||||||
if (candidate_transformation.IsApplicable(GetIRContext(),
|
if (candidate_transformation.IsApplicable(GetIRContext(),
|
||||||
|
@ -1,222 +0,0 @@
|
|||||||
// 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_add_useful_constructs.h"
|
|
||||||
|
|
||||||
#include "source/fuzz/transformation_add_constant_boolean.h"
|
|
||||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
|
||||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
|
||||||
#include "source/fuzz/transformation_add_type_float.h"
|
|
||||||
#include "source/fuzz/transformation_add_type_int.h"
|
|
||||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
|
||||||
|
|
||||||
namespace spvtools {
|
|
||||||
namespace fuzz {
|
|
||||||
|
|
||||||
FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
|
|
||||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
|
||||||
FuzzerContext* fuzzer_context,
|
|
||||||
protobufs::TransformationSequence* transformations)
|
|
||||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
|
||||||
transformations) {}
|
|
||||||
|
|
||||||
FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
|
|
||||||
|
|
||||||
void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
|
|
||||||
uint32_t width, bool is_signed, std::vector<uint32_t> data) const {
|
|
||||||
opt::analysis::Integer temp_int_type(width, is_signed);
|
|
||||||
assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) &&
|
|
||||||
"int type should already be registered.");
|
|
||||||
auto registered_int_type = GetIRContext()
|
|
||||||
->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_int_type)
|
|
||||||
->AsInteger();
|
|
||||||
auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type);
|
|
||||||
assert(int_type_id &&
|
|
||||||
"The relevant int type should have been added to the module already.");
|
|
||||||
opt::analysis::IntConstant int_constant(registered_int_type, data);
|
|
||||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
|
|
||||||
TransformationAddConstantScalar add_constant_int =
|
|
||||||
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
|
|
||||||
int_type_id, data);
|
|
||||||
assert(add_constant_int.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_constant_int.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() = add_constant_int.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
|
|
||||||
uint32_t width, std::vector<uint32_t> data) const {
|
|
||||||
opt::analysis::Float temp_float_type(width);
|
|
||||||
assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) &&
|
|
||||||
"float type should already be registered.");
|
|
||||||
auto registered_float_type = GetIRContext()
|
|
||||||
->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_float_type)
|
|
||||||
->AsFloat();
|
|
||||||
auto float_type_id =
|
|
||||||
GetIRContext()->get_type_mgr()->GetId(registered_float_type);
|
|
||||||
assert(
|
|
||||||
float_type_id &&
|
|
||||||
"The relevant float type should have been added to the module already.");
|
|
||||||
opt::analysis::FloatConstant float_constant(registered_float_type, data);
|
|
||||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
|
|
||||||
TransformationAddConstantScalar add_constant_float =
|
|
||||||
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
|
|
||||||
float_type_id, data);
|
|
||||||
assert(add_constant_float.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_constant_float.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() =
|
|
||||||
add_constant_float.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuzzerPassAddUsefulConstructs::Apply() {
|
|
||||||
{
|
|
||||||
// Add boolean type if not present.
|
|
||||||
opt::analysis::Bool temp_bool_type;
|
|
||||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
|
|
||||||
auto add_type_boolean =
|
|
||||||
TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
|
|
||||||
assert(add_type_boolean.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_type_boolean.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() =
|
|
||||||
add_type_boolean.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Add signed and unsigned 32-bit integer types if not present.
|
|
||||||
for (auto is_signed : {true, false}) {
|
|
||||||
opt::analysis::Integer temp_int_type(32, is_signed);
|
|
||||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
|
|
||||||
TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
|
|
||||||
GetFuzzerContext()->GetFreshId(), 32, is_signed);
|
|
||||||
assert(add_type_int.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_type_int.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() = add_type_int.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Add 32-bit float type if not present.
|
|
||||||
opt::analysis::Float temp_float_type(32);
|
|
||||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
|
|
||||||
TransformationAddTypeFloat add_type_float =
|
|
||||||
TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
|
|
||||||
assert(add_type_float.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_type_float.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() = add_type_float.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add boolean constants true and false if not present.
|
|
||||||
opt::analysis::Bool temp_bool_type;
|
|
||||||
auto bool_type = GetIRContext()
|
|
||||||
->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_bool_type)
|
|
||||||
->AsBool();
|
|
||||||
for (auto boolean_value : {true, false}) {
|
|
||||||
// Add OpConstantTrue/False if not already there.
|
|
||||||
opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
|
|
||||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
|
|
||||||
TransformationAddConstantBoolean add_constant_boolean(
|
|
||||||
GetFuzzerContext()->GetFreshId(), boolean_value);
|
|
||||||
assert(add_constant_boolean.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_constant_boolean.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() =
|
|
||||||
add_constant_boolean.ToMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add signed and unsigned 32-bit integer constants 0 and 1 if not present.
|
|
||||||
for (auto is_signed : {true, false}) {
|
|
||||||
for (auto value : {0u, 1u}) {
|
|
||||||
MaybeAddIntConstant(32, is_signed, {value});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 32-bit float constants 0.0 and 1.0 if not present.
|
|
||||||
uint32_t uint_data[2];
|
|
||||||
float float_data[2] = {0.0, 1.0};
|
|
||||||
memcpy(uint_data, float_data, sizeof(float_data));
|
|
||||||
for (unsigned int& datum : uint_data) {
|
|
||||||
MaybeAddFloatConstant(32, {datum});
|
|
||||||
}
|
|
||||||
|
|
||||||
// For every known-to-be-constant uniform, make sure we have instructions
|
|
||||||
// declaring:
|
|
||||||
// - a pointer type with uniform storage class, whose pointee type is the type
|
|
||||||
// of the element
|
|
||||||
// - a signed integer constant for each index required to access the element
|
|
||||||
// - a constant for the constant value itself
|
|
||||||
for (auto& fact_and_type_id : GetTransformationContext()
|
|
||||||
->GetFactManager()
|
|
||||||
->GetConstantUniformFactsAndTypes()) {
|
|
||||||
uint32_t element_type_id = fact_and_type_id.second;
|
|
||||||
assert(element_type_id);
|
|
||||||
auto element_type =
|
|
||||||
GetIRContext()->get_type_mgr()->GetType(element_type_id);
|
|
||||||
assert(element_type &&
|
|
||||||
"If the constant uniform fact is well-formed, the module must "
|
|
||||||
"already have a declaration of the type for the uniform element.");
|
|
||||||
opt::analysis::Pointer uniform_pointer(element_type,
|
|
||||||
SpvStorageClassUniform);
|
|
||||||
if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
|
|
||||||
auto add_pointer =
|
|
||||||
TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
|
|
||||||
SpvStorageClassUniform, element_type_id);
|
|
||||||
assert(add_pointer.IsApplicable(GetIRContext(),
|
|
||||||
*GetTransformationContext()) &&
|
|
||||||
"Should be applicable by construction.");
|
|
||||||
add_pointer.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() = add_pointer.ToMessage();
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> words;
|
|
||||||
for (auto word : fact_and_type_id.first.constant_word()) {
|
|
||||||
words.push_back(word);
|
|
||||||
}
|
|
||||||
// We get the element type again as the type manager may have been
|
|
||||||
// invalidated since we last retrieved it.
|
|
||||||
element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id);
|
|
||||||
if (element_type->AsInteger()) {
|
|
||||||
MaybeAddIntConstant(element_type->AsInteger()->width(),
|
|
||||||
element_type->AsInteger()->IsSigned(), words);
|
|
||||||
} else {
|
|
||||||
assert(element_type->AsFloat() &&
|
|
||||||
"Known uniform values must be integer or floating-point.");
|
|
||||||
MaybeAddFloatConstant(element_type->AsFloat()->width(), words);
|
|
||||||
}
|
|
||||||
for (auto index :
|
|
||||||
fact_and_type_id.first.uniform_buffer_element_descriptor().index()) {
|
|
||||||
MaybeAddIntConstant(32, true, {index});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fuzz
|
|
||||||
} // namespace spvtools
|
|
@ -1,46 +0,0 @@
|
|||||||
// 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_ADD_USEFUL_CONSTRUCTS_
|
|
||||||
#define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
|
|
||||||
|
|
||||||
#include "source/fuzz/fuzzer_pass.h"
|
|
||||||
|
|
||||||
namespace spvtools {
|
|
||||||
namespace fuzz {
|
|
||||||
|
|
||||||
// An initial pass for adding useful ingredients to the module, such as boolean
|
|
||||||
// constants, if they are not present.
|
|
||||||
class FuzzerPassAddUsefulConstructs : public FuzzerPass {
|
|
||||||
public:
|
|
||||||
FuzzerPassAddUsefulConstructs(
|
|
||||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
|
||||||
FuzzerContext* fuzzer_context,
|
|
||||||
protobufs::TransformationSequence* transformations);
|
|
||||||
|
|
||||||
~FuzzerPassAddUsefulConstructs() override;
|
|
||||||
|
|
||||||
void Apply() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void MaybeAddIntConstant(uint32_t width, bool is_signed,
|
|
||||||
std::vector<uint32_t> data) const;
|
|
||||||
|
|
||||||
void MaybeAddFloatConstant(uint32_t width, std::vector<uint32_t> data) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fuzz
|
|
||||||
} // namespace spvtools
|
|
||||||
|
|
||||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
|
|
@ -14,11 +14,14 @@
|
|||||||
|
|
||||||
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "source/fuzz/fuzzer_util.h"
|
||||||
#include "source/fuzz/instruction_descriptor.h"
|
#include "source/fuzz/instruction_descriptor.h"
|
||||||
#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/uniform_buffer_element_descriptor.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
@ -240,6 +243,29 @@ void FuzzerPassObfuscateConstants::
|
|||||||
first_constant_is_larger);
|
first_constant_is_larger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<uint32_t>>
|
||||||
|
FuzzerPassObfuscateConstants::GetConstantWordsFromUniformsForType(
|
||||||
|
uint32_t type_id) {
|
||||||
|
assert(type_id && "Type id can't be 0");
|
||||||
|
std::vector<std::vector<uint32_t>> result;
|
||||||
|
|
||||||
|
for (const auto& facts_and_types : GetTransformationContext()
|
||||||
|
->GetFactManager()
|
||||||
|
->GetConstantUniformFactsAndTypes()) {
|
||||||
|
if (facts_and_types.second != type_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> words(facts_and_types.first.constant_word().begin(),
|
||||||
|
facts_and_types.first.constant_word().end());
|
||||||
|
if (std::find(result.begin(), result.end(), words) == result.end()) {
|
||||||
|
result.push_back(std::move(words));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
|
void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
|
||||||
uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
|
uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
|
||||||
// We want to replace the boolean constant use with a binary expression over
|
// We want to replace the boolean constant use with a binary expression over
|
||||||
@ -258,11 +284,9 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
|
|||||||
auto chosen_type_id =
|
auto chosen_type_id =
|
||||||
available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
|
available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
|
||||||
available_types_with_uniforms)];
|
available_types_with_uniforms)];
|
||||||
auto available_constants = GetTransformationContext()
|
auto available_constant_words =
|
||||||
->GetFactManager()
|
GetConstantWordsFromUniformsForType(chosen_type_id);
|
||||||
->GetConstantsAvailableFromUniformsForType(
|
if (available_constant_words.size() == 1) {
|
||||||
GetIRContext(), chosen_type_id);
|
|
||||||
if (available_constants.size() == 1) {
|
|
||||||
// TODO(afd): for now we only obfuscate a boolean if there are at least
|
// TODO(afd): for now we only obfuscate a boolean if there are at least
|
||||||
// two constants available from uniforms, so that we can do a
|
// two constants available from uniforms, so that we can do a
|
||||||
// comparison between them. It would be good to be able to do the
|
// comparison between them. It would be good to be able to do the
|
||||||
@ -271,18 +295,25 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(!available_constant_words.empty() &&
|
||||||
|
"There exists a fact but no constants - impossible");
|
||||||
|
|
||||||
// We know we have at least two known-to-be-constant uniforms of the chosen
|
// We know we have at least two known-to-be-constant uniforms of the chosen
|
||||||
// type. Pick one of them at random.
|
// type. Pick one of them at random.
|
||||||
auto constant_index_1 = GetFuzzerContext()->RandomIndex(available_constants);
|
auto constant_index_1 =
|
||||||
|
GetFuzzerContext()->RandomIndex(available_constant_words);
|
||||||
uint32_t constant_index_2;
|
uint32_t constant_index_2;
|
||||||
|
|
||||||
// Now choose another one distinct from the first one.
|
// Now choose another one distinct from the first one.
|
||||||
do {
|
do {
|
||||||
constant_index_2 = GetFuzzerContext()->RandomIndex(available_constants);
|
constant_index_2 =
|
||||||
|
GetFuzzerContext()->RandomIndex(available_constant_words);
|
||||||
} while (constant_index_1 == constant_index_2);
|
} while (constant_index_1 == constant_index_2);
|
||||||
|
|
||||||
auto constant_id_1 = available_constants[constant_index_1];
|
auto constant_id_1 = FindOrCreateConstant(
|
||||||
auto constant_id_2 = available_constants[constant_index_2];
|
available_constant_words[constant_index_1], chosen_type_id);
|
||||||
|
auto constant_id_2 = FindOrCreateConstant(
|
||||||
|
available_constant_words[constant_index_2], chosen_type_id);
|
||||||
|
|
||||||
assert(constant_id_1 != 0 && constant_id_2 != 0 &&
|
assert(constant_id_1 != 0 && constant_id_2 != 0 &&
|
||||||
"We should not find an available constant with an id of 0.");
|
"We should not find an available constant with an id of 0.");
|
||||||
@ -324,18 +355,39 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Choose a random available uniform known to be equal to the constant.
|
// Choose a random available uniform known to be equal to the constant.
|
||||||
protobufs::UniformBufferElementDescriptor uniform_descriptor =
|
const auto& uniform_descriptor =
|
||||||
uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
|
uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
|
||||||
|
|
||||||
|
// Make sure the module has OpConstant instructions for each index used to
|
||||||
|
// access a uniform.
|
||||||
|
for (auto index : uniform_descriptor.index()) {
|
||||||
|
FindOrCreate32BitIntegerConstant(index, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the module has OpTypePointer that points to the element type of
|
||||||
|
// the uniform.
|
||||||
|
const auto* uniform_variable_instr =
|
||||||
|
FindUniformVariable(uniform_descriptor, GetIRContext(), true);
|
||||||
|
assert(uniform_variable_instr &&
|
||||||
|
"Uniform variable does not exist or not unique.");
|
||||||
|
|
||||||
|
const auto* uniform_variable_type_intr =
|
||||||
|
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||||
|
uniform_variable_instr->type_id());
|
||||||
|
assert(uniform_variable_type_intr && "Uniform variable has invalid type");
|
||||||
|
|
||||||
|
auto element_type_id = fuzzerutil::WalkCompositeTypeIndices(
|
||||||
|
GetIRContext(), uniform_variable_type_intr->GetSingleWordInOperand(1),
|
||||||
|
uniform_descriptor.index());
|
||||||
|
assert(element_type_id && "Type of uniform variable is invalid");
|
||||||
|
|
||||||
|
FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
|
||||||
|
|
||||||
// Create, apply and record a transformation to replace the constant use with
|
// Create, apply and record a transformation to replace the constant use with
|
||||||
// the result of a load from the chosen uniform.
|
// the result of a load from the chosen uniform.
|
||||||
auto transformation = TransformationReplaceConstantWithUniform(
|
ApplyTransformation(TransformationReplaceConstantWithUniform(
|
||||||
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
|
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
|
||||||
GetFuzzerContext()->GetFreshId());
|
GetFuzzerContext()->GetFreshId()));
|
||||||
// Transformation should be applicable by construction.
|
|
||||||
assert(
|
|
||||||
transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
|
|
||||||
transformation.Apply(GetIRContext(), GetTransformationContext());
|
|
||||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
||||||
|
@ -99,6 +99,11 @@ class FuzzerPassObfuscateConstants : public FuzzerPass {
|
|||||||
uint32_t base_instruction_result_id,
|
uint32_t base_instruction_result_id,
|
||||||
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
||||||
std::vector<protobufs::IdUseDescriptor>* constant_uses);
|
std::vector<protobufs::IdUseDescriptor>* constant_uses);
|
||||||
|
|
||||||
|
// Returns a vector of unique words that denote constants. Every such constant
|
||||||
|
// is used in |FactConstantUniform| and has type with id equal to |type_id|.
|
||||||
|
std::vector<std::vector<uint32_t>> GetConstantWordsFromUniformsForType(
|
||||||
|
uint32_t type_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fuzz
|
} // namespace fuzz
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||||
|
#include "source/fuzz/transformation_context.h"
|
||||||
#include "source/opt/basic_block.h"
|
#include "source/opt/basic_block.h"
|
||||||
#include "source/opt/instruction.h"
|
#include "source/opt/instruction.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
|
@ -21,7 +21,6 @@ if (${SPIRV_BUILD_FUZZER})
|
|||||||
equivalence_relation_test.cpp
|
equivalence_relation_test.cpp
|
||||||
fact_manager_test.cpp
|
fact_manager_test.cpp
|
||||||
fuzz_test_util.cpp
|
fuzz_test_util.cpp
|
||||||
fuzzer_pass_add_useful_constructs_test.cpp
|
|
||||||
fuzzer_pass_construct_composites_test.cpp
|
fuzzer_pass_construct_composites_test.cpp
|
||||||
fuzzer_pass_donate_modules_test.cpp
|
fuzzer_pass_donate_modules_test.cpp
|
||||||
instruction_descriptor_test.cpp
|
instruction_descriptor_test.cpp
|
||||||
|
@ -1,401 +0,0 @@
|
|||||||
// 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_add_useful_constructs.h"
|
|
||||||
#include "source/fuzz/pseudo_random_generator.h"
|
|
||||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
|
||||||
#include "test/fuzz/fuzz_test_util.h"
|
|
||||||
|
|
||||||
namespace spvtools {
|
|
||||||
namespace fuzz {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool AddFactHelper(
|
|
||||||
FactManager* fact_manager, opt::IRContext* context, uint32_t word,
|
|
||||||
const protobufs::UniformBufferElementDescriptor& descriptor) {
|
|
||||||
protobufs::FactConstantUniform constant_uniform_fact;
|
|
||||||
constant_uniform_fact.add_constant_word(word);
|
|
||||||
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
|
|
||||||
descriptor;
|
|
||||||
protobufs::Fact fact;
|
|
||||||
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
|
|
||||||
return fact_manager->AddFact(fact, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) {
|
|
||||||
// The SPIR-V came from the following empty GLSL shader:
|
|
||||||
//
|
|
||||||
// #version 450
|
|
||||||
//
|
|
||||||
// void main()
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
|
|
||||||
std::string shader = R"(
|
|
||||||
OpCapability Shader
|
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpMemoryModel Logical GLSL450
|
|
||||||
OpEntryPoint Fragment %4 "main"
|
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
|
||||||
OpSource GLSL 450
|
|
||||||
OpName %4 "main"
|
|
||||||
%2 = OpTypeVoid
|
|
||||||
%3 = OpTypeFunction %2
|
|
||||||
%4 = OpFunction %2 None %3
|
|
||||||
%5 = OpLabel
|
|
||||||
OpReturn
|
|
||||||
OpFunctionEnd
|
|
||||||
)";
|
|
||||||
|
|
||||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
|
||||||
const auto consumer = nullptr;
|
|
||||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
|
||||||
ASSERT_TRUE(IsValid(env, context.get()));
|
|
||||||
|
|
||||||
FactManager fact_manager;
|
|
||||||
spvtools::ValidatorOptions validator_options;
|
|
||||||
TransformationContext transformation_context(&fact_manager,
|
|
||||||
validator_options);
|
|
||||||
|
|
||||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
|
||||||
protobufs::TransformationSequence transformation_sequence;
|
|
||||||
|
|
||||||
FuzzerPassAddUsefulConstructs pass(context.get(), &transformation_context,
|
|
||||||
&fuzzer_context, &transformation_sequence);
|
|
||||||
pass.Apply();
|
|
||||||
ASSERT_TRUE(IsValid(env, context.get()));
|
|
||||||
|
|
||||||
std::string after = R"(
|
|
||||||
OpCapability Shader
|
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpMemoryModel Logical GLSL450
|
|
||||||
OpEntryPoint Fragment %4 "main"
|
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
|
||||||
OpSource GLSL 450
|
|
||||||
OpName %4 "main"
|
|
||||||
%2 = OpTypeVoid
|
|
||||||
%3 = OpTypeFunction %2
|
|
||||||
%100 = OpTypeBool
|
|
||||||
%101 = OpTypeInt 32 1
|
|
||||||
%102 = OpTypeInt 32 0
|
|
||||||
%103 = OpTypeFloat 32
|
|
||||||
%104 = OpConstantTrue %100
|
|
||||||
%105 = OpConstantFalse %100
|
|
||||||
%106 = OpConstant %101 0
|
|
||||||
%107 = OpConstant %101 1
|
|
||||||
%108 = OpConstant %102 0
|
|
||||||
%109 = OpConstant %102 1
|
|
||||||
%110 = OpConstant %103 0
|
|
||||||
%111 = OpConstant %103 1
|
|
||||||
%4 = OpFunction %2 None %3
|
|
||||||
%5 = OpLabel
|
|
||||||
OpReturn
|
|
||||||
OpFunctionEnd
|
|
||||||
)";
|
|
||||||
ASSERT_TRUE(IsEqual(env, after, context.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FuzzerPassAddUsefulConstructsTest,
|
|
||||||
CheckTypesIndicesAndConstantsAddedForUniformFacts) {
|
|
||||||
// The SPIR-V came from the following GLSL shader:
|
|
||||||
//
|
|
||||||
// #version 450
|
|
||||||
//
|
|
||||||
// struct S {
|
|
||||||
// int x;
|
|
||||||
// float y;
|
|
||||||
// int z;
|
|
||||||
// int w;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// uniform buf {
|
|
||||||
// S s;
|
|
||||||
// uint w[10];
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// void main() {
|
|
||||||
// }
|
|
||||||
|
|
||||||
std::string shader = R"(
|
|
||||||
OpCapability Shader
|
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpMemoryModel Logical GLSL450
|
|
||||||
OpEntryPoint Fragment %4 "main"
|
|
||||||
OpExecutionMode %4 OriginUpperLeft
|
|
||||||
OpSource GLSL 450
|
|
||||||
OpName %4 "main"
|
|
||||||
OpName %8 "S"
|
|
||||||
OpMemberName %8 0 "x"
|
|
||||||
OpMemberName %8 1 "y"
|
|
||||||
OpMemberName %8 2 "z"
|
|
||||||
OpMemberName %8 3 "w"
|
|
||||||
OpName %12 "buf"
|
|
||||||
OpMemberName %12 0 "s"
|
|
||||||
OpMemberName %12 1 "w"
|
|
||||||
OpName %14 ""
|
|
||||||
OpMemberDecorate %8 0 Offset 0
|
|
||||||
OpMemberDecorate %8 1 Offset 4
|
|
||||||
OpMemberDecorate %8 2 Offset 8
|
|
||||||
OpMemberDecorate %8 3 Offset 12
|
|
||||||
OpDecorate %11 ArrayStride 16
|
|
||||||
OpMemberDecorate %12 0 Offset 0
|
|
||||||
OpMemberDecorate %12 1 Offset 16
|
|
||||||
OpDecorate %12 Block
|
|
||||||
OpDecorate %14 DescriptorSet 0
|
|
||||||
OpDecorate %14 Binding 0
|
|
||||||
%2 = OpTypeVoid
|
|
||||||
%3 = OpTypeFunction %2
|
|
||||||
%6 = OpTypeInt 32 1
|
|
||||||
%7 = OpTypeFloat 32
|
|
||||||
%8 = OpTypeStruct %6 %7 %6 %6
|
|
||||||
%9 = OpTypeInt 32 0
|
|
||||||
%10 = OpConstant %9 10
|
|
||||||
%11 = OpTypeArray %9 %10
|
|
||||||
%12 = OpTypeStruct %8 %11
|
|
||||||
%13 = OpTypePointer Uniform %12
|
|
||||||
%14 = OpVariable %13 Uniform
|
|
||||||
%4 = OpFunction %2 None %3
|
|
||||||
%5 = OpLabel
|
|
||||||
OpReturn
|
|
||||||
OpFunctionEnd
|
|
||||||
)";
|
|
||||||
|
|
||||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
|
||||||
const auto consumer = nullptr;
|
|
||||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
|
||||||
ASSERT_TRUE(IsValid(env, context.get()));
|
|
||||||
|
|
||||||
FactManager fact_manager;
|
|
||||||
spvtools::ValidatorOptions validator_options;
|
|
||||||
TransformationContext transformation_context(&fact_manager,
|
|
||||||
validator_options);
|
|
||||||
|
|
||||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
|
||||||
protobufs::TransformationSequence transformation_sequence;
|
|
||||||
|
|
||||||
// Add some uniform facts.
|
|
||||||
|
|
||||||
// buf.s.x == 200
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {0, 0})));
|
|
||||||
|
|
||||||
// buf.s.y == 0.5
|
|
||||||
const float float_value = 0.5;
|
|
||||||
uint32_t float_value_as_uint;
|
|
||||||
memcpy(&float_value_as_uint, &float_value, sizeof(float_value));
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {0, 1})));
|
|
||||||
|
|
||||||
// buf.s.z == 300
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {0, 2})));
|
|
||||||
|
|
||||||
// buf.s.w == 400
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {0, 3})));
|
|
||||||
|
|
||||||
// buf.w[6] = 22
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {1, 6})));
|
|
||||||
|
|
||||||
// buf.w[8] = 23
|
|
||||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23,
|
|
||||||
MakeUniformBufferElementDescriptor(0, 0, {1, 8})));
|
|
||||||
|
|
||||||
// Assert some things about the module that are not true prior to adding the
|
|
||||||
// pass
|
|
||||||
|
|
||||||
{
|
|
||||||
// No uniform int pointer
|
|
||||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
|
||||||
opt::analysis::Integer* registered_type_signed_int =
|
|
||||||
context->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_type_signed_int)
|
|
||||||
->AsInteger();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
|
||||||
registered_type_signed_int, SpvStorageClassUniform);
|
|
||||||
ASSERT_EQ(0,
|
|
||||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
|
||||||
|
|
||||||
// No uniform uint pointer
|
|
||||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
|
||||||
opt::analysis::Integer* registered_type_unsigned_int =
|
|
||||||
context->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_type_unsigned_int)
|
|
||||||
->AsInteger();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
|
||||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
|
||||||
ASSERT_EQ(
|
|
||||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
|
||||||
|
|
||||||
// No uniform float pointer
|
|
||||||
opt::analysis::Float temp_type_float(32);
|
|
||||||
opt::analysis::Float* registered_type_float =
|
|
||||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
|
||||||
SpvStorageClassUniform);
|
|
||||||
ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
|
||||||
|
|
||||||
// No int constants 200, 300 nor 400
|
|
||||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
|
||||||
{200});
|
|
||||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
|
||||||
{300});
|
|
||||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
|
||||||
{400});
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
|
||||||
|
|
||||||
// No float constant 0.5
|
|
||||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
|
||||||
registered_type_float, {float_value_as_uint});
|
|
||||||
ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(
|
|
||||||
&float_constant_zero_point_five));
|
|
||||||
|
|
||||||
// No uint constant 22
|
|
||||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
|
||||||
{22});
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
|
||||||
|
|
||||||
// No uint constant 23
|
|
||||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
|
||||||
{23});
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
|
||||||
|
|
||||||
// No int constants 0, 1, 2, 3, 6, 8
|
|
||||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
|
||||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
|
||||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
|
||||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
|
||||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
|
||||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
|
||||||
ASSERT_EQ(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
FuzzerPassAddUsefulConstructs pass(context.get(), &transformation_context,
|
|
||||||
&fuzzer_context, &transformation_sequence);
|
|
||||||
pass.Apply();
|
|
||||||
ASSERT_TRUE(IsValid(env, context.get()));
|
|
||||||
|
|
||||||
// Now assert some things about the module that should be true following the
|
|
||||||
// pass.
|
|
||||||
|
|
||||||
// We reconstruct all necessary types and constants to guard against the type
|
|
||||||
// and constant managers for the module having been invalidated.
|
|
||||||
|
|
||||||
{
|
|
||||||
// Uniform int pointer now present
|
|
||||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
|
||||||
opt::analysis::Integer* registered_type_signed_int =
|
|
||||||
context->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_type_signed_int)
|
|
||||||
->AsInteger();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
|
||||||
registered_type_signed_int, SpvStorageClassUniform);
|
|
||||||
ASSERT_NE(0,
|
|
||||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
|
||||||
|
|
||||||
// Uniform uint pointer now present
|
|
||||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
|
||||||
opt::analysis::Integer* registered_type_unsigned_int =
|
|
||||||
context->get_type_mgr()
|
|
||||||
->GetRegisteredType(&temp_type_unsigned_int)
|
|
||||||
->AsInteger();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
|
||||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
|
||||||
ASSERT_NE(
|
|
||||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
|
||||||
|
|
||||||
// Uniform float pointer now present
|
|
||||||
opt::analysis::Float temp_type_float(32);
|
|
||||||
opt::analysis::Float* registered_type_float =
|
|
||||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
|
||||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
|
||||||
SpvStorageClassUniform);
|
|
||||||
ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
|
||||||
|
|
||||||
// int constants 200, 300, 400 now present
|
|
||||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
|
||||||
{200});
|
|
||||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
|
||||||
{300});
|
|
||||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
|
||||||
{400});
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
|
||||||
|
|
||||||
// float constant 0.5 now present
|
|
||||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
|
||||||
registered_type_float, {float_value_as_uint});
|
|
||||||
ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(
|
|
||||||
&float_constant_zero_point_five));
|
|
||||||
|
|
||||||
// uint constant 22 now present
|
|
||||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
|
||||||
{22});
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
|
||||||
|
|
||||||
// uint constant 23 now present
|
|
||||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
|
||||||
{23});
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
|
||||||
|
|
||||||
// int constants 0, 1, 2, 3, 6, 8 now present
|
|
||||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
|
||||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
|
||||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
|
||||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
|
||||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
|
||||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
|
||||||
ASSERT_NE(nullptr,
|
|
||||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace fuzz
|
|
||||||
} // namespace spvtools
|
|
Loading…
Reference in New Issue
Block a user