mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-20 13:53:14 +01:00
Updated spirv-tools.
This commit is contained in:
@@ -1 +1 @@
|
||||
"v2020.4-dev", "SPIRV-Tools v2020.4-dev 0dd31c89ea3db9b4acd6c39bb6f31cc30adf7dc6"
|
||||
"v2020.4-dev", "SPIRV-Tools v2020.4-dev 7efb218fd1272e44be3bc1e891ac153da59e9871"
|
||||
|
||||
12
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
vendored
12
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
vendored
@@ -39,6 +39,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass.h
|
||||
fuzzer_pass_add_access_chains.h
|
||||
fuzzer_pass_add_composite_types.h
|
||||
fuzzer_pass_add_copy_memory.h
|
||||
fuzzer_pass_add_dead_blocks.h
|
||||
fuzzer_pass_add_dead_breaks.h
|
||||
fuzzer_pass_add_dead_continues.h
|
||||
@@ -60,6 +61,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_construct_composites.h
|
||||
fuzzer_pass_copy_objects.h
|
||||
fuzzer_pass_donate_modules.h
|
||||
fuzzer_pass_invert_comparison_operators.h
|
||||
fuzzer_pass_merge_blocks.h
|
||||
fuzzer_pass_obfuscate_constants.h
|
||||
fuzzer_pass_outline_functions.h
|
||||
@@ -87,6 +89,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_constant_composite.h
|
||||
transformation_add_constant_null.h
|
||||
transformation_add_constant_scalar.h
|
||||
transformation_add_copy_memory.h
|
||||
transformation_add_dead_block.h
|
||||
transformation_add_dead_break.h
|
||||
transformation_add_dead_continue.h
|
||||
@@ -95,7 +98,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_global_variable.h
|
||||
transformation_add_local_variable.h
|
||||
transformation_add_no_contraction_decoration.h
|
||||
transformation_add_parameters.h
|
||||
transformation_add_parameter.h
|
||||
transformation_add_spec_constant_op.h
|
||||
transformation_add_type_array.h
|
||||
transformation_add_type_boolean.h
|
||||
@@ -114,6 +117,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_copy_object.h
|
||||
transformation_equation_instruction.h
|
||||
transformation_function_call.h
|
||||
transformation_invert_comparison_operator.h
|
||||
transformation_load.h
|
||||
transformation_merge_blocks.h
|
||||
transformation_move_block_down.h
|
||||
@@ -147,6 +151,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass.cpp
|
||||
fuzzer_pass_add_access_chains.cpp
|
||||
fuzzer_pass_add_composite_types.cpp
|
||||
fuzzer_pass_add_copy_memory.cpp
|
||||
fuzzer_pass_add_dead_blocks.cpp
|
||||
fuzzer_pass_add_dead_breaks.cpp
|
||||
fuzzer_pass_add_dead_continues.cpp
|
||||
@@ -168,6 +173,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_construct_composites.cpp
|
||||
fuzzer_pass_copy_objects.cpp
|
||||
fuzzer_pass_donate_modules.cpp
|
||||
fuzzer_pass_invert_comparison_operators.cpp
|
||||
fuzzer_pass_merge_blocks.cpp
|
||||
fuzzer_pass_obfuscate_constants.cpp
|
||||
fuzzer_pass_outline_functions.cpp
|
||||
@@ -194,6 +200,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_constant_composite.cpp
|
||||
transformation_add_constant_null.cpp
|
||||
transformation_add_constant_scalar.cpp
|
||||
transformation_add_copy_memory.cpp
|
||||
transformation_add_dead_block.cpp
|
||||
transformation_add_dead_break.cpp
|
||||
transformation_add_dead_continue.cpp
|
||||
@@ -202,7 +209,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_global_variable.cpp
|
||||
transformation_add_local_variable.cpp
|
||||
transformation_add_no_contraction_decoration.cpp
|
||||
transformation_add_parameters.cpp
|
||||
transformation_add_parameter.cpp
|
||||
transformation_add_spec_constant_op.cpp
|
||||
transformation_add_type_array.cpp
|
||||
transformation_add_type_boolean.cpp
|
||||
@@ -221,6 +228,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_copy_object.cpp
|
||||
transformation_equation_instruction.cpp
|
||||
transformation_function_call.cpp
|
||||
transformation_invert_comparison_operator.cpp
|
||||
transformation_load.cpp
|
||||
transformation_merge_blocks.cpp
|
||||
transformation_move_block_down.cpp
|
||||
|
||||
8
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
8
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
@@ -23,6 +23,7 @@
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_access_chains.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_composite_types.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_copy_memory.h"
|
||||
#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"
|
||||
@@ -43,6 +44,7 @@
|
||||
#include "source/fuzz/fuzzer_pass_construct_composites.h"
|
||||
#include "source/fuzz/fuzzer_pass_copy_objects.h"
|
||||
#include "source/fuzz/fuzzer_pass_donate_modules.h"
|
||||
#include "source/fuzz/fuzzer_pass_invert_comparison_operators.h"
|
||||
#include "source/fuzz/fuzzer_pass_merge_blocks.h"
|
||||
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
|
||||
#include "source/fuzz/fuzzer_pass_outline_functions.h"
|
||||
@@ -201,6 +203,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassAddCompositeTypes>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddCopyMemory>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddDeadBlocks>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
@@ -246,6 +251,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassDonateModules>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out, donor_suppliers);
|
||||
MaybeAddPass<FuzzerPassInvertComparisonOperators>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassMergeBlocks>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
|
||||
@@ -27,6 +27,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingAccessChain = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingAnotherStructField = {20,
|
||||
90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingCopyMemory = {20, 50};
|
||||
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};
|
||||
@@ -58,6 +59,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfGoingDeeperWhenMakingAccessChain =
|
||||
{50, 95};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfInvertingComparisonOperators = {
|
||||
20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfMakingDonorLivesafe = {40, 60};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfMergingBlocks = {20, 95};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfMovingBlockDown = {20, 50};
|
||||
@@ -119,6 +122,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField);
|
||||
chance_of_adding_array_or_struct_type_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType);
|
||||
chance_of_adding_copy_memory_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingCopyMemory);
|
||||
chance_of_adding_dead_block_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingDeadBlock);
|
||||
chance_of_adding_dead_break_ =
|
||||
@@ -164,6 +169,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfDonatingAdditionalModule);
|
||||
chance_of_going_deeper_when_making_access_chain_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfGoingDeeperWhenMakingAccessChain);
|
||||
chance_of_inverting_comparison_operators_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfInvertingComparisonOperators);
|
||||
chance_of_making_donor_livesafe_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfMakingDonorLivesafe);
|
||||
chance_of_merging_blocks_ = ChooseBetweenMinAndMax(kChanceOfMergingBlocks);
|
||||
|
||||
@@ -114,6 +114,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfAddingArrayOrStructType() {
|
||||
return chance_of_adding_array_or_struct_type_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingCopyMemory() {
|
||||
return chance_of_adding_copy_memory_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingDeadBlock() { return chance_of_adding_dead_block_; }
|
||||
uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; }
|
||||
uint32_t GetChanceOfAddingDeadContinue() {
|
||||
@@ -172,6 +175,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfGoingDeeperWhenMakingAccessChain() {
|
||||
return chance_of_going_deeper_when_making_access_chain_;
|
||||
}
|
||||
uint32_t GetChanceOfInvertingComparisonOperators() {
|
||||
return chance_of_inverting_comparison_operators_;
|
||||
}
|
||||
uint32_t ChanceOfMakingDonorLivesafe() {
|
||||
return chance_of_making_donor_livesafe_;
|
||||
}
|
||||
@@ -274,6 +280,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_adding_access_chain_;
|
||||
uint32_t chance_of_adding_another_struct_field_;
|
||||
uint32_t chance_of_adding_array_or_struct_type_;
|
||||
uint32_t chance_of_adding_copy_memory_;
|
||||
uint32_t chance_of_adding_dead_block_;
|
||||
uint32_t chance_of_adding_dead_break_;
|
||||
uint32_t chance_of_adding_dead_continue_;
|
||||
@@ -298,6 +305,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_copying_object_;
|
||||
uint32_t chance_of_donating_additional_module_;
|
||||
uint32_t chance_of_going_deeper_when_making_access_chain_;
|
||||
uint32_t chance_of_inverting_comparison_operators_;
|
||||
uint32_t chance_of_making_donor_livesafe_;
|
||||
uint32_t chance_of_merging_blocks_;
|
||||
uint32_t chance_of_moving_block_down_;
|
||||
|
||||
31
3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
vendored
31
3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
vendored
@@ -28,6 +28,7 @@
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "source/fuzz/transformation_add_type_matrix.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "source/fuzz/transformation_add_type_struct.h"
|
||||
#include "source/fuzz/transformation_add_type_vector.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -162,9 +163,8 @@ uint32_t FuzzerPass::FindOrCreateBoolType() {
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateIntegerType(uint32_t width, bool is_signed) {
|
||||
opt::analysis::Integer int_type(width, is_signed);
|
||||
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&int_type);
|
||||
if (existing_id) {
|
||||
if (auto existing_id =
|
||||
fuzzerutil::MaybeGetIntegerType(GetIRContext(), width, is_signed)) {
|
||||
return existing_id;
|
||||
}
|
||||
auto result = GetFuzzerContext()->GetFreshId();
|
||||
@@ -173,9 +173,7 @@ uint32_t FuzzerPass::FindOrCreateIntegerType(uint32_t width, bool is_signed) {
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateFloatType(uint32_t width) {
|
||||
opt::analysis::Float float_type(width);
|
||||
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&float_type);
|
||||
if (existing_id) {
|
||||
if (auto existing_id = fuzzerutil::MaybeGetFloatType(GetIRContext(), width)) {
|
||||
return existing_id;
|
||||
}
|
||||
auto result = GetFuzzerContext()->GetFreshId();
|
||||
@@ -205,14 +203,8 @@ uint32_t FuzzerPass::FindOrCreateFunctionType(
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateVectorType(uint32_t component_type_id,
|
||||
uint32_t component_count) {
|
||||
assert(component_count >= 2 && component_count <= 4 &&
|
||||
"Precondition: component count must be in range [2, 4].");
|
||||
opt::analysis::Type* component_type =
|
||||
GetIRContext()->get_type_mgr()->GetType(component_type_id);
|
||||
assert(component_type && "Precondition: the component type must exist.");
|
||||
opt::analysis::Vector vector_type(component_type, component_count);
|
||||
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&vector_type);
|
||||
if (existing_id) {
|
||||
if (auto existing_id = fuzzerutil::MaybeGetVectorType(
|
||||
GetIRContext(), component_type_id, component_count)) {
|
||||
return existing_id;
|
||||
}
|
||||
auto result = GetFuzzerContext()->GetFreshId();
|
||||
@@ -242,6 +234,17 @@ uint32_t FuzzerPass::FindOrCreateMatrixType(uint32_t column_count,
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateStructType(
|
||||
const std::vector<uint32_t>& component_type_ids) {
|
||||
if (auto existing_id =
|
||||
fuzzerutil::MaybeGetStructType(GetIRContext(), component_type_ids)) {
|
||||
return existing_id;
|
||||
}
|
||||
auto new_id = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddTypeStruct(new_id, component_type_ids));
|
||||
return new_id;
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
|
||||
SpvStorageClass storage_class) {
|
||||
// We do not use the type manager here, due to problems related to isomorphic
|
||||
|
||||
@@ -136,6 +136,13 @@ class FuzzerPass {
|
||||
// type itself do not exist, transformations are applied to add them.
|
||||
uint32_t FindOrCreateMatrixType(uint32_t column_count, uint32_t row_count);
|
||||
|
||||
// Returns the id of an OpTypeStruct instruction with |component_type_ids| as
|
||||
// type ids for struct's components. If no such a struct type exists,
|
||||
// transformations are applied to add it. |component_type_ids| may not contain
|
||||
// a result id of an OpTypeFunction.
|
||||
uint32_t FindOrCreateStructType(
|
||||
const std::vector<uint32_t>& component_type_ids);
|
||||
|
||||
// Returns the id of a pointer type with base type |base_type_id| (which must
|
||||
// already exist) and storage class |storage_class|. A transformation is
|
||||
// applied to add the pointer if it does not already exist.
|
||||
|
||||
82
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp
vendored
Normal file
82
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.cpp
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_copy_memory.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_add_copy_memory.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAddCopyMemory::FuzzerPassAddCopyMemory(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassAddCopyMemory::~FuzzerPassAddCopyMemory() = default;
|
||||
|
||||
void FuzzerPassAddCopyMemory::Apply() {
|
||||
ForEachInstructionWithInstructionDescriptor(
|
||||
[this](opt::Function* function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
// Check that we can insert an OpCopyMemory before this instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAddingCopyMemory())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all instructions available before |inst_it| according to the
|
||||
// domination rules.
|
||||
auto instructions = FindAvailableInstructions(
|
||||
function, block, inst_it,
|
||||
TransformationAddCopyMemory::IsInstructionSupported);
|
||||
|
||||
if (instructions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* inst =
|
||||
instructions[GetFuzzerContext()->RandomIndex(instructions)];
|
||||
|
||||
// Decide whether to create global or local variable.
|
||||
auto storage_class = GetFuzzerContext()->ChooseEven()
|
||||
? SpvStorageClassPrivate
|
||||
: SpvStorageClassFunction;
|
||||
|
||||
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
GetIRContext(), inst->type_id());
|
||||
|
||||
// Create a pointer type with |storage_class| if needed.
|
||||
FindOrCreatePointerType(pointee_type_id, storage_class);
|
||||
|
||||
ApplyTransformation(TransformationAddCopyMemory(
|
||||
instruction_descriptor, GetFuzzerContext()->GetFreshId(),
|
||||
inst->result_id(), storage_class,
|
||||
FindOrCreateZeroConstant(pointee_type_id)));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h
vendored
Normal file
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_copy_memory.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_COPY_MEMORY_INSTRUCTIONS_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADD_COPY_MEMORY_INSTRUCTIONS_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Randomly decides whether to add OpCopyMemory before some instruction in the
|
||||
// module.
|
||||
class FuzzerPassAddCopyMemory : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAddCopyMemory(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAddCopyMemory() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_COPY_MEMORY_INSTRUCTIONS_H_
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_add_parameters.h"
|
||||
#include "source/fuzz/transformation_add_parameter.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@@ -57,50 +57,17 @@ void FuzzerPassAddParameters::Apply() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto* type_inst =
|
||||
fuzzerutil::GetFunctionType(GetIRContext(), &function);
|
||||
assert(type_inst);
|
||||
|
||||
// -1 because we don't take return type into account.
|
||||
auto num_old_parameters = type_inst->NumInOperands() - 1;
|
||||
auto num_new_parameters =
|
||||
GetFuzzerContext()->GetRandomNumberOfNewParameters(
|
||||
GetNumberOfParameters(function));
|
||||
|
||||
std::vector<uint32_t> all_types(num_old_parameters);
|
||||
std::vector<uint32_t> new_types(num_new_parameters);
|
||||
std::vector<uint32_t> parameter_ids(num_new_parameters);
|
||||
std::vector<uint32_t> constant_ids(num_new_parameters);
|
||||
|
||||
// Get type ids for old parameters.
|
||||
for (uint32_t i = 0; i < num_old_parameters; ++i) {
|
||||
// +1 since we don't take return type into account.
|
||||
all_types[i] = type_inst->GetSingleWordInOperand(i + 1);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_new_parameters; ++i) {
|
||||
// Get type ids for new parameters.
|
||||
new_types[i] =
|
||||
type_candidates[GetFuzzerContext()->RandomIndex(type_candidates)];
|
||||
|
||||
// Create constants to initialize new parameters from.
|
||||
constant_ids[i] = FindOrCreateZeroConstant(new_types[i]);
|
||||
ApplyTransformation(TransformationAddParameter(
|
||||
function.result_id(), GetFuzzerContext()->GetFreshId(),
|
||||
FindOrCreateZeroConstant(
|
||||
type_candidates[GetFuzzerContext()->RandomIndex(
|
||||
type_candidates)]),
|
||||
GetFuzzerContext()->GetFreshId()));
|
||||
}
|
||||
|
||||
// Append new parameters to the old ones.
|
||||
all_types.insert(all_types.end(), new_types.begin(), new_types.end());
|
||||
|
||||
// Generate result ids for new parameters.
|
||||
for (auto& id : parameter_ids) {
|
||||
id = GetFuzzerContext()->GetFreshId();
|
||||
}
|
||||
|
||||
auto result_type_id = type_inst->GetSingleWordInOperand(0);
|
||||
ApplyTransformation(TransformationAddParameters(
|
||||
function.result_id(),
|
||||
FindOrCreateFunctionType(result_type_id, all_types),
|
||||
std::move(new_types), std::move(parameter_ids),
|
||||
std::move(constant_ids)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
52
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp
vendored
Normal file
52
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_invert_comparison_operators.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_invert_comparison_operator.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassInvertComparisonOperators::FuzzerPassInvertComparisonOperators(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassInvertComparisonOperators::~FuzzerPassInvertComparisonOperators() =
|
||||
default;
|
||||
|
||||
void FuzzerPassInvertComparisonOperators::Apply() {
|
||||
GetIRContext()->module()->ForEachInst([this](const opt::Instruction* inst) {
|
||||
if (!TransformationInvertComparisonOperator::IsInversionSupported(
|
||||
inst->opcode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfInvertingComparisonOperators())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyTransformation(TransformationInvertComparisonOperator(
|
||||
inst->result_id(), GetFuzzerContext()->GetFreshId()));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h
vendored
Normal file
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_invert_comparison_operators.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_INVERT_COMPARISON_OPERATORS_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_INVERT_COMPARISON_OPERATORS_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Iterates over different comparison operators in the module (>=, <, > etc.)
|
||||
// and randomly decides whether to invert each one or not.
|
||||
class FuzzerPassInvertComparisonOperators : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassInvertComparisonOperators(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassInvertComparisonOperators() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_INVERT_COMPARISON_OPERATORS_H_
|
||||
@@ -61,20 +61,9 @@ void FuzzerPassPermuteFunctionParameters::Apply() {
|
||||
std::iota(permutation.begin(), permutation.end(), 0);
|
||||
GetFuzzerContext()->Shuffle(&permutation);
|
||||
|
||||
// Create a new OpFunctionType instruction with permuted arguments
|
||||
// if needed
|
||||
auto result_type_id = function_type->GetSingleWordInOperand(0);
|
||||
std::vector<uint32_t> argument_ids;
|
||||
|
||||
for (auto index : permutation) {
|
||||
// +1 to take function's return type into account
|
||||
argument_ids.push_back(function_type->GetSingleWordInOperand(index + 1));
|
||||
}
|
||||
|
||||
// Apply our transformation
|
||||
ApplyTransformation(TransformationPermuteFunctionParameters(
|
||||
function_id, FindOrCreateFunctionType(result_type_id, argument_ids),
|
||||
permutation));
|
||||
function_id, GetFuzzerContext()->GetFreshId(), permutation));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
186
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp
vendored
186
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp
vendored
@@ -12,11 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
#include "source/opt/build_module.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -590,6 +590,8 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
uint32_t type_id, SpvStorageClass storage_class,
|
||||
uint32_t initializer_id) {
|
||||
// Check various preconditions.
|
||||
assert(result_id != 0 && "Result id can't be 0");
|
||||
|
||||
assert((storage_class == SpvStorageClassPrivate ||
|
||||
storage_class == SpvStorageClassWorkgroup) &&
|
||||
"Variable's storage class must be either Private or Workgroup");
|
||||
@@ -631,6 +633,8 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
uint32_t type_id, uint32_t function_id,
|
||||
uint32_t initializer_id) {
|
||||
// Check various preconditions.
|
||||
assert(result_id != 0 && "Result id can't be 0");
|
||||
|
||||
auto* type_inst = context->get_def_use_mgr()->GetDef(type_id);
|
||||
(void)type_inst; // Variable becomes unused in release mode.
|
||||
assert(type_inst && type_inst->opcode() == SpvOpTypePointer &&
|
||||
@@ -687,6 +691,184 @@ std::vector<opt::Instruction*> GetParameters(opt::IRContext* ir_context,
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddFunctionType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& type_ids) {
|
||||
assert(result_id != 0 && "Result id can't be 0");
|
||||
assert(!type_ids.empty() &&
|
||||
"OpTypeFunction always has at least one operand - function's return "
|
||||
"type");
|
||||
assert(IsNonFunctionTypeId(ir_context, type_ids[0]) &&
|
||||
"Return type must not be a function");
|
||||
|
||||
for (size_t i = 1; i < type_ids.size(); ++i) {
|
||||
const auto* param_type = ir_context->get_type_mgr()->GetType(type_ids[i]);
|
||||
(void)param_type; // Make compiler happy in release mode.
|
||||
assert(param_type && !param_type->AsVoid() && !param_type->AsFunction() &&
|
||||
"Function parameter can't have a function or void type");
|
||||
}
|
||||
|
||||
opt::Instruction::OperandList operands;
|
||||
operands.reserve(type_ids.size());
|
||||
for (auto id : type_ids) {
|
||||
operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
|
||||
}
|
||||
|
||||
ir_context->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeFunction, 0, result_id, std::move(operands)));
|
||||
|
||||
UpdateModuleIdBound(ir_context, result_id);
|
||||
}
|
||||
|
||||
uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context,
|
||||
uint32_t result_id,
|
||||
const std::vector<uint32_t>& type_ids) {
|
||||
if (auto existing_id = FindFunctionType(ir_context, type_ids)) {
|
||||
return existing_id;
|
||||
}
|
||||
AddFunctionType(ir_context, result_id, type_ids);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width,
|
||||
bool is_signed) {
|
||||
opt::analysis::Integer type(width, is_signed);
|
||||
return ir_context->get_type_mgr()->GetId(&type);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width) {
|
||||
opt::analysis::Float type(width);
|
||||
return ir_context->get_type_mgr()->GetId(&type);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
|
||||
uint32_t component_type_id,
|
||||
uint32_t element_count) {
|
||||
const auto* component_type =
|
||||
ir_context->get_type_mgr()->GetType(component_type_id);
|
||||
assert(component_type &&
|
||||
(component_type->AsInteger() || component_type->AsFloat() ||
|
||||
component_type->AsBool()) &&
|
||||
"|component_type_id| is invalid");
|
||||
assert(element_count >= 2 && element_count <= 4 &&
|
||||
"Precondition: component count must be in range [2, 4].");
|
||||
opt::analysis::Vector type(component_type, element_count);
|
||||
return ir_context->get_type_mgr()->GetId(&type);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetStructType(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& component_type_ids) {
|
||||
std::vector<const opt::analysis::Type*> component_types;
|
||||
component_types.reserve(component_type_ids.size());
|
||||
|
||||
for (auto type_id : component_type_ids) {
|
||||
const auto* component_type = ir_context->get_type_mgr()->GetType(type_id);
|
||||
assert(component_type && !component_type->AsFunction() &&
|
||||
"Component type is invalid");
|
||||
component_types.push_back(component_type);
|
||||
}
|
||||
|
||||
opt::analysis::Struct type(component_types);
|
||||
return ir_context->get_type_mgr()->GetId(&type);
|
||||
}
|
||||
|
||||
void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width, bool is_signed) {
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeInt, 0, result_id,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {is_signed ? 1u : 0u}}}));
|
||||
|
||||
UpdateModuleIdBound(ir_context, result_id);
|
||||
}
|
||||
|
||||
void AddFloatType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width) {
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeFloat, 0, result_id,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}}));
|
||||
|
||||
UpdateModuleIdBound(ir_context, result_id);
|
||||
}
|
||||
|
||||
void AddVectorType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t component_type_id, uint32_t element_count) {
|
||||
const auto* component_type =
|
||||
ir_context->get_type_mgr()->GetType(component_type_id);
|
||||
(void)component_type; // Make compiler happy in release mode.
|
||||
assert(component_type &&
|
||||
(component_type->AsInteger() || component_type->AsFloat() ||
|
||||
component_type->AsBool()) &&
|
||||
"|component_type_id| is invalid");
|
||||
assert(element_count >= 2 && element_count <= 4 &&
|
||||
"Precondition: component count must be in range [2, 4].");
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeVector, 0, result_id,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {component_type_id}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {element_count}}}));
|
||||
|
||||
UpdateModuleIdBound(ir_context, result_id);
|
||||
}
|
||||
|
||||
void AddStructType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& component_type_ids) {
|
||||
opt::Instruction::OperandList operands;
|
||||
operands.reserve(component_type_ids.size());
|
||||
|
||||
for (auto type_id : component_type_ids) {
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(type_id);
|
||||
(void)type; // Make compiler happy in release mode.
|
||||
assert(type && !type->AsFunction() && "Component's type id is invalid");
|
||||
operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}});
|
||||
}
|
||||
|
||||
ir_context->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeStruct, 0, result_id, std::move(operands)));
|
||||
|
||||
UpdateModuleIdBound(ir_context, result_id);
|
||||
}
|
||||
|
||||
uint32_t FindOrCreateIntegerType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width, bool is_signed) {
|
||||
if (auto existing_id = MaybeGetIntegerType(ir_context, width, is_signed)) {
|
||||
return existing_id;
|
||||
}
|
||||
AddIntegerType(ir_context, result_id, width, is_signed);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t FindOrCreateFloatType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width) {
|
||||
if (auto existing_id = MaybeGetFloatType(ir_context, width)) {
|
||||
return existing_id;
|
||||
}
|
||||
AddFloatType(ir_context, result_id, width);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t FindOrCreateVectorType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t component_type_id,
|
||||
uint32_t element_count) {
|
||||
if (auto existing_id =
|
||||
MaybeGetVectorType(ir_context, component_type_id, element_count)) {
|
||||
return existing_id;
|
||||
}
|
||||
AddVectorType(ir_context, result_id, component_type_id, element_count);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t FindOrCreateStructType(
|
||||
opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& component_type_ids) {
|
||||
if (auto existing_id = MaybeGetStructType(ir_context, component_type_ids)) {
|
||||
return existing_id;
|
||||
}
|
||||
AddStructType(ir_context, result_id, component_type_ids);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
||||
96
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
vendored
96
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
vendored
@@ -266,6 +266,102 @@ bool IsPermutationOfRange(const std::vector<uint32_t>& arr, uint32_t lo,
|
||||
std::vector<opt::Instruction*> GetParameters(opt::IRContext* ir_context,
|
||||
uint32_t function_id);
|
||||
|
||||
// Creates new OpTypeFunction instruction in the module. |type_ids| may not be
|
||||
// empty. It may not contain result ids of OpTypeFunction instructions.
|
||||
// |type_ids[i]| may not be a result id of OpTypeVoid instruction for |i >= 1|.
|
||||
// |result_id| may not equal to 0. Updates module's id bound to accommodate for
|
||||
// |result_id|.
|
||||
void AddFunctionType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& type_ids);
|
||||
|
||||
// Returns a result id of an OpTypeFunction instruction in the module. Creates a
|
||||
// new instruction if required and returns |result_id|. type_ids| may not be
|
||||
// empty. It may not contain result ids of OpTypeFunction instructions.
|
||||
// |type_ids[i]| may not be a result id of OpTypeVoid instruction for |i >= 1|.
|
||||
// |result_id| must not be equal to 0. Updates module's id bound to accommodate
|
||||
// for |result_id|.
|
||||
uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context,
|
||||
uint32_t result_id,
|
||||
const std::vector<uint32_t>& type_ids);
|
||||
|
||||
// Returns a result id of an OpTypeInt instruction if present. Returns 0
|
||||
// otherwise.
|
||||
uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width,
|
||||
bool is_signed);
|
||||
|
||||
// Returns a result id of an OpTypeFloat instruction if present. Returns 0
|
||||
// otherwise.
|
||||
uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width);
|
||||
|
||||
// Returns a result id of an OpTypeVector instruction if present. Returns 0
|
||||
// otherwise. |component_type_id| must be a valid result id of an OpTypeInt,
|
||||
// OpTypeFloat or OpTypeBool instruction in the module. |element_count| must be
|
||||
// in the range [2, 4].
|
||||
uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
|
||||
uint32_t component_type_id, uint32_t element_count);
|
||||
|
||||
// Returns a result id of an OpTypeStruct instruction if present. Returns 0
|
||||
// otherwise. |component_type_ids| may not contain a result id of an
|
||||
// OpTypeFunction.
|
||||
uint32_t MaybeGetStructType(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& component_type_ids);
|
||||
|
||||
// Creates a new OpTypeInt instruction in the module. Updates module's id bound
|
||||
// to accommodate for |result_id|.
|
||||
void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width, bool is_signed);
|
||||
|
||||
// Creates a new OpTypeFloat instruction in the module. Updates module's id
|
||||
// bound to accommodate for |result_id|.
|
||||
void AddFloatType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width);
|
||||
|
||||
// Creates a new OpTypeVector instruction in the module. |component_type_id|
|
||||
// must be a valid result id of an OpTypeInt, OpTypeFloat or OpTypeBool
|
||||
// instruction in the module. |element_count| must be in the range [2, 4].
|
||||
// Updates module's id bound to accommodate for |result_id|.
|
||||
void AddVectorType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t component_type_id, uint32_t element_count);
|
||||
|
||||
// Creates a new OpTypeStruct instruction in the module. Updates module's id
|
||||
// bound to accommodate for |result_id|. |component_type_ids| may not contain
|
||||
// a result id of an OpTypeFunction.
|
||||
void AddStructType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& component_type_ids);
|
||||
|
||||
// Returns a result id of an OpTypeInt instruction in the module. Creates a new
|
||||
// instruction with |result_id|, if no required OpTypeInt is present in the
|
||||
// module, and returns |result_id|. Updates module's id bound to accommodate for
|
||||
// |result_id|.
|
||||
uint32_t FindOrCreateIntegerType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width, bool is_signed);
|
||||
|
||||
// Returns a result id of an OpTypeFloat instruction in the module. Creates a
|
||||
// new instruction with |result_id|, if no required OpTypeFloat is present in
|
||||
// the module, and returns |result_id|. Updates module's id bound
|
||||
// to accommodate for |result_id|.
|
||||
uint32_t FindOrCreateFloatType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width);
|
||||
|
||||
// Returns a result id of an OpTypeVector instruction in the module. Creates a
|
||||
// new instruction with |result_id|, if no required OpTypeVector is present in
|
||||
// the module, and returns |result_id|. |component_type_id| must be a valid
|
||||
// result id of an OpTypeInt, OpTypeFloat or OpTypeBool instruction in the
|
||||
// module. |element_count| must be in the range [2, 4]. Updates module's id
|
||||
// bound to accommodate for |result_id|.
|
||||
uint32_t FindOrCreateVectorType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t component_type_id,
|
||||
uint32_t element_count);
|
||||
|
||||
// Returns a result id of an OpTypeStruct instruction in the module. Creates a
|
||||
// new instruction with |result_id|, if no required OpTypeStruct is present in
|
||||
// the module, and returns |result_id|. Updates module's id bound
|
||||
// to accommodate for |result_id|. |component_type_ids| may not contain a result
|
||||
// id of an OpTypeFunction.
|
||||
uint32_t FindOrCreateStructType(
|
||||
opt::IRContext* ir_context, uint32_t result_id,
|
||||
const std::vector<uint32_t>& component_type_ids);
|
||||
|
||||
} // namespace fuzzerutil
|
||||
|
||||
} // namespace fuzz
|
||||
|
||||
@@ -380,7 +380,9 @@ message Transformation {
|
||||
TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 49;
|
||||
TransformationSwapConditionalBranchOperands swap_conditional_branch_operands = 50;
|
||||
TransformationPermutePhiOperands permute_phi_operands = 51;
|
||||
TransformationAddParameters add_parameters = 52;
|
||||
TransformationAddParameter add_parameter = 52;
|
||||
TransformationAddCopyMemory add_copy_memory = 53;
|
||||
TransformationInvertComparisonOperator invert_comparison_operator = 54;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@@ -458,6 +460,30 @@ message TransformationAddConstantScalar {
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddCopyMemory {
|
||||
|
||||
// Adds an OpCopyMemory instruction into the module.
|
||||
// Creates either a global or a local variable (based on
|
||||
// |storage_class| field) to copy the target into.
|
||||
|
||||
// OpCopyMemory will be inserted before this instruction.
|
||||
InstructionDescriptor instruction_descriptor = 1;
|
||||
|
||||
// Fresh id to copy memory into.
|
||||
uint32 fresh_id = 2;
|
||||
|
||||
// Source to copy memory from.
|
||||
uint32 source_id = 3;
|
||||
|
||||
// Storage class for the target variable. Can be either Function or Private.
|
||||
uint32 storage_class = 4;
|
||||
|
||||
// Result id for the variable's initializer operand. Its type must be equal to
|
||||
// variable's pointee type.
|
||||
uint32 initializer_id = 5;
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddDeadBlock {
|
||||
|
||||
// Adds a new block to the module that is statically reachable from an
|
||||
@@ -624,24 +650,25 @@ message TransformationAddNoContractionDecoration {
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddParameters {
|
||||
message TransformationAddParameter {
|
||||
|
||||
// Adds new parameters into the function.
|
||||
// Adds a new parameter into the function.
|
||||
|
||||
// Result id of the function to add parameters to.
|
||||
uint32 function_id = 1;
|
||||
|
||||
// New type of the function.
|
||||
uint32 new_type_id = 2;
|
||||
// Fresh id for a new parameter.
|
||||
uint32 parameter_fresh_id = 2;
|
||||
|
||||
// Type ids of parameters to add to the function.
|
||||
repeated uint32 new_parameter_type = 3;
|
||||
// Result id of the instruction, used to initializer new parameter
|
||||
// in function calls. Type id of that instruction is the type id of the parameter.
|
||||
// It may not be OpTypeVoid.
|
||||
uint32 initializer_id = 3;
|
||||
|
||||
// Result ids for new parameters.
|
||||
repeated uint32 new_parameter_id = 4;
|
||||
|
||||
// Constants to initialize new parameters from.
|
||||
repeated uint32 constant_id = 5;
|
||||
// A fresh id for a new function type. This might not be used
|
||||
// if a required function type already exists or if we can change
|
||||
// the old function type.
|
||||
uint32 function_type_fresh_id = 4;
|
||||
|
||||
}
|
||||
|
||||
@@ -916,6 +943,22 @@ message TransformationFunctionCall {
|
||||
|
||||
}
|
||||
|
||||
message TransformationInvertComparisonOperator {
|
||||
|
||||
// For some instruction with result id |operator_id| that
|
||||
// represents a binary comparison operator (e.g. <, >, <=), this transformation
|
||||
// will replace that instruction's result id with |fresh_id|,
|
||||
// invert the opcode (< will become >=) and insert OpLogicalNot
|
||||
// instruction with result id |operator_id| below.
|
||||
|
||||
// Result id of the instruction to invert.
|
||||
uint32 operator_id = 1;
|
||||
|
||||
// Fresh id that will be used by the operator after the inversion.
|
||||
uint32 fresh_id = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationLoad {
|
||||
|
||||
// Transformation that adds an OpLoad instruction from a pointer into an id.
|
||||
@@ -1011,12 +1054,10 @@ message TransformationPermuteFunctionParameters {
|
||||
// Function, whose parameters will be permuted
|
||||
uint32 function_id = 1;
|
||||
|
||||
// |new_type_id| is a result id of a valid OpTypeFunction instruction.
|
||||
// New type is valid if:
|
||||
// - it has the same number of operands as the old one
|
||||
// - function's result type is the same as the old one
|
||||
// - function's arguments are permuted according to |permutation| vector
|
||||
uint32 new_type_id = 2;
|
||||
// Fresh id for a new type of the function. This might not be used
|
||||
// if a required function type already exists or if we can change
|
||||
// the old function type.
|
||||
uint32 function_type_fresh_id = 2;
|
||||
|
||||
// An array of size |n|, where |n| is a number of arguments to a function
|
||||
// with |function_id|. For each i: 0 <= permutation[i] < n.
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "source/fuzz/transformation_add_constant_composite.h"
|
||||
#include "source/fuzz/transformation_add_constant_null.h"
|
||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
||||
#include "source/fuzz/transformation_add_copy_memory.h"
|
||||
#include "source/fuzz/transformation_add_dead_block.h"
|
||||
#include "source/fuzz/transformation_add_dead_break.h"
|
||||
#include "source/fuzz/transformation_add_dead_continue.h"
|
||||
@@ -30,7 +31,7 @@
|
||||
#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_parameters.h"
|
||||
#include "source/fuzz/transformation_add_parameter.h"
|
||||
#include "source/fuzz/transformation_add_spec_constant_op.h"
|
||||
#include "source/fuzz/transformation_add_type_array.h"
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
@@ -48,6 +49,7 @@
|
||||
#include "source/fuzz/transformation_copy_object.h"
|
||||
#include "source/fuzz/transformation_equation_instruction.h"
|
||||
#include "source/fuzz/transformation_function_call.h"
|
||||
#include "source/fuzz/transformation_invert_comparison_operator.h"
|
||||
#include "source/fuzz/transformation_load.h"
|
||||
#include "source/fuzz/transformation_merge_blocks.h"
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
@@ -93,6 +95,8 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
|
||||
return MakeUnique<TransformationAddConstantScalar>(
|
||||
message.add_constant_scalar());
|
||||
case protobufs::Transformation::TransformationCase::kAddCopyMemory:
|
||||
return MakeUnique<TransformationAddCopyMemory>(message.add_copy_memory());
|
||||
case protobufs::Transformation::TransformationCase::kAddDeadBlock:
|
||||
return MakeUnique<TransformationAddDeadBlock>(message.add_dead_block());
|
||||
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
|
||||
@@ -115,8 +119,8 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
kAddNoContractionDecoration:
|
||||
return MakeUnique<TransformationAddNoContractionDecoration>(
|
||||
message.add_no_contraction_decoration());
|
||||
case protobufs::Transformation::TransformationCase::kAddParameters:
|
||||
return MakeUnique<TransformationAddParameters>(message.add_parameters());
|
||||
case protobufs::Transformation::TransformationCase::kAddParameter:
|
||||
return MakeUnique<TransformationAddParameter>(message.add_parameter());
|
||||
case protobufs::Transformation::TransformationCase::kAddSpecConstantOp:
|
||||
return MakeUnique<TransformationAddSpecConstantOp>(
|
||||
message.add_spec_constant_op());
|
||||
@@ -161,6 +165,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
message.equation_instruction());
|
||||
case protobufs::Transformation::TransformationCase::kFunctionCall:
|
||||
return MakeUnique<TransformationFunctionCall>(message.function_call());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kInvertComparisonOperator:
|
||||
return MakeUnique<TransformationInvertComparisonOperator>(
|
||||
message.invert_comparison_operator());
|
||||
case protobufs::Transformation::TransformationCase::kLoad:
|
||||
return MakeUnique<TransformationLoad>(message.load());
|
||||
case protobufs::Transformation::TransformationCase::kMergeBlocks:
|
||||
|
||||
193
3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.cpp
vendored
Normal file
193
3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.cpp
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_copy_memory.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/opt/instruction.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationAddCopyMemory::TransformationAddCopyMemory(
|
||||
const protobufs::TransformationAddCopyMemory& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationAddCopyMemory::TransformationAddCopyMemory(
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor,
|
||||
uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
|
||||
uint32_t initializer_id) {
|
||||
*message_.mutable_instruction_descriptor() = instruction_descriptor;
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_source_id(source_id);
|
||||
message_.set_storage_class(storage_class);
|
||||
message_.set_initializer_id(initializer_id);
|
||||
}
|
||||
|
||||
bool TransformationAddCopyMemory::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// Check that target id is fresh.
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that instruction descriptor is valid. This also checks that
|
||||
// |message_.instruction_descriptor| is not a global instruction.
|
||||
auto* inst = FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||
if (!inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can insert OpCopyMemory before |instruction_descriptor|.
|
||||
auto iter = fuzzerutil::GetIteratorForInstruction(
|
||||
ir_context->get_instr_block(inst), inst);
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory, iter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that source instruction exists and is valid.
|
||||
auto* source_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.source_id());
|
||||
if (!source_inst || !IsInstructionSupported(ir_context, source_inst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |storage_class| is either Function or Private.
|
||||
if (message_.storage_class() != SpvStorageClassFunction &&
|
||||
message_.storage_class() != SpvStorageClassPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
ir_context, source_inst->type_id());
|
||||
|
||||
// OpTypePointer with |message_.storage_class| exists.
|
||||
if (!fuzzerutil::MaybeGetPointerType(
|
||||
ir_context, pointee_type_id,
|
||||
static_cast<SpvStorageClass>(message_.storage_class()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that |initializer_id| exists and has valid type.
|
||||
const auto* initializer_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.initializer_id());
|
||||
if (!initializer_inst || initializer_inst->type_id() != pointee_type_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that domination rules are satisfied.
|
||||
return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, inst,
|
||||
message_.source_id());
|
||||
}
|
||||
|
||||
void TransformationAddCopyMemory::Apply(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const {
|
||||
// Insert OpCopyMemory before |instruction_descriptor|.
|
||||
auto* insert_before_inst =
|
||||
FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||
assert(insert_before_inst);
|
||||
|
||||
auto insert_before_iter = fuzzerutil::GetIteratorForInstruction(
|
||||
ir_context->get_instr_block(insert_before_inst), insert_before_inst);
|
||||
|
||||
insert_before_iter.InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCopyMemory, 0, 0,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.source_id()}}}));
|
||||
|
||||
// Add global or local variable to copy memory into.
|
||||
auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
|
||||
auto type_id = fuzzerutil::MaybeGetPointerType(
|
||||
ir_context,
|
||||
fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
ir_context, fuzzerutil::GetTypeId(ir_context, message_.source_id())),
|
||||
storage_class);
|
||||
|
||||
if (storage_class == SpvStorageClassPrivate) {
|
||||
fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id,
|
||||
storage_class, message_.initializer_id());
|
||||
} else {
|
||||
assert(storage_class == SpvStorageClassFunction &&
|
||||
"Storage class can be either Private or Function");
|
||||
fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), type_id,
|
||||
ir_context->get_instr_block(insert_before_inst)
|
||||
->GetParent()
|
||||
->result_id(),
|
||||
message_.initializer_id());
|
||||
}
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
|
||||
// Even though the copy memory instruction will - at least temporarily - lead
|
||||
// to the destination and source pointers referring to identical values, this
|
||||
// fact is not guaranteed to hold throughout execution of the SPIR-V code
|
||||
// since the source pointer could be over-written. We thus assume nothing
|
||||
// about the destination pointer, and record this fact so that the destination
|
||||
// pointer can be used freely by other fuzzer passes.
|
||||
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
|
||||
message_.fresh_id());
|
||||
|
||||
// Make sure our changes are analyzed
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationAddCopyMemory::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_copy_memory() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TransformationAddCopyMemory::IsInstructionSupported(
|
||||
opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
if (!inst->result_id() || !inst->type_id() ||
|
||||
inst->opcode() == SpvOpConstantNull || inst->opcode() == SpvOpUndef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(inst->type_id());
|
||||
assert(type && "Instruction must have a valid type");
|
||||
|
||||
return type->AsPointer() &&
|
||||
CanUsePointeeWithCopyMemory(*type->AsPointer()->pointee_type());
|
||||
}
|
||||
|
||||
bool TransformationAddCopyMemory::CanUsePointeeWithCopyMemory(
|
||||
const opt::analysis::Type& type) {
|
||||
switch (type.kind()) {
|
||||
case opt::analysis::Type::kBool:
|
||||
case opt::analysis::Type::kInteger:
|
||||
case opt::analysis::Type::kFloat:
|
||||
case opt::analysis::Type::kArray:
|
||||
return true;
|
||||
case opt::analysis::Type::kVector:
|
||||
return CanUsePointeeWithCopyMemory(*type.AsVector()->element_type());
|
||||
case opt::analysis::Type::kMatrix:
|
||||
return CanUsePointeeWithCopyMemory(*type.AsMatrix()->element_type());
|
||||
case opt::analysis::Type::kStruct:
|
||||
return std::all_of(type.AsStruct()->element_types().begin(),
|
||||
type.AsStruct()->element_types().end(),
|
||||
[](const opt::analysis::Type* element) {
|
||||
return CanUsePointeeWithCopyMemory(*element);
|
||||
});
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
74
3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.h
vendored
Normal file
74
3rdparty/spirv-tools/source/fuzz/transformation_add_copy_memory.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_COPY_MEMORY_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_COPY_MEMORY_H_
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationAddCopyMemory : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddCopyMemory(
|
||||
const protobufs::TransformationAddCopyMemory& message);
|
||||
|
||||
TransformationAddCopyMemory(
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor,
|
||||
uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
|
||||
uint32_t initializer_id);
|
||||
|
||||
// - |instruction_descriptor| must point to a valid instruction in the module.
|
||||
// - it should be possible to insert OpCopyMemory before
|
||||
// |instruction_descriptor| (i.e. the module remains valid after the
|
||||
// insertion).
|
||||
// - |source_id| must be a result id for some valid instruction in the module.
|
||||
// - |fresh_id| must be a fresh id to copy memory into.
|
||||
// - type of |source_id| must be OpTypePointer where pointee can be used with
|
||||
// OpCopyMemory.
|
||||
// - |storage_class| must be either Private or Function.
|
||||
// - type ids of instructions with result ids |source_id| and |initialize_id|
|
||||
// must be the same.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// A global or local variable with id |target_id| and |storage_class| class is
|
||||
// created. An 'OpCopyMemory %fresh_id %source_id' instruction is inserted
|
||||
// before the |instruction_descriptor|.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
// Returns true if we can copy memory from |instruction| using OpCopyMemory.
|
||||
static bool IsInstructionSupported(opt::IRContext* ir_context,
|
||||
opt::Instruction* inst);
|
||||
|
||||
private:
|
||||
// Returns whether the type, pointed to by some OpTypePointer, can be used
|
||||
// with OpCopyMemory instruction.
|
||||
static bool CanUsePointeeWithCopyMemory(const opt::analysis::Type& type);
|
||||
|
||||
protobufs::TransformationAddCopyMemory message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_COPY_MEMORY_H_
|
||||
143
3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.cpp
vendored
Normal file
143
3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.cpp
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_parameter.h"
|
||||
|
||||
#include <source/spirv_constant.h>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationAddParameter::TransformationAddParameter(
|
||||
const protobufs::TransformationAddParameter& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationAddParameter::TransformationAddParameter(
|
||||
uint32_t function_id, uint32_t parameter_fresh_id, uint32_t initializer_id,
|
||||
uint32_t function_type_fresh_id) {
|
||||
message_.set_function_id(function_id);
|
||||
message_.set_parameter_fresh_id(parameter_fresh_id);
|
||||
message_.set_initializer_id(initializer_id);
|
||||
message_.set_function_type_fresh_id(function_type_fresh_id);
|
||||
}
|
||||
|
||||
bool TransformationAddParameter::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// Check that function exists
|
||||
const auto* function =
|
||||
fuzzerutil::FindFunction(ir_context, message_.function_id());
|
||||
if (!function ||
|
||||
fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that |initializer_id| is valid.
|
||||
const auto* initializer_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.initializer_id());
|
||||
|
||||
if (!initializer_inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that initializer's type is valid.
|
||||
const auto* initializer_type =
|
||||
ir_context->get_type_mgr()->GetType(initializer_inst->type_id());
|
||||
|
||||
if (!initializer_type || initializer_type->AsVoid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fuzzerutil::IsFreshId(ir_context, message_.parameter_fresh_id()) &&
|
||||
fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()) &&
|
||||
message_.parameter_fresh_id() != message_.function_type_fresh_id();
|
||||
}
|
||||
|
||||
void TransformationAddParameter::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
// Find the function that will be transformed
|
||||
auto* function = fuzzerutil::FindFunction(ir_context, message_.function_id());
|
||||
assert(function && "Can't find the function");
|
||||
|
||||
auto parameter_type_id =
|
||||
fuzzerutil::GetTypeId(ir_context, message_.initializer_id());
|
||||
assert(parameter_type_id != 0 && "Initializer has invalid type");
|
||||
|
||||
// Add new parameters to the function.
|
||||
function->AddParameter(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFunctionParameter, parameter_type_id,
|
||||
message_.parameter_fresh_id(), opt::Instruction::OperandList()));
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.parameter_fresh_id());
|
||||
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403):
|
||||
// Add an PointeeValueIsIrrelevant fact if the parameter is a pointer.
|
||||
|
||||
// Fix all OpFunctionCall instructions.
|
||||
ir_context->get_def_use_mgr()->ForEachUser(
|
||||
&function->DefInst(), [this](opt::Instruction* call) {
|
||||
if (call->opcode() != SpvOpFunctionCall ||
|
||||
call->GetSingleWordInOperand(0) != message_.function_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
|
||||
// it would be good to mark this usage of |id| as irrelevant, so that
|
||||
// we can perform some interesting transformations on it later.
|
||||
call->AddOperand({SPV_OPERAND_TYPE_ID, {message_.initializer_id()}});
|
||||
});
|
||||
|
||||
auto* old_function_type = fuzzerutil::GetFunctionType(ir_context, function);
|
||||
assert(old_function_type && "Function must have a valid type");
|
||||
|
||||
if (ir_context->get_def_use_mgr()->NumUsers(old_function_type) == 1) {
|
||||
// Adjust existing function type if it is used only by this function.
|
||||
old_function_type->AddOperand({SPV_OPERAND_TYPE_ID, {parameter_type_id}});
|
||||
|
||||
// We must make sure that all dependencies of |old_function_type| are
|
||||
// evaluated before |old_function_type| (i.e. the domination rules are not
|
||||
// broken). Thus, we move |old_function_type| to the end of the list of all
|
||||
// types in the module.
|
||||
old_function_type->RemoveFromList();
|
||||
ir_context->AddType(std::unique_ptr<opt::Instruction>(old_function_type));
|
||||
} else {
|
||||
// Otherwise, either create a new type or use an existing one.
|
||||
std::vector<uint32_t> type_ids;
|
||||
type_ids.reserve(old_function_type->NumInOperands() + 1);
|
||||
|
||||
for (uint32_t i = 0, n = old_function_type->NumInOperands(); i < n; ++i) {
|
||||
type_ids.push_back(old_function_type->GetSingleWordInOperand(i));
|
||||
}
|
||||
|
||||
type_ids.push_back(parameter_type_id);
|
||||
|
||||
function->DefInst().SetInOperand(
|
||||
1, {fuzzerutil::FindOrCreateFunctionType(
|
||||
ir_context, message_.function_type_fresh_id(), type_ids)});
|
||||
}
|
||||
|
||||
// Make sure our changes are analyzed.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationAddParameter::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_parameter() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
62
3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.h
vendored
Normal file
62
3rdparty/spirv-tools/source/fuzz/transformation_add_parameter.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_PARAMETER_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETER_H_
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationAddParameter : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddParameter(
|
||||
const protobufs::TransformationAddParameter& message);
|
||||
|
||||
TransformationAddParameter(uint32_t function_id, uint32_t parameter_fresh_id,
|
||||
uint32_t initializer_id,
|
||||
uint32_t function_type_fresh_id);
|
||||
|
||||
// - |function_id| must be a valid result id of some non-entry-point function
|
||||
// in the module.
|
||||
// - |initializer_id| must be a valid result id of some instruction in the
|
||||
// module. Instruction's type may not be OpTypeVoid.
|
||||
// - |parameter_fresh_id| and |function_type_fresh_id| are fresh ids and are
|
||||
// not equal.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// - Creates a new OpFunctionParameter instruction with result id
|
||||
// |parameter_fresh_id| for the function with |function_id|.
|
||||
// - Adjusts function's type to include a new parameter.
|
||||
// - Adds |initializer_id| as a new operand to every OpFunctionCall
|
||||
// instruction that calls the function.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddParameter message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETER_H_
|
||||
@@ -1,201 +0,0 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_parameters.h"
|
||||
|
||||
#include <source/spirv_constant.h>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationAddParameters::TransformationAddParameters(
|
||||
const protobufs::TransformationAddParameters& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationAddParameters::TransformationAddParameters(
|
||||
uint32_t function_id, uint32_t new_type_id,
|
||||
const std::vector<uint32_t>& new_parameter_type,
|
||||
const std::vector<uint32_t>& new_parameter_id,
|
||||
const std::vector<uint32_t>& constant_id) {
|
||||
message_.set_function_id(function_id);
|
||||
message_.set_new_type_id(new_type_id);
|
||||
|
||||
for (auto id : new_parameter_type) {
|
||||
message_.add_new_parameter_type(id);
|
||||
}
|
||||
|
||||
for (auto id : new_parameter_id) {
|
||||
message_.add_new_parameter_id(id);
|
||||
}
|
||||
|
||||
for (auto id : constant_id) {
|
||||
message_.add_constant_id(id);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransformationAddParameters::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// Check that function exists
|
||||
const auto* function =
|
||||
fuzzerutil::FindFunction(ir_context, message_.function_id());
|
||||
if (!function ||
|
||||
fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new parameters.
|
||||
const auto& new_type_ids = message_.new_parameter_type();
|
||||
const auto& new_parameter_ids = message_.new_parameter_id();
|
||||
const auto& constant_ids = message_.constant_id();
|
||||
|
||||
// All three vectors must have the same size.
|
||||
if (new_type_ids.size() != new_parameter_ids.size() ||
|
||||
new_type_ids.size() != constant_ids.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vectors must have at least one component.
|
||||
if (new_type_ids.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that type ids exist in the module and are not OpTypeVoid.
|
||||
for (auto id : new_type_ids) {
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(id);
|
||||
if (!type || type->AsVoid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all parameter ids are fresh.
|
||||
for (auto id : new_parameter_ids) {
|
||||
if (!fuzzerutil::IsFreshId(ir_context, id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that constants exist and have valid type.
|
||||
for (int i = 0, n = constant_ids.size(); i < n; ++i) {
|
||||
const auto* inst = ir_context->get_def_use_mgr()->GetDef(constant_ids[i]);
|
||||
if (!inst || inst->type_id() != new_type_ids[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate new function type.
|
||||
const auto* old_type_inst = fuzzerutil::GetFunctionType(ir_context, function);
|
||||
const auto* new_type_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.new_type_id());
|
||||
|
||||
// Both types must exist.
|
||||
assert(old_type_inst && old_type_inst->opcode() == SpvOpTypeFunction);
|
||||
if (!new_type_inst || new_type_inst->opcode() != SpvOpTypeFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto num_old_parameters = old_type_inst->NumInOperands();
|
||||
auto num_new_parameters = new_type_ids.size();
|
||||
|
||||
// New function type has been added to the module which means that it's valid.
|
||||
// Thus, we don't need to check whether the limit on the number of arguments
|
||||
// is satisfied.
|
||||
|
||||
// New type = old type + new parameters.
|
||||
if (new_type_inst->NumInOperands() !=
|
||||
num_old_parameters + num_new_parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that old parameters and the return type are preserved.
|
||||
for (uint32_t i = 0; i < num_old_parameters; ++i) {
|
||||
if (new_type_inst->GetSingleWordInOperand(i) !=
|
||||
old_type_inst->GetSingleWordInOperand(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that new parameters have been appended.
|
||||
for (int i = 0; i < num_new_parameters; ++i) {
|
||||
if (new_type_inst->GetSingleWordInOperand(i + num_old_parameters) !=
|
||||
new_type_ids[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransformationAddParameters::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
// Retrieve all data from the message
|
||||
auto function_id = message_.function_id();
|
||||
const auto& new_parameter_type = message_.new_parameter_type();
|
||||
const auto& new_parameter_id = message_.new_parameter_id();
|
||||
const auto& constant_id = message_.constant_id();
|
||||
|
||||
// Find the function that will be transformed
|
||||
auto* function = fuzzerutil::FindFunction(ir_context, function_id);
|
||||
assert(function && "Can't find the function");
|
||||
|
||||
// Change function's type
|
||||
function->DefInst().SetInOperand(1, {message_.new_type_id()});
|
||||
|
||||
// Add new parameters to the function.
|
||||
for (int i = 0, n = new_parameter_id.size(); i < n; ++i) {
|
||||
function->AddParameter(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFunctionParameter, new_parameter_type[i],
|
||||
new_parameter_id[i], opt::Instruction::OperandList()));
|
||||
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403):
|
||||
// Add an PointeeValueIsIrrelevant fact if the parameter is a pointer.
|
||||
}
|
||||
|
||||
// Fix all OpFunctionCall instructions.
|
||||
ir_context->get_def_use_mgr()->ForEachUser(
|
||||
&function->DefInst(),
|
||||
[function_id, &constant_id](opt::Instruction* call) {
|
||||
if (call->opcode() != SpvOpFunctionCall ||
|
||||
call->GetSingleWordInOperand(0) != function_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto id : constant_id) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
|
||||
// it would be good to mark this usage of |id| as irrelevant, so that
|
||||
// we can perform some interesting transformations on it later.
|
||||
call->AddOperand({SPV_OPERAND_TYPE_ID, {id}});
|
||||
}
|
||||
});
|
||||
|
||||
// Update module's id bound. We can safely dereference the result of
|
||||
// max_element since |new_parameter_id| is guaranteed to have elements.
|
||||
fuzzerutil::UpdateModuleIdBound(
|
||||
ir_context,
|
||||
*std::max_element(new_parameter_id.begin(), new_parameter_id.end()));
|
||||
|
||||
// Make sure our changes are analyzed.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationAddParameters::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_parameters() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_PARAMETERS_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETERS_H_
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationAddParameters : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddParameters(
|
||||
const protobufs::TransformationAddParameters& message);
|
||||
|
||||
TransformationAddParameters(uint32_t function_id, uint32_t new_type_id,
|
||||
const std::vector<uint32_t>& new_parameter_type,
|
||||
const std::vector<uint32_t>& new_parameter_id,
|
||||
const std::vector<uint32_t>& constant_id);
|
||||
|
||||
// - |function_id| must be a valid result id of some non-entry-point function
|
||||
// in the module.
|
||||
// - |new_type_id| must be a result id of OpTypeFunction instruction.
|
||||
// - New type of the function must have the same return type. New function
|
||||
// parameters must be appended to the old ones.
|
||||
// - |new_parameter_type| contains result ids of some OpType* instructions in
|
||||
// the module. It may not contain result ids of OpTypeVoid.
|
||||
// - |new_parameter_id| contains fresh ids.
|
||||
// - |constant_id| contains result ids used to initialize new parameters. Type
|
||||
// ids of these instructions must be the same as |new_parameter_type| (i.e.
|
||||
// |new_parameter_type[i] == GetDef(constant_id[i])->type_id()|).
|
||||
// - |new_parameter_id|, |new_parameter_type| and |constant_id| should all
|
||||
// have the same size and may not be empty.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// - Creates new OpFunctionParameter instructions for the function with
|
||||
// |function_id|.
|
||||
// - Changes type of the function to |new_type_id|.
|
||||
// - Adds ids from |constant_id| to every OpFunctionCall instruction that
|
||||
// calls the function.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddParameters message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_PARAMETERS_H_
|
||||
@@ -38,17 +38,12 @@ bool TransformationAddTypeFloat::IsApplicable(
|
||||
|
||||
// Applicable if there is no float type with this width already declared in
|
||||
// the module.
|
||||
opt::analysis::Float float_type(message_.width());
|
||||
return ir_context->get_type_mgr()->GetId(&float_type) == 0;
|
||||
return fuzzerutil::MaybeGetFloatType(ir_context, message_.width()) == 0;
|
||||
}
|
||||
|
||||
void TransformationAddTypeFloat::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
opt::Instruction::OperandList width = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}};
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeFloat, 0, message_.fresh_id(), width));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
fuzzerutil::AddFloatType(ir_context, message_.fresh_id(), message_.width());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
|
||||
@@ -55,48 +55,19 @@ bool TransformationAddTypeFunction::IsApplicable(
|
||||
// exactly the same return and argument type ids. (Note that the type manager
|
||||
// does not allow us to check this, as it does not distinguish between
|
||||
// function types with different but isomorphic pointer argument types.)
|
||||
for (auto& inst : ir_context->module()->types_values()) {
|
||||
if (inst.opcode() != SpvOpTypeFunction) {
|
||||
// Consider only OpTypeFunction instructions.
|
||||
continue;
|
||||
}
|
||||
if (inst.GetSingleWordInOperand(0) != message_.return_type_id()) {
|
||||
// Different return types - cannot be the same.
|
||||
continue;
|
||||
}
|
||||
if (inst.NumInOperands() !=
|
||||
1 + static_cast<uint32_t>(message_.argument_type_id().size())) {
|
||||
// Different numbers of arguments - cannot be the same.
|
||||
continue;
|
||||
}
|
||||
bool found_argument_mismatch = false;
|
||||
for (uint32_t index = 1; index < inst.NumInOperands(); index++) {
|
||||
if (message_.argument_type_id(index - 1) !=
|
||||
inst.GetSingleWordInOperand(index)) {
|
||||
// Argument mismatch - cannot be the same.
|
||||
found_argument_mismatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_argument_mismatch) {
|
||||
continue;
|
||||
}
|
||||
// Everything matches - the type is already declared.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
std::vector<uint32_t> type_ids = {message_.return_type_id()};
|
||||
type_ids.insert(type_ids.end(), message_.argument_type_id().begin(),
|
||||
message_.argument_type_id().end());
|
||||
return fuzzerutil::FindFunctionType(ir_context, type_ids) == 0;
|
||||
}
|
||||
|
||||
void TransformationAddTypeFunction::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
opt::Instruction::OperandList in_operands;
|
||||
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.return_type_id()}});
|
||||
for (auto argument_type_id : message_.argument_type_id()) {
|
||||
in_operands.push_back({SPV_OPERAND_TYPE_ID, {argument_type_id}});
|
||||
}
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
std::vector<uint32_t> type_ids = {message_.return_type_id()};
|
||||
type_ids.insert(type_ids.end(), message_.argument_type_id().begin(),
|
||||
message_.argument_type_id().end());
|
||||
|
||||
fuzzerutil::AddFunctionType(ir_context, message_.fresh_id(), type_ids);
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
|
||||
@@ -40,18 +40,14 @@ bool TransformationAddTypeInt::IsApplicable(
|
||||
|
||||
// Applicable if there is no int type with this width and signedness already
|
||||
// declared in the module.
|
||||
opt::analysis::Integer int_type(message_.width(), message_.is_signed());
|
||||
return ir_context->get_type_mgr()->GetId(&int_type) == 0;
|
||||
return fuzzerutil::MaybeGetIntegerType(ir_context, message_.width(),
|
||||
message_.is_signed()) == 0;
|
||||
}
|
||||
|
||||
void TransformationAddTypeInt::Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* /*unused*/) const {
|
||||
opt::Instruction::OperandList in_operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.is_signed() ? 1u : 0u}}};
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeInt, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
fuzzerutil::AddIntegerType(ir_context, message_.fresh_id(), message_.width(),
|
||||
message_.is_signed());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
|
||||
@@ -50,13 +50,10 @@ bool TransformationAddTypeStruct::IsApplicable(
|
||||
|
||||
void TransformationAddTypeStruct::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
opt::Instruction::OperandList in_operands;
|
||||
for (auto member_type : message_.member_type_id()) {
|
||||
in_operands.push_back({SPV_OPERAND_TYPE_ID, {member_type}});
|
||||
}
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeStruct, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
fuzzerutil::AddStructType(
|
||||
ir_context, message_.fresh_id(),
|
||||
std::vector<uint32_t>(message_.member_type_id().begin(),
|
||||
message_.member_type_id().end()));
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
|
||||
@@ -46,13 +46,9 @@ bool TransformationAddTypeVector::IsApplicable(
|
||||
|
||||
void TransformationAddTypeVector::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
opt::Instruction::OperandList in_operands;
|
||||
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.component_type_id()}});
|
||||
in_operands.push_back(
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.component_count()}});
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpTypeVector, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
fuzzerutil::AddVectorType(ir_context, message_.fresh_id(),
|
||||
message_.component_type_id(),
|
||||
message_.component_count());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
|
||||
142
3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.cpp
vendored
Normal file
142
3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.cpp
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_invert_comparison_operator.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationInvertComparisonOperator::TransformationInvertComparisonOperator(
|
||||
protobufs::TransformationInvertComparisonOperator message)
|
||||
: message_(std::move(message)) {}
|
||||
|
||||
TransformationInvertComparisonOperator::TransformationInvertComparisonOperator(
|
||||
uint32_t operator_id, uint32_t fresh_id) {
|
||||
message_.set_operator_id(operator_id);
|
||||
message_.set_fresh_id(fresh_id);
|
||||
}
|
||||
|
||||
bool TransformationInvertComparisonOperator::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// |message_.operator_id| must be valid and inversion must be supported for
|
||||
// it.
|
||||
auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id());
|
||||
if (!inst || !IsInversionSupported(inst->opcode())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can insert negation instruction.
|
||||
auto* block = ir_context->get_instr_block(inst);
|
||||
assert(block && "Instruction must have a basic block");
|
||||
|
||||
auto iter = fuzzerutil::GetIteratorForInstruction(block, inst);
|
||||
++iter;
|
||||
assert(iter != block->end() && "Instruction can't be the last in the block");
|
||||
assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter) &&
|
||||
"Can't insert negation after comparison operator");
|
||||
|
||||
// |message_.fresh_id| must be fresh.
|
||||
return fuzzerutil::IsFreshId(ir_context, message_.fresh_id());
|
||||
}
|
||||
|
||||
void TransformationInvertComparisonOperator::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id());
|
||||
assert(inst && "Result id of an operator is invalid");
|
||||
|
||||
// Insert negation after |inst|.
|
||||
auto iter = fuzzerutil::GetIteratorForInstruction(
|
||||
ir_context->get_instr_block(inst), inst);
|
||||
++iter;
|
||||
|
||||
iter.InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpLogicalNot, inst->type_id(), inst->result_id(),
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}));
|
||||
|
||||
// Change the result id of the original operator to |fresh_id|.
|
||||
inst->SetResultId(message_.fresh_id());
|
||||
|
||||
// Invert the operator.
|
||||
inst->SetOpcode(InvertOpcode(inst->opcode()));
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
|
||||
ir_context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
bool TransformationInvertComparisonOperator::IsInversionSupported(
|
||||
SpvOp opcode) {
|
||||
switch (opcode) {
|
||||
case SpvOpSGreaterThan:
|
||||
case SpvOpSGreaterThanEqual:
|
||||
case SpvOpSLessThan:
|
||||
case SpvOpSLessThanEqual:
|
||||
case SpvOpUGreaterThan:
|
||||
case SpvOpUGreaterThanEqual:
|
||||
case SpvOpULessThan:
|
||||
case SpvOpULessThanEqual:
|
||||
case SpvOpIEqual:
|
||||
case SpvOpINotEqual:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SpvOp TransformationInvertComparisonOperator::InvertOpcode(SpvOp opcode) {
|
||||
assert(IsInversionSupported(opcode) && "Inversion must be supported");
|
||||
|
||||
switch (opcode) {
|
||||
case SpvOpSGreaterThan:
|
||||
return SpvOpSLessThanEqual;
|
||||
case SpvOpSGreaterThanEqual:
|
||||
return SpvOpSLessThan;
|
||||
case SpvOpSLessThan:
|
||||
return SpvOpSGreaterThanEqual;
|
||||
case SpvOpSLessThanEqual:
|
||||
return SpvOpSGreaterThan;
|
||||
case SpvOpUGreaterThan:
|
||||
return SpvOpULessThanEqual;
|
||||
case SpvOpUGreaterThanEqual:
|
||||
return SpvOpULessThan;
|
||||
case SpvOpULessThan:
|
||||
return SpvOpUGreaterThanEqual;
|
||||
case SpvOpULessThanEqual:
|
||||
return SpvOpUGreaterThan;
|
||||
case SpvOpIEqual:
|
||||
return SpvOpINotEqual;
|
||||
case SpvOpINotEqual:
|
||||
return SpvOpIEqual;
|
||||
default:
|
||||
// The program will fail in the debug mode because of the assertion
|
||||
// at the beginning of the function.
|
||||
return SpvOpNop;
|
||||
}
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationInvertComparisonOperator::ToMessage()
|
||||
const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_invert_comparison_operator() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
63
3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.h
vendored
Normal file
63
3rdparty/spirv-tools/source/fuzz/transformation_invert_comparison_operator.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2020 Vasyl Teliman
|
||||
//
|
||||
// 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_INVERT_COMPARISON_OPERATOR_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_INVERT_COMPARISON_OPERATOR_H_
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationInvertComparisonOperator : public Transformation {
|
||||
public:
|
||||
explicit TransformationInvertComparisonOperator(
|
||||
protobufs::TransformationInvertComparisonOperator message);
|
||||
|
||||
TransformationInvertComparisonOperator(uint32_t operator_id,
|
||||
uint32_t fresh_id);
|
||||
|
||||
// - |operator_id| should be a result id of some instruction for which
|
||||
// IsInversionSupported returns true.
|
||||
// - |fresh_id| must be a fresh id.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// Inverts the opcode of the instruction with result id |operator_id| (e.g >=
|
||||
// becomes <) and inserts OpLogicalNot instruction after |operator_id|. Also,
|
||||
// changes the result id of OpLogicalNot to |operator_id| and the result id of
|
||||
// the inverted operator to |fresh_id|.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
// Returns true if |opcode| is supported by this transformation.
|
||||
static bool IsInversionSupported(SpvOp opcode);
|
||||
|
||||
private:
|
||||
// Returns an inverted |opcode| (e.g. < becomes >=, == becomes != etc.)
|
||||
static SpvOp InvertOpcode(SpvOp opcode);
|
||||
|
||||
protobufs::TransformationInvertComparisonOperator message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_INVERT_COMPARISON_OPERATOR_H_
|
||||
@@ -12,10 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_permute_function_parameters.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_permute_function_parameters.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@@ -28,10 +29,10 @@ TransformationPermuteFunctionParameters::
|
||||
|
||||
TransformationPermuteFunctionParameters::
|
||||
TransformationPermuteFunctionParameters(
|
||||
uint32_t function_id, uint32_t new_type_id,
|
||||
uint32_t function_id, uint32_t function_type_fresh_id,
|
||||
const std::vector<uint32_t>& permutation) {
|
||||
message_.set_function_id(function_id);
|
||||
message_.set_new_type_id(new_type_id);
|
||||
message_.set_function_type_fresh_id(function_type_fresh_id);
|
||||
|
||||
for (auto index : permutation) {
|
||||
message_.add_permutation(index);
|
||||
@@ -77,49 +78,46 @@ bool TransformationPermuteFunctionParameters::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that new function's type is valid:
|
||||
// - Has the same number of operands
|
||||
// - Has the same result type as the old one
|
||||
// - Order of arguments is permuted
|
||||
auto new_type_id = message_.new_type_id();
|
||||
const auto* new_type = ir_context->get_def_use_mgr()->GetDef(new_type_id);
|
||||
|
||||
if (!new_type || new_type->opcode() != SpvOpTypeFunction ||
|
||||
new_type->NumInOperands() != function_type->NumInOperands()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that both instructions have the same result type
|
||||
if (new_type->GetSingleWordInOperand(0) !=
|
||||
function_type->GetSingleWordInOperand(0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that new function type has its arguments permuted
|
||||
for (int i = 0, n = static_cast<int>(permutation.size()); i < n; ++i) {
|
||||
// +1 to take return type into account
|
||||
if (new_type->GetSingleWordInOperand(i + 1) !=
|
||||
function_type->GetSingleWordInOperand(permutation[i] + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id());
|
||||
}
|
||||
|
||||
void TransformationPermuteFunctionParameters::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
// Retrieve all data from the message
|
||||
uint32_t function_id = message_.function_id();
|
||||
uint32_t new_type_id = message_.new_type_id();
|
||||
const auto& permutation = message_.permutation();
|
||||
|
||||
// Find the function that will be transformed
|
||||
auto* function = fuzzerutil::FindFunction(ir_context, function_id);
|
||||
auto* function = fuzzerutil::FindFunction(ir_context, message_.function_id());
|
||||
assert(function && "Can't find the function");
|
||||
|
||||
auto* old_function_type_inst =
|
||||
fuzzerutil::GetFunctionType(ir_context, function);
|
||||
assert(old_function_type_inst && "Function must have a valid type");
|
||||
|
||||
// Change function's type
|
||||
function->DefInst().SetInOperand(1, {new_type_id});
|
||||
if (ir_context->get_def_use_mgr()->NumUsers(old_function_type_inst) == 1) {
|
||||
// If only the current function uses |old_function_type_inst| - change it
|
||||
// in-place.
|
||||
opt::Instruction::OperandList permuted_operands = {
|
||||
std::move(old_function_type_inst->GetInOperand(0))};
|
||||
for (auto index : message_.permutation()) {
|
||||
// +1 since the first operand to OpTypeFunction is a return type.
|
||||
permuted_operands.push_back(
|
||||
std::move(old_function_type_inst->GetInOperand(index + 1)));
|
||||
}
|
||||
|
||||
old_function_type_inst->SetInOperands(std::move(permuted_operands));
|
||||
} else {
|
||||
// Either use an existing type or create a new one.
|
||||
std::vector<uint32_t> type_ids = {
|
||||
old_function_type_inst->GetSingleWordInOperand(0)};
|
||||
for (auto index : message_.permutation()) {
|
||||
// +1 since the first operand to OpTypeFunction is a return type.
|
||||
type_ids.push_back(
|
||||
old_function_type_inst->GetSingleWordInOperand(index + 1));
|
||||
}
|
||||
|
||||
function->DefInst().SetInOperand(
|
||||
1, {fuzzerutil::FindOrCreateFunctionType(
|
||||
ir_context, message_.function_type_fresh_id(), type_ids)});
|
||||
}
|
||||
|
||||
// Adjust OpFunctionParameter instructions
|
||||
|
||||
@@ -133,7 +131,7 @@ void TransformationPermuteFunctionParameters::Apply(
|
||||
|
||||
// Permute parameters' ids and types
|
||||
std::vector<uint32_t> permuted_param_id, permuted_param_type;
|
||||
for (auto index : permutation) {
|
||||
for (auto index : message_.permutation()) {
|
||||
permuted_param_id.push_back(param_id[index]);
|
||||
permuted_param_type.push_back(param_type[index]);
|
||||
}
|
||||
@@ -149,10 +147,9 @@ void TransformationPermuteFunctionParameters::Apply(
|
||||
|
||||
// Fix all OpFunctionCall instructions
|
||||
ir_context->get_def_use_mgr()->ForEachUser(
|
||||
&function->DefInst(),
|
||||
[function_id, &permutation](opt::Instruction* call) {
|
||||
&function->DefInst(), [this](opt::Instruction* call) {
|
||||
if (call->opcode() != SpvOpFunctionCall ||
|
||||
call->GetSingleWordInOperand(0) != function_id) {
|
||||
call->GetSingleWordInOperand(0) != message_.function_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,7 +157,7 @@ void TransformationPermuteFunctionParameters::Apply(
|
||||
call->GetInOperand(0) // Function id
|
||||
};
|
||||
|
||||
for (auto index : permutation) {
|
||||
for (auto index : message_.permutation()) {
|
||||
// Take function id into account
|
||||
call_operands.push_back(call->GetInOperand(index + 1));
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ class TransformationPermuteFunctionParameters : public Transformation {
|
||||
const protobufs::TransformationPermuteFunctionParameters& message);
|
||||
|
||||
TransformationPermuteFunctionParameters(
|
||||
uint32_t function_id, uint32_t new_type_id,
|
||||
uint32_t function_id, uint32_t function_type_fresh_id,
|
||||
const std::vector<uint32_t>& permutation);
|
||||
|
||||
// - |function_id| is a valid non-entry-point OpFunction instruction
|
||||
// - |new_type_id| is a result id of a valid OpTypeFunction instruction.
|
||||
// - |function_type_fresh_id| is a fresh id.
|
||||
// New type is valid if:
|
||||
// - it has the same number of operands as the old one
|
||||
// - function's result type is the same as the old one
|
||||
@@ -46,7 +46,7 @@ class TransformationPermuteFunctionParameters : public Transformation {
|
||||
|
||||
// - OpFunction instruction with |result_id == function_id| is changed.
|
||||
// Its arguments are permuted according to the |permutation| vector
|
||||
// - Changed function gets a new type specified by |type_id|
|
||||
// - Adjusts function's type to accommodate for permuted parameters.
|
||||
// - Calls to the function are adjusted accordingly
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
@@ -105,13 +105,17 @@ bool AggressiveDCEPass::IsLocalVar(uint32_t varId) {
|
||||
IsVarOfStorage(varId, SpvStorageClassWorkgroup);
|
||||
}
|
||||
|
||||
void AggressiveDCEPass::AddStores(uint32_t ptrId) {
|
||||
get_def_use_mgr()->ForEachUser(ptrId, [this, ptrId](Instruction* user) {
|
||||
void AggressiveDCEPass::AddStores(Function* func, uint32_t ptrId) {
|
||||
get_def_use_mgr()->ForEachUser(ptrId, [this, ptrId, func](Instruction* user) {
|
||||
// If the user is not a part of |func|, skip it.
|
||||
BasicBlock* blk = context()->get_instr_block(user);
|
||||
if (blk && blk->GetParent() != func) return;
|
||||
|
||||
switch (user->opcode()) {
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain:
|
||||
case SpvOpCopyObject:
|
||||
this->AddStores(user->result_id());
|
||||
this->AddStores(func, user->result_id());
|
||||
break;
|
||||
case SpvOpLoad:
|
||||
break;
|
||||
@@ -169,13 +173,13 @@ bool AggressiveDCEPass::IsTargetDead(Instruction* inst) {
|
||||
return IsDead(tInst);
|
||||
}
|
||||
|
||||
void AggressiveDCEPass::ProcessLoad(uint32_t varId) {
|
||||
void AggressiveDCEPass::ProcessLoad(Function* func, uint32_t varId) {
|
||||
// Only process locals
|
||||
if (!IsLocalVar(varId)) return;
|
||||
// Return if already processed
|
||||
if (live_local_vars_.find(varId) != live_local_vars_.end()) return;
|
||||
// Mark all stores to varId as live
|
||||
AddStores(varId);
|
||||
AddStores(func, varId);
|
||||
// Cache varId as processed
|
||||
live_local_vars_.insert(varId);
|
||||
}
|
||||
@@ -332,6 +336,7 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) {
|
||||
call_in_func_ = false;
|
||||
func_is_entry_point_ = false;
|
||||
private_stores_.clear();
|
||||
live_local_vars_.clear();
|
||||
// Stacks to keep track of when we are inside an if- or loop-construct.
|
||||
// When immediately inside an if- or loop-construct, we do not initially
|
||||
// mark branches live. All other branches must be marked live.
|
||||
@@ -454,7 +459,7 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) {
|
||||
uint32_t varId;
|
||||
(void)GetPtr(liveInst, &varId);
|
||||
if (varId != 0) {
|
||||
ProcessLoad(varId);
|
||||
ProcessLoad(func, varId);
|
||||
}
|
||||
// Process memory copies like loads
|
||||
} else if (liveInst->opcode() == SpvOpCopyMemory ||
|
||||
@@ -463,7 +468,7 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) {
|
||||
(void)GetPtr(liveInst->GetSingleWordInOperand(kCopyMemorySourceAddrInIdx),
|
||||
&varId);
|
||||
if (varId != 0) {
|
||||
ProcessLoad(varId);
|
||||
ProcessLoad(func, varId);
|
||||
}
|
||||
// If merge, add other branches that are part of its control structure
|
||||
} else if (liveInst->opcode() == SpvOpLoopMerge ||
|
||||
@@ -471,23 +476,23 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) {
|
||||
AddBreaksAndContinuesToWorklist(liveInst);
|
||||
// If function call, treat as if it loads from all pointer arguments
|
||||
} else if (liveInst->opcode() == SpvOpFunctionCall) {
|
||||
liveInst->ForEachInId([this](const uint32_t* iid) {
|
||||
liveInst->ForEachInId([this, func](const uint32_t* iid) {
|
||||
// Skip non-ptr args
|
||||
if (!IsPtr(*iid)) return;
|
||||
uint32_t varId;
|
||||
(void)GetPtr(*iid, &varId);
|
||||
ProcessLoad(varId);
|
||||
ProcessLoad(func, varId);
|
||||
});
|
||||
// If function parameter, treat as if it's result id is loaded from
|
||||
} else if (liveInst->opcode() == SpvOpFunctionParameter) {
|
||||
ProcessLoad(liveInst->result_id());
|
||||
ProcessLoad(func, liveInst->result_id());
|
||||
// We treat an OpImageTexelPointer as a load of the pointer, and
|
||||
// that value is manipulated to get the result.
|
||||
} else if (liveInst->opcode() == SpvOpImageTexelPointer) {
|
||||
uint32_t varId;
|
||||
(void)GetPtr(liveInst, &varId);
|
||||
if (varId != 0) {
|
||||
ProcessLoad(varId);
|
||||
ProcessLoad(func, varId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class AggressiveDCEPass : public MemPass {
|
||||
|
||||
// Add all store instruction which use |ptrId|, directly or indirectly,
|
||||
// to the live instruction worklist.
|
||||
void AddStores(uint32_t ptrId);
|
||||
void AddStores(Function* func, uint32_t ptrId);
|
||||
|
||||
// Initialize extensions allowlist
|
||||
void InitExtensions();
|
||||
@@ -99,7 +99,7 @@ class AggressiveDCEPass : public MemPass {
|
||||
bool IsTargetDead(Instruction* inst);
|
||||
|
||||
// If |varId| is local, mark all stores of varId as live.
|
||||
void ProcessLoad(uint32_t varId);
|
||||
void ProcessLoad(Function* func, uint32_t varId);
|
||||
|
||||
// If |bp| is structured header block, returns true and sets |mergeInst| to
|
||||
// the merge instruction, |branchInst| to the branch and |mergeBlockId| to the
|
||||
|
||||
Reference in New Issue
Block a user