mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-18 13:03:05 +01:00
Updated spirv-tools.
This commit is contained in:
@@ -1 +1 @@
|
||||
"v2020.4-dev", "SPIRV-Tools v2020.4-dev 7efb218fd1272e44be3bc1e891ac153da59e9871"
|
||||
"v2020.4-dev", "SPIRV-Tools v2020.4-dev 38bba44706260cfb807097c58ca926c64c3a13d2"
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
{19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"},
|
||||
{20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"},
|
||||
{21, "Google", "Clspv", "Google Clspv"},
|
||||
{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},
|
||||
{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},
|
||||
{23, "Google", "Tint Compiler", "Google Tint Compiler"},
|
||||
10
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
vendored
10
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
vendored
@@ -46,6 +46,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_add_equation_instructions.h
|
||||
fuzzer_pass_add_function_calls.h
|
||||
fuzzer_pass_add_global_variables.h
|
||||
fuzzer_pass_add_image_sample_unused_components.h
|
||||
fuzzer_pass_add_loads.h
|
||||
fuzzer_pass_add_local_variables.h
|
||||
fuzzer_pass_add_no_contraction_decorations.h
|
||||
@@ -70,6 +71,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_permute_phi_operands.h
|
||||
fuzzer_pass_push_ids_through_variables.h
|
||||
fuzzer_pass_replace_linear_algebra_instructions.h
|
||||
fuzzer_pass_replace_parameter_with_global.h
|
||||
fuzzer_pass_split_blocks.h
|
||||
fuzzer_pass_swap_commutable_operands.h
|
||||
fuzzer_pass_swap_conditional_branch_operands.h
|
||||
@@ -96,6 +98,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_function.h
|
||||
transformation_add_global_undef.h
|
||||
transformation_add_global_variable.h
|
||||
transformation_add_image_sample_unused_components.h
|
||||
transformation_add_local_variable.h
|
||||
transformation_add_no_contraction_decoration.h
|
||||
transformation_add_parameter.h
|
||||
@@ -125,10 +128,12 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_permute_function_parameters.h
|
||||
transformation_permute_phi_operands.h
|
||||
transformation_push_id_through_variable.h
|
||||
transformation_record_synonymous_constants.h
|
||||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
transformation_replace_constant_with_uniform.h
|
||||
transformation_replace_id_with_synonym.h
|
||||
transformation_replace_linear_algebra_instruction.h
|
||||
transformation_replace_parameter_with_global.h
|
||||
transformation_set_function_control.h
|
||||
transformation_set_loop_control.h
|
||||
transformation_set_memory_operands_mask.h
|
||||
@@ -158,6 +163,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_add_equation_instructions.cpp
|
||||
fuzzer_pass_add_function_calls.cpp
|
||||
fuzzer_pass_add_global_variables.cpp
|
||||
fuzzer_pass_add_image_sample_unused_components.cpp
|
||||
fuzzer_pass_add_loads.cpp
|
||||
fuzzer_pass_add_local_variables.cpp
|
||||
fuzzer_pass_add_no_contraction_decorations.cpp
|
||||
@@ -182,6 +188,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
fuzzer_pass_permute_phi_operands.cpp
|
||||
fuzzer_pass_push_ids_through_variables.cpp
|
||||
fuzzer_pass_replace_linear_algebra_instructions.cpp
|
||||
fuzzer_pass_replace_parameter_with_global.cpp
|
||||
fuzzer_pass_split_blocks.cpp
|
||||
fuzzer_pass_swap_commutable_operands.cpp
|
||||
fuzzer_pass_swap_conditional_branch_operands.cpp
|
||||
@@ -207,6 +214,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_function.cpp
|
||||
transformation_add_global_undef.cpp
|
||||
transformation_add_global_variable.cpp
|
||||
transformation_add_image_sample_unused_components.cpp
|
||||
transformation_add_local_variable.cpp
|
||||
transformation_add_no_contraction_decoration.cpp
|
||||
transformation_add_parameter.cpp
|
||||
@@ -236,10 +244,12 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_permute_function_parameters.cpp
|
||||
transformation_permute_phi_operands.cpp
|
||||
transformation_push_id_through_variable.cpp
|
||||
transformation_record_synonymous_constants.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
transformation_replace_constant_with_uniform.cpp
|
||||
transformation_replace_id_with_synonym.cpp
|
||||
transformation_replace_linear_algebra_instruction.cpp
|
||||
transformation_replace_parameter_with_global.cpp
|
||||
transformation_set_function_control.cpp
|
||||
transformation_set_loop_control.cpp
|
||||
transformation_set_memory_operands_mask.cpp
|
||||
|
||||
8
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
8
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
@@ -30,6 +30,7 @@
|
||||
#include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_function_calls.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_global_variables.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_loads.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_local_variables.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
|
||||
#include "source/fuzz/fuzzer_pass_push_ids_through_variables.h"
|
||||
#include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h"
|
||||
#include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h"
|
||||
#include "source/fuzz/fuzzer_pass_split_blocks.h"
|
||||
#include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
|
||||
#include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
|
||||
@@ -224,6 +226,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassAddGlobalVariables>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddImageSampleUnusedComponents>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
|
||||
&transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
@@ -272,6 +277,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
MaybeAddPass<FuzzerPassPushIdsThroughVariables>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassReplaceParameterWithGlobal>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
MaybeAddPass<FuzzerPassReplaceLinearAlgebraInstructions>(
|
||||
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
|
||||
transformation_sequence_out);
|
||||
|
||||
@@ -34,6 +34,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingEquationInstruction = {5,
|
||||
90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingGlobalVariable = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingImageSampleUnusedComponents =
|
||||
{20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
|
||||
@@ -54,6 +56,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfCallingFunction = {1, 10};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfChoosingStructTypeVsArrayType = {
|
||||
20, 80};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfChoosingWorkgroupStorageClass = {
|
||||
50, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
|
||||
@@ -72,6 +76,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfPushingIdThroughVariable = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
|
||||
const std::pair<uint32_t, uint32_t>
|
||||
kChanceOfReplacingLinearAlgebraInstructions = {10, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingParametersWithGlobals = {
|
||||
30, 70};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfSwappingConditionalBranchOperands =
|
||||
{10, 70};
|
||||
@@ -135,6 +141,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
chance_of_adding_global_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
|
||||
chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad);
|
||||
chance_of_adding_image_sample_unused_components_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingImageSampleUnusedComponents);
|
||||
chance_of_adding_local_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
|
||||
chance_of_adding_matrix_type_ =
|
||||
@@ -162,6 +170,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfCallingFunction);
|
||||
chance_of_choosing_struct_type_vs_array_type_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType);
|
||||
chance_of_choosing_workgroup_storage_class_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfChoosingWorkgroupStorageClass);
|
||||
chance_of_constructing_composite_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
|
||||
chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
|
||||
@@ -190,6 +200,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
||||
ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
|
||||
chance_of_replacing_linear_algebra_instructions_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions);
|
||||
chance_of_replacing_parameters_with_globals_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfReplacingParametersWithGlobals);
|
||||
chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
|
||||
chance_of_swapping_conditional_branch_operands_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfSwappingConditionalBranchOperands);
|
||||
|
||||
@@ -128,6 +128,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfAddingGlobalVariable() {
|
||||
return chance_of_adding_global_variable_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingImageSampleUnusedComponents() {
|
||||
return chance_of_adding_image_sample_unused_components_;
|
||||
}
|
||||
uint32_t GetChanceOfAddingLoad() { return chance_of_adding_load_; }
|
||||
uint32_t GetChanceOfAddingLocalVariable() {
|
||||
return chance_of_adding_local_variable_;
|
||||
@@ -165,6 +168,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfChoosingStructTypeVsArrayType() {
|
||||
return chance_of_choosing_struct_type_vs_array_type_;
|
||||
}
|
||||
uint32_t GetChanceOfChoosingWorkgroupStorageClass() {
|
||||
return chance_of_choosing_workgroup_storage_class_;
|
||||
}
|
||||
uint32_t GetChanceOfConstructingComposite() {
|
||||
return chance_of_constructing_composite_;
|
||||
}
|
||||
@@ -204,6 +210,9 @@ class FuzzerContext {
|
||||
uint32_t GetChanceOfReplacingLinearAlgebraInstructions() {
|
||||
return chance_of_replacing_linear_algebra_instructions_;
|
||||
}
|
||||
uint32_t GetChanceOfReplacingParametersWithGlobals() {
|
||||
return chance_of_replacing_parameters_with_globals_;
|
||||
}
|
||||
uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
|
||||
uint32_t GetChanceOfSwappingConditionalBranchOperands() {
|
||||
return chance_of_swapping_conditional_branch_operands_;
|
||||
@@ -265,6 +274,11 @@ class FuzzerContext {
|
||||
// Ensure that the array size is non-zero.
|
||||
return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
|
||||
}
|
||||
uint32_t GetRandomUnusedComponentCountForImageSample(
|
||||
uint32_t max_unused_component_count) {
|
||||
// Ensure that the number of unused components is non-zero.
|
||||
return random_generator_->RandomUint32(max_unused_component_count) + 1;
|
||||
}
|
||||
bool GoDeeperInConstantObfuscation(uint32_t depth) {
|
||||
return go_deeper_in_constant_obfuscation_(depth, random_generator_);
|
||||
}
|
||||
@@ -286,6 +300,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_adding_dead_continue_;
|
||||
uint32_t chance_of_adding_equation_instruction_;
|
||||
uint32_t chance_of_adding_global_variable_;
|
||||
uint32_t chance_of_adding_image_sample_unused_components_;
|
||||
uint32_t chance_of_adding_load_;
|
||||
uint32_t chance_of_adding_local_variable_;
|
||||
uint32_t chance_of_adding_matrix_type_;
|
||||
@@ -301,6 +316,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_adjusting_selection_control_;
|
||||
uint32_t chance_of_calling_function_;
|
||||
uint32_t chance_of_choosing_struct_type_vs_array_type_;
|
||||
uint32_t chance_of_choosing_workgroup_storage_class_;
|
||||
uint32_t chance_of_constructing_composite_;
|
||||
uint32_t chance_of_copying_object_;
|
||||
uint32_t chance_of_donating_additional_module_;
|
||||
@@ -316,6 +332,7 @@ class FuzzerContext {
|
||||
uint32_t chance_of_pushing_id_through_variable_;
|
||||
uint32_t chance_of_replacing_id_with_synonym_;
|
||||
uint32_t chance_of_replacing_linear_algebra_instructions_;
|
||||
uint32_t chance_of_replacing_parameters_with_globals_;
|
||||
uint32_t chance_of_splitting_block_;
|
||||
uint32_t chance_of_swapping_conditional_branch_operands_;
|
||||
uint32_t chance_of_toggling_access_chain_instruction_;
|
||||
|
||||
@@ -30,8 +30,22 @@ FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
|
||||
FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default;
|
||||
|
||||
void FuzzerPassAddGlobalVariables::Apply() {
|
||||
SpvStorageClass variable_storage_class = SpvStorageClassPrivate;
|
||||
for (auto& entry_point : GetIRContext()->module()->entry_points()) {
|
||||
// If the execution model of some entry point is GLCompute,
|
||||
// then the variable storage class may be Workgroup.
|
||||
if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) {
|
||||
variable_storage_class =
|
||||
GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass())
|
||||
? SpvStorageClassWorkgroup
|
||||
: SpvStorageClassPrivate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto basic_type_ids_and_pointers =
|
||||
GetAvailableBasicTypesAndPointers(SpvStorageClassPrivate);
|
||||
GetAvailableBasicTypesAndPointers(variable_storage_class);
|
||||
|
||||
// These are the basic types that are available to this fuzzer pass.
|
||||
auto& basic_types = basic_type_ids_and_pointers.first;
|
||||
@@ -59,18 +73,21 @@ void FuzzerPassAddGlobalVariables::Apply() {
|
||||
pointer_type_id = GetFuzzerContext()->GetFreshId();
|
||||
available_pointers_to_basic_type.push_back(pointer_type_id);
|
||||
ApplyTransformation(TransformationAddTypePointer(
|
||||
pointer_type_id, SpvStorageClassPrivate, basic_type));
|
||||
pointer_type_id, variable_storage_class, basic_type));
|
||||
} else {
|
||||
// There is - grab one.
|
||||
pointer_type_id =
|
||||
available_pointers_to_basic_type[GetFuzzerContext()->RandomIndex(
|
||||
available_pointers_to_basic_type)];
|
||||
}
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3274): We could
|
||||
// add new variables with Workgroup storage class in compute shaders.
|
||||
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
GetFuzzerContext()->GetFreshId(), pointer_type_id,
|
||||
SpvStorageClassPrivate, FindOrCreateZeroConstant(basic_type), true));
|
||||
variable_storage_class,
|
||||
variable_storage_class == SpvStorageClassPrivate
|
||||
? FindOrCreateZeroConstant(basic_type)
|
||||
: 0,
|
||||
true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
200
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp
vendored
Normal file
200
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2020 André Perez Maselco
|
||||
//
|
||||
// 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_image_sample_unused_components.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
|
||||
#include "source/fuzz/transformation_composite_construct.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassAddImageSampleUnusedComponents::
|
||||
FuzzerPassAddImageSampleUnusedComponents(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassAddImageSampleUnusedComponents::
|
||||
~FuzzerPassAddImageSampleUnusedComponents() = default;
|
||||
|
||||
void FuzzerPassAddImageSampleUnusedComponents::Apply() {
|
||||
// SPIR-V module to help understand the transformation.
|
||||
//
|
||||
// OpCapability Shader
|
||||
// %1 = OpExtInstImport "GLSL.std.450"
|
||||
// OpMemoryModel Logical GLSL450
|
||||
// OpEntryPoint Fragment %15 "main" %12 %14
|
||||
// OpExecutionMode %15 OriginUpperLeft
|
||||
//
|
||||
// ; Decorations
|
||||
// OpDecorate %12 Location 0 ; Input color variable location
|
||||
// OpDecorate %13 DescriptorSet 0 ; Image coordinate variable
|
||||
// descriptor set OpDecorate %13 Binding 0 ; Image coordinate
|
||||
// variable binding OpDecorate %14 Location 0 ; Fragment color
|
||||
// variable location
|
||||
//
|
||||
// ; Types
|
||||
// %2 = OpTypeVoid
|
||||
// %3 = OpTypeFunction %2
|
||||
// %4 = OpTypeFloat 32
|
||||
// %5 = OpTypeVector %4 2
|
||||
// %6 = OpTypeVector %4 4
|
||||
// %7 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
|
||||
// %8 = OpTypeSampledImage %7
|
||||
// %9 = OpTypePointer Input %5
|
||||
// %10 = OpTypePointer UniformConstant %8
|
||||
// %11 = OpTypePointer Output %6
|
||||
//
|
||||
// ; Variables
|
||||
// %12 = OpVariable %9 Input ; Input image coordinate variable
|
||||
// %13 = OpVariable %10 UniformConstant ; Image variable
|
||||
// %14 = OpVariable %11 Output ; Fragment color variable
|
||||
//
|
||||
// ; main function
|
||||
// %15 = OpFunction %2 None %3
|
||||
// %16 = OpLabel
|
||||
// %17 = OpLoad %5 %12
|
||||
// %18 = OpLoad %8 %13
|
||||
// %19 = OpImageSampleImplicitLod %6 %18 %17
|
||||
// OpStore %14 %19
|
||||
// OpReturn
|
||||
// OpFunctionEnd
|
||||
|
||||
GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
|
||||
// |instruction| %19 = OpImageSampleImplicitLod %6 %18 %17
|
||||
if (!spvOpcodeIsImageSample(instruction->opcode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()
|
||||
->GetChanceOfAddingImageSampleUnusedComponents())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Gets image sample coordinate information.
|
||||
// |coordinate_instruction| %17 = OpLoad %5 %12
|
||||
uint32_t coordinate_id = instruction->GetSingleWordInOperand(1);
|
||||
auto coordinate_instruction =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(coordinate_id);
|
||||
auto coordinate_type = GetIRContext()->get_type_mgr()->GetType(
|
||||
coordinate_instruction->type_id());
|
||||
|
||||
// If the coordinate is a 4-dimensional vector, then no unused components
|
||||
// may be added.
|
||||
if (coordinate_type->AsVector() &&
|
||||
coordinate_type->AsVector()->element_count() == 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the coordinate is a scalar, then at most 3 unused components may be
|
||||
// added. If the coordinate is a vector, then the maximum number of unused
|
||||
// components depends on the vector size.
|
||||
// For the sample module, the coordinate type instruction is %5 =
|
||||
// OpTypeVector %4 2, thus |max_unused_component_count| = 4 - 2 = 2.
|
||||
uint32_t max_unused_component_count =
|
||||
coordinate_type->AsInteger() || coordinate_type->AsFloat()
|
||||
? 3
|
||||
: 4 - coordinate_type->AsVector()->element_count();
|
||||
|
||||
// |unused_component_count| may be 1 or 2.
|
||||
uint32_t unused_component_count =
|
||||
GetFuzzerContext()->GetRandomUnusedComponentCountForImageSample(
|
||||
max_unused_component_count);
|
||||
|
||||
// Gets a type for the zero-unused components.
|
||||
uint32_t zero_constant_type_id;
|
||||
switch (unused_component_count) {
|
||||
case 1:
|
||||
// If the coordinate is an integer or float, then the unused components
|
||||
// type is the same as the coordinate. If the coordinate is a vector,
|
||||
// then the unused components type is the same as the vector components
|
||||
// type.
|
||||
zero_constant_type_id =
|
||||
coordinate_type->AsInteger() || coordinate_type->AsFloat()
|
||||
? coordinate_instruction->type_id()
|
||||
: GetIRContext()->get_type_mgr()->GetId(
|
||||
coordinate_type->AsVector()->element_type());
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
// If the coordinate is an integer or float, then the unused components
|
||||
// type is the same as the coordinate. If the coordinate is a vector,
|
||||
// then the unused components type is the same as the coordinate
|
||||
// components type.
|
||||
// |zero_constant_type_id| %5 = OpTypeVector %4 2
|
||||
zero_constant_type_id =
|
||||
coordinate_type->AsInteger() || coordinate_type->AsFloat()
|
||||
? FindOrCreateVectorType(coordinate_instruction->type_id(),
|
||||
unused_component_count)
|
||||
: FindOrCreateVectorType(
|
||||
GetIRContext()->get_type_mgr()->GetId(
|
||||
coordinate_type->AsVector()->element_type()),
|
||||
unused_component_count);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable.");
|
||||
zero_constant_type_id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Gets |coordinate_type| again because the module may have changed due to
|
||||
// the use of FindOrCreateVectorType above.
|
||||
coordinate_type = GetIRContext()->get_type_mgr()->GetType(
|
||||
coordinate_instruction->type_id());
|
||||
|
||||
// If the new vector type with unused components does not exist, then create
|
||||
// it. |coordinate_with_unused_components_type_id| %6 = OpTypeVector %4 4
|
||||
uint32_t coordinate_with_unused_components_type_id =
|
||||
coordinate_type->AsInteger() || coordinate_type->AsFloat()
|
||||
? FindOrCreateVectorType(coordinate_instruction->type_id(),
|
||||
1 + unused_component_count)
|
||||
: FindOrCreateVectorType(
|
||||
GetIRContext()->get_type_mgr()->GetId(
|
||||
coordinate_type->AsVector()->element_type()),
|
||||
coordinate_type->AsVector()->element_count() +
|
||||
unused_component_count);
|
||||
|
||||
// Inserts an OpCompositeConstruct instruction which
|
||||
// represents the coordinate with unused components.
|
||||
// |coordinate_with_unused_components_id|
|
||||
// %22 = OpCompositeConstruct %6 %17 %21
|
||||
uint32_t coordinate_with_unused_components_id =
|
||||
GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationCompositeConstruct(
|
||||
coordinate_with_unused_components_type_id,
|
||||
{coordinate_instruction->result_id(),
|
||||
// FindOrCreateZeroConstant
|
||||
// %20 = OpConstant %4 0
|
||||
// %21 = OpConstantComposite %5 %20 %20
|
||||
FindOrCreateZeroConstant(zero_constant_type_id)},
|
||||
MakeInstructionDescriptor(GetIRContext(), instruction),
|
||||
coordinate_with_unused_components_id));
|
||||
|
||||
// Tries to add unused components to the image sample coordinate.
|
||||
// %19 = OpImageSampleImplicitLod %6 %18 %22
|
||||
ApplyTransformation(TransformationAddImageSampleUnusedComponents(
|
||||
coordinate_with_unused_components_id,
|
||||
MakeInstructionDescriptor(GetIRContext(), instruction)));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
41
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h
vendored
Normal file
41
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2020 André Perez Maselco
|
||||
//
|
||||
// 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_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// This fuzzer pass searches for image sample instructions in the module and
|
||||
// randomly applies the transformation to add unused components to the image
|
||||
// sample coordinate.
|
||||
class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassAddImageSampleUnusedComponents(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassAddImageSampleUnusedComponents();
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
|
||||
@@ -43,6 +43,8 @@ void FuzzerPassReplaceLinearAlgebraInstructions::Apply() {
|
||||
// |spvOpcodeIsLinearAlgebra|.
|
||||
if (instruction->opcode() != SpvOpVectorTimesScalar &&
|
||||
instruction->opcode() != SpvOpMatrixTimesScalar &&
|
||||
instruction->opcode() != SpvOpVectorTimesMatrix &&
|
||||
instruction->opcode() != SpvOpMatrixTimesVector &&
|
||||
instruction->opcode() != SpvOpDot) {
|
||||
return;
|
||||
}
|
||||
|
||||
92
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
vendored
Normal file
92
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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_replace_parameter_with_global.h"
|
||||
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_replace_parameter_with_global.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
FuzzerPassReplaceParameterWithGlobal::FuzzerPassReplaceParameterWithGlobal(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassReplaceParameterWithGlobal::~FuzzerPassReplaceParameterWithGlobal() =
|
||||
default;
|
||||
|
||||
void FuzzerPassReplaceParameterWithGlobal::Apply() {
|
||||
for (const auto& function : *GetIRContext()->module()) {
|
||||
if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(),
|
||||
function.result_id())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfReplacingParametersWithGlobals())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto params =
|
||||
fuzzerutil::GetParameters(GetIRContext(), function.result_id());
|
||||
|
||||
// Make sure at least one parameter can be replaced. Also checks that the
|
||||
// function has at least one parameter.
|
||||
if (std::none_of(params.begin(), params.end(),
|
||||
[this](const opt::Instruction* param) {
|
||||
const auto* param_type =
|
||||
GetIRContext()->get_type_mgr()->GetType(
|
||||
param->type_id());
|
||||
assert(param_type && "Parameter has invalid type");
|
||||
return TransformationReplaceParameterWithGlobal::
|
||||
CanReplaceFunctionParameterType(*param_type);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select id of a parameter to replace.
|
||||
const opt::Instruction* replaced_param = nullptr;
|
||||
const opt::analysis::Type* param_type = nullptr;
|
||||
do {
|
||||
replaced_param = GetFuzzerContext()->RemoveAtRandomIndex(¶ms);
|
||||
param_type =
|
||||
GetIRContext()->get_type_mgr()->GetType(replaced_param->type_id());
|
||||
assert(param_type && "Parameter has invalid type");
|
||||
} while (!TransformationReplaceParameterWithGlobal::
|
||||
CanReplaceFunctionParameterType(*param_type));
|
||||
|
||||
assert(replaced_param && "Unable to find a parameter to replace");
|
||||
|
||||
// Make sure type id for the global variable exists in the module.
|
||||
FindOrCreatePointerType(replaced_param->type_id(), SpvStorageClassPrivate);
|
||||
|
||||
// Make sure initializer for the global variable exists in the module.
|
||||
FindOrCreateZeroConstant(replaced_param->type_id());
|
||||
|
||||
ApplyTransformation(TransformationReplaceParameterWithGlobal(
|
||||
GetFuzzerContext()->GetFreshId(), replaced_param->result_id(),
|
||||
GetFuzzerContext()->GetFreshId()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h
vendored
Normal file
40
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.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_REPLACE_PARAMETER_WITH_GLOBAL_H_
|
||||
#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Iterates over all non-entry-point functions in the module and randomly
|
||||
// replaces a parameter with a global variable.
|
||||
class FuzzerPassReplaceParameterWithGlobal : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassReplaceParameterWithGlobal(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassReplaceParameterWithGlobal() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_
|
||||
211
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp
vendored
211
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp
vendored
@@ -112,19 +112,6 @@ bool PhiIdsOkForNewEdge(
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value) {
|
||||
opt::analysis::Bool bool_type;
|
||||
auto registered_bool_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&bool_type);
|
||||
if (!registered_bool_type) {
|
||||
return 0;
|
||||
}
|
||||
opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
|
||||
value);
|
||||
return context->get_constant_mgr()->FindDeclaredConstant(
|
||||
&bool_constant, context->get_type_mgr()->GetId(&bool_type));
|
||||
}
|
||||
|
||||
void AddUnreachableEdgeAndUpdateOpPhis(
|
||||
opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
|
||||
bool condition_value,
|
||||
@@ -135,7 +122,7 @@ void AddUnreachableEdgeAndUpdateOpPhis(
|
||||
"Precondition on terminator of bb_from is not satisfied");
|
||||
|
||||
// Get the id of the boolean constant to be used as the condition.
|
||||
uint32_t bool_id = MaybeGetBoolConstantId(context, condition_value);
|
||||
uint32_t bool_id = MaybeGetBoolConstant(context, condition_value);
|
||||
assert(
|
||||
bool_id &&
|
||||
"Precondition that condition value must be available is not satisfied");
|
||||
@@ -627,6 +614,7 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
context, SpvOpVariable, type_id, result_id, std::move(operands)));
|
||||
|
||||
AddVariableIdToEntryPointInterfaces(context, result_id);
|
||||
UpdateModuleIdBound(context, result_id);
|
||||
}
|
||||
|
||||
void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
@@ -657,6 +645,8 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
|
||||
{SPV_OPERAND_TYPE_ID, {initializer_id}}}));
|
||||
|
||||
UpdateModuleIdBound(context, result_id);
|
||||
}
|
||||
|
||||
bool HasDuplicates(const std::vector<uint32_t>& arr) {
|
||||
@@ -771,6 +761,199 @@ uint32_t MaybeGetStructType(opt::IRContext* ir_context,
|
||||
return ir_context->get_type_mgr()->GetId(&type);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetZeroConstant(opt::IRContext* ir_context,
|
||||
uint32_t scalar_or_composite_type_id) {
|
||||
const auto* type =
|
||||
ir_context->get_type_mgr()->GetType(scalar_or_composite_type_id);
|
||||
assert(type && "|scalar_or_composite_type_id| is invalid");
|
||||
|
||||
switch (type->kind()) {
|
||||
case opt::analysis::Type::kBool:
|
||||
return MaybeGetBoolConstant(ir_context, false);
|
||||
case opt::analysis::Type::kFloat:
|
||||
case opt::analysis::Type::kInteger: {
|
||||
std::vector<uint32_t> words = {0};
|
||||
if ((type->AsInteger() && type->AsInteger()->width() > 32) ||
|
||||
(type->AsFloat() && type->AsFloat()->width() > 32)) {
|
||||
words.push_back(0);
|
||||
}
|
||||
|
||||
return MaybeGetScalarConstant(ir_context, words,
|
||||
scalar_or_composite_type_id);
|
||||
}
|
||||
case opt::analysis::Type::kStruct: {
|
||||
std::vector<uint32_t> component_ids;
|
||||
for (const auto* component_type : type->AsStruct()->element_types()) {
|
||||
auto component_type_id =
|
||||
ir_context->get_type_mgr()->GetId(component_type);
|
||||
assert(component_type_id && "Component type is invalid");
|
||||
|
||||
auto component_id = MaybeGetZeroConstant(ir_context, component_type_id);
|
||||
if (component_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
component_ids.push_back(component_id);
|
||||
}
|
||||
|
||||
return MaybeGetCompositeConstant(ir_context, component_ids,
|
||||
scalar_or_composite_type_id);
|
||||
}
|
||||
case opt::analysis::Type::kMatrix:
|
||||
case opt::analysis::Type::kVector: {
|
||||
const auto* component_type = type->AsVector()
|
||||
? type->AsVector()->element_type()
|
||||
: type->AsMatrix()->element_type();
|
||||
auto component_type_id =
|
||||
ir_context->get_type_mgr()->GetId(component_type);
|
||||
assert(component_type_id && "Component type is invalid");
|
||||
|
||||
if (auto component_id =
|
||||
MaybeGetZeroConstant(ir_context, component_type_id)) {
|
||||
auto component_count = type->AsVector()
|
||||
? type->AsVector()->element_count()
|
||||
: type->AsMatrix()->element_count();
|
||||
return MaybeGetCompositeConstant(
|
||||
ir_context, std::vector<uint32_t>(component_count, component_id),
|
||||
scalar_or_composite_type_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case opt::analysis::Type::kArray: {
|
||||
auto component_type_id =
|
||||
ir_context->get_type_mgr()->GetId(type->AsArray()->element_type());
|
||||
assert(component_type_id && "Component type is invalid");
|
||||
|
||||
if (auto component_id =
|
||||
MaybeGetZeroConstant(ir_context, component_type_id)) {
|
||||
auto type_id = ir_context->get_type_mgr()->GetId(type);
|
||||
assert(type_id && "|type| is invalid");
|
||||
|
||||
const auto* type_inst = ir_context->get_def_use_mgr()->GetDef(type_id);
|
||||
assert(type_inst && "Array's type id is invalid");
|
||||
|
||||
return MaybeGetCompositeConstant(
|
||||
ir_context,
|
||||
std::vector<uint32_t>(GetArraySize(*type_inst, ir_context),
|
||||
component_id),
|
||||
scalar_or_composite_type_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
assert(false && "Type is not supported");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MaybeGetScalarConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t scalar_type_id) {
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(scalar_type_id);
|
||||
assert(type && "|scalar_type_id| is invalid");
|
||||
|
||||
if (const auto* int_type = type->AsInteger()) {
|
||||
return MaybeGetIntegerConstant(ir_context, words, int_type->width(),
|
||||
int_type->IsSigned());
|
||||
} else if (const auto* float_type = type->AsFloat()) {
|
||||
return MaybeGetFloatConstant(ir_context, words, float_type->width());
|
||||
} else {
|
||||
assert(type->AsBool() && words.size() == 1 &&
|
||||
"|scalar_type_id| doesn't represent a scalar type");
|
||||
return MaybeGetBoolConstant(ir_context, words[0]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MaybeGetCompositeConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& component_ids,
|
||||
uint32_t composite_type_id) {
|
||||
std::vector<const opt::analysis::Constant*> constants;
|
||||
for (auto id : component_ids) {
|
||||
const auto* component_constant =
|
||||
ir_context->get_constant_mgr()->FindDeclaredConstant(id);
|
||||
assert(component_constant && "|id| is invalid");
|
||||
|
||||
constants.push_back(component_constant);
|
||||
}
|
||||
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(composite_type_id);
|
||||
assert(type && "|composite_type_id| is invalid");
|
||||
|
||||
std::unique_ptr<opt::analysis::Constant> composite_constant;
|
||||
switch (type->kind()) {
|
||||
case opt::analysis::Type::kStruct:
|
||||
composite_constant = MakeUnique<opt::analysis::StructConstant>(
|
||||
type->AsStruct(), std::move(constants));
|
||||
break;
|
||||
case opt::analysis::Type::kVector:
|
||||
composite_constant = MakeUnique<opt::analysis::VectorConstant>(
|
||||
type->AsVector(), std::move(constants));
|
||||
break;
|
||||
case opt::analysis::Type::kMatrix:
|
||||
composite_constant = MakeUnique<opt::analysis::MatrixConstant>(
|
||||
type->AsMatrix(), std::move(constants));
|
||||
break;
|
||||
case opt::analysis::Type::kArray:
|
||||
composite_constant = MakeUnique<opt::analysis::ArrayConstant>(
|
||||
type->AsArray(), std::move(constants));
|
||||
break;
|
||||
default:
|
||||
assert(false &&
|
||||
"|composite_type_id| is not a result id of a composite type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ir_context->get_constant_mgr()->FindDeclaredConstant(
|
||||
composite_constant.get(), composite_type_id);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetIntegerConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t width, bool is_signed) {
|
||||
auto type_id = MaybeGetIntegerType(ir_context, width, is_signed);
|
||||
if (!type_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(type_id);
|
||||
assert(type && "|type_id| is invalid");
|
||||
|
||||
opt::analysis::IntConstant constant(type->AsInteger(), words);
|
||||
return ir_context->get_constant_mgr()->FindDeclaredConstant(&constant,
|
||||
type_id);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetFloatConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t width) {
|
||||
auto type_id = MaybeGetFloatType(ir_context, width);
|
||||
if (!type_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto* type = ir_context->get_type_mgr()->GetType(type_id);
|
||||
assert(type && "|type_id| is invalid");
|
||||
|
||||
opt::analysis::FloatConstant constant(type->AsFloat(), words);
|
||||
return ir_context->get_constant_mgr()->FindDeclaredConstant(&constant,
|
||||
type_id);
|
||||
}
|
||||
|
||||
uint32_t MaybeGetBoolConstant(opt::IRContext* context, bool value) {
|
||||
opt::analysis::Bool bool_type;
|
||||
auto registered_bool_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&bool_type);
|
||||
if (!registered_bool_type) {
|
||||
return 0;
|
||||
}
|
||||
opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
|
||||
value);
|
||||
return context->get_constant_mgr()->FindDeclaredConstant(
|
||||
&bool_constant, context->get_type_mgr()->GetId(&bool_type));
|
||||
}
|
||||
|
||||
void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
|
||||
uint32_t width, bool is_signed) {
|
||||
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
|
||||
50
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
vendored
50
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
vendored
@@ -53,10 +53,6 @@ bool PhiIdsOkForNewEdge(
|
||||
opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
|
||||
const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids);
|
||||
|
||||
// Returns the id of a boolean constant with value |value| if it exists in the
|
||||
// module, or 0 otherwise.
|
||||
uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value);
|
||||
|
||||
// Requires that a boolean constant with value |condition_value| is available,
|
||||
// that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds, and that
|
||||
// bb_from ends with "OpBranch %some_block". Turns OpBranch into
|
||||
@@ -229,7 +225,8 @@ void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id);
|
||||
// Adds a global variable with storage class |storage_class| to the module, with
|
||||
// type |type_id| and either no initializer or |initializer_id| as an
|
||||
// initializer, depending on whether |initializer_id| is 0. The global variable
|
||||
// has result id |result_id|.
|
||||
// has result id |result_id|. Updates module's id bound to accommodate for
|
||||
// |result_id|.
|
||||
//
|
||||
// - |type_id| must be the id of a pointer type with the same storage class as
|
||||
// |storage_class|.
|
||||
@@ -243,6 +240,7 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
|
||||
// Adds an instruction to the start of |function_id|, of the form:
|
||||
// |result_id| = OpVariable |type_id| Function |initializer_id|.
|
||||
// Updates module's id bound to accommodate for |result_id|.
|
||||
//
|
||||
// - |type_id| must be the id of a pointer type with Function storage class.
|
||||
// - |initializer_id| must be the id of a constant with the same type as the
|
||||
@@ -306,6 +304,48 @@ uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
|
||||
uint32_t MaybeGetStructType(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& component_type_ids);
|
||||
|
||||
// Recursive definition is the following:
|
||||
// - if |scalar_or_composite_type_id| is a result id of a scalar type - returns
|
||||
// a result id of the following constants (depending on the type): int -> 0,
|
||||
// float -> 0.0, bool -> false.
|
||||
// - otherwise, returns a result id of an OpConstantComposite instruction.
|
||||
// Every component of the composite constant is looked up by calling this
|
||||
// function with the type id of that component.
|
||||
// Returns 0 if no such instruction is present in the module.
|
||||
uint32_t MaybeGetZeroConstant(opt::IRContext* ir_context,
|
||||
uint32_t scalar_or_composite_type_id);
|
||||
|
||||
// Returns the result id of an OpConstant instruction. |scalar_type_id| must be
|
||||
// a result id of a scalar type (i.e. int, float or bool). Returns 0 if no such
|
||||
// instruction is present in the module.
|
||||
uint32_t MaybeGetScalarConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t scalar_type_id);
|
||||
|
||||
// Returns the result id of an OpConstantComposite instruction.
|
||||
// |composite_type_id| must be a result id of a composite type (i.e. vector,
|
||||
// matrix, struct or array). Returns 0 if no such instruction is present in the
|
||||
// module.
|
||||
uint32_t MaybeGetCompositeConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& component_ids,
|
||||
uint32_t composite_type_id);
|
||||
|
||||
// Returns the result id of an OpConstant instruction of integral type.
|
||||
// Returns 0 if no such instruction or type is present in the module.
|
||||
uint32_t MaybeGetIntegerConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t width, bool is_signed);
|
||||
|
||||
// Returns the result id of an OpConstant instruction of floating-point type.
|
||||
// Returns 0 if no such instruction or type is present in the module.
|
||||
uint32_t MaybeGetFloatConstant(opt::IRContext* ir_context,
|
||||
const std::vector<uint32_t>& words,
|
||||
uint32_t width);
|
||||
|
||||
// Returns the id of a boolean constant with value |value| if it exists in the
|
||||
// module, or 0 otherwise.
|
||||
uint32_t MaybeGetBoolConstant(opt::IRContext* context, bool value);
|
||||
|
||||
// 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,
|
||||
|
||||
@@ -383,6 +383,9 @@ message Transformation {
|
||||
TransformationAddParameter add_parameter = 52;
|
||||
TransformationAddCopyMemory add_copy_memory = 53;
|
||||
TransformationInvertComparisonOperator invert_comparison_operator = 54;
|
||||
TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 55;
|
||||
TransformationReplaceParameterWithGlobal replace_parameter_with_global = 56;
|
||||
TransformationRecordSynonymousConstants record_synonymous_constants = 57;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@@ -616,6 +619,18 @@ message TransformationAddGlobalVariable {
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddImageSampleUnusedComponents {
|
||||
|
||||
// A transformation that adds unused components to an image sample coordinate.
|
||||
|
||||
// An vector id with the original coordinate and the unused components.
|
||||
uint32 coordinate_with_unused_components_id = 1;
|
||||
|
||||
// A descriptor for an image sample instruction.
|
||||
InstructionDescriptor instruction_descriptor = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationAddLocalVariable {
|
||||
|
||||
// Adds a local variable of the given type (which must be a pointer with
|
||||
@@ -1109,6 +1124,43 @@ message TransformationPushIdThroughVariable {
|
||||
|
||||
}
|
||||
|
||||
message TransformationRecordSynonymousConstants {
|
||||
|
||||
// A transformation that, given the IDs to two synonymous constants,
|
||||
// records the fact that they are synonymous. The module is not changed.
|
||||
// Two constants are synonymous if:
|
||||
// - they have the same type (ignoring the presence of integer sign)
|
||||
// - they have the same opcode (one of OpConstant, OpConstantTrue,
|
||||
// OpConstantFalse, OpConstantNull)
|
||||
// - they have the same value
|
||||
// If the types are the same, OpConstantNull is equivalent to
|
||||
// OpConstantFalse or OpConstant with value zero.
|
||||
|
||||
// The id of a constant
|
||||
uint32 constant1_id = 1;
|
||||
|
||||
// The id of the synonym
|
||||
uint32 constant2_id = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationReplaceParameterWithGlobal {
|
||||
|
||||
// Removes parameter with result id |parameter_id| from its function
|
||||
// and creates a global variable to pass its value to the function instead.
|
||||
|
||||
// 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 = 2;
|
||||
|
||||
// Result id of the OpFunctionParameter instruction to remove.
|
||||
uint32 parameter_id = 3;
|
||||
|
||||
// Fresh id of a global variable used to pass parameter's value to the function.
|
||||
uint32 global_variable_fresh_id = 4;
|
||||
|
||||
}
|
||||
|
||||
message TransformationReplaceBooleanConstantWithConstantBinary {
|
||||
|
||||
// A transformation to capture replacing a use of a boolean constant with
|
||||
@@ -1176,14 +1228,14 @@ message TransformationReplaceLinearAlgebraInstruction {
|
||||
// Supported:
|
||||
// OpVectorTimesScalar
|
||||
// OpMatrixTimesScalar
|
||||
// OpVectorTimesMatrix
|
||||
// OpMatrixTimesVector
|
||||
// OpDot
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
|
||||
// Right now we only support certain operations. When this issue is addressed
|
||||
// the supporting comments can be removed.
|
||||
// To be supported in the future:
|
||||
// OpTranspose
|
||||
// OpVectorTimesMatrix
|
||||
// OpMatrixTimesVector
|
||||
// OpMatrixTimesMatrix
|
||||
// OpOuterProduct
|
||||
InstructionDescriptor instruction_descriptor = 2;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "source/fuzz/transformation_add_function.h"
|
||||
#include "source/fuzz/transformation_add_global_undef.h"
|
||||
#include "source/fuzz/transformation_add_global_variable.h"
|
||||
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
|
||||
#include "source/fuzz/transformation_add_local_variable.h"
|
||||
#include "source/fuzz/transformation_add_no_contraction_decoration.h"
|
||||
#include "source/fuzz/transformation_add_parameter.h"
|
||||
@@ -57,10 +58,12 @@
|
||||
#include "source/fuzz/transformation_permute_function_parameters.h"
|
||||
#include "source/fuzz/transformation_permute_phi_operands.h"
|
||||
#include "source/fuzz/transformation_push_id_through_variable.h"
|
||||
#include "source/fuzz/transformation_record_synonymous_constants.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/fuzz/transformation_replace_id_with_synonym.h"
|
||||
#include "source/fuzz/transformation_replace_linear_algebra_instruction.h"
|
||||
#include "source/fuzz/transformation_replace_parameter_with_global.h"
|
||||
#include "source/fuzz/transformation_set_function_control.h"
|
||||
#include "source/fuzz/transformation_set_loop_control.h"
|
||||
#include "source/fuzz/transformation_set_memory_operands_mask.h"
|
||||
@@ -112,6 +115,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kAddGlobalVariable:
|
||||
return MakeUnique<TransformationAddGlobalVariable>(
|
||||
message.add_global_variable());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kAddImageSampleUnusedComponents:
|
||||
return MakeUnique<TransformationAddImageSampleUnusedComponents>(
|
||||
message.add_image_sample_unused_components());
|
||||
case protobufs::Transformation::TransformationCase::kAddLocalVariable:
|
||||
return MakeUnique<TransformationAddLocalVariable>(
|
||||
message.add_local_variable());
|
||||
@@ -188,6 +195,14 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kPushIdThroughVariable:
|
||||
return MakeUnique<TransformationPushIdThroughVariable>(
|
||||
message.push_id_through_variable());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kRecordSynonymousConstants:
|
||||
return MakeUnique<TransformationRecordSynonymousConstants>(
|
||||
message.record_synonymous_constants());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceParameterWithGlobal:
|
||||
return MakeUnique<TransformationReplaceParameterWithGlobal>(
|
||||
message.replace_parameter_with_global());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceBooleanConstantWithConstantBinary:
|
||||
return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(
|
||||
|
||||
@@ -40,8 +40,8 @@ bool TransformationAddDeadBlock::IsApplicable(
|
||||
|
||||
// First, we check that a constant with the same value as
|
||||
// |message_.condition_value| is present.
|
||||
if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
|
||||
message_.condition_value())) {
|
||||
if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
|
||||
message_.condition_value())) {
|
||||
// The required constant is not present, so the transformation cannot be
|
||||
// applied.
|
||||
return false;
|
||||
@@ -92,8 +92,8 @@ void TransformationAddDeadBlock::Apply(
|
||||
existing_block->terminator()->GetSingleWordInOperand(0);
|
||||
|
||||
// Get the id of the boolean value that will be used as the branch condition.
|
||||
auto bool_id = fuzzerutil::MaybeGetBoolConstantId(ir_context,
|
||||
message_.condition_value());
|
||||
auto bool_id =
|
||||
fuzzerutil::MaybeGetBoolConstant(ir_context, message_.condition_value());
|
||||
|
||||
// Make a new block that unconditionally branches to the original successor
|
||||
// block.
|
||||
|
||||
@@ -112,8 +112,8 @@ bool TransformationAddDeadBreak::IsApplicable(
|
||||
const TransformationContext& transformation_context) const {
|
||||
// First, we check that a constant with the same value as
|
||||
// |message_.break_condition_value| is present.
|
||||
if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
|
||||
message_.break_condition_value())) {
|
||||
if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
|
||||
message_.break_condition_value())) {
|
||||
// The required constant is not present, so the transformation cannot be
|
||||
// applied.
|
||||
return false;
|
||||
|
||||
@@ -38,8 +38,8 @@ bool TransformationAddDeadContinue::IsApplicable(
|
||||
const TransformationContext& transformation_context) const {
|
||||
// First, we check that a constant with the same value as
|
||||
// |message_.continue_condition_value| is present.
|
||||
if (!fuzzerutil::MaybeGetBoolConstantId(
|
||||
ir_context, message_.continue_condition_value())) {
|
||||
if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
|
||||
message_.continue_condition_value())) {
|
||||
// The required constant is not present, so the transformation cannot be
|
||||
// applied.
|
||||
return false;
|
||||
|
||||
@@ -98,8 +98,6 @@ void TransformationAddGlobalVariable::Apply(
|
||||
static_cast<SpvStorageClass>(message_.storage_class()),
|
||||
message_.initializer_id());
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
|
||||
if (message_.value_is_irrelevant()) {
|
||||
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
|
||||
message_.fresh_id());
|
||||
|
||||
117
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp
vendored
Normal file
117
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2020 André Perez Maselco
|
||||
//
|
||||
// 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_image_sample_unused_components.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationAddImageSampleUnusedComponents::
|
||||
TransformationAddImageSampleUnusedComponents(
|
||||
const spvtools::fuzz::protobufs::
|
||||
TransformationAddImageSampleUnusedComponents& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationAddImageSampleUnusedComponents::
|
||||
TransformationAddImageSampleUnusedComponents(
|
||||
uint32_t coordinate_with_unused_components_id,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
message_.set_coordinate_with_unused_components_id(
|
||||
coordinate_with_unused_components_id);
|
||||
*message_.mutable_instruction_descriptor() = instruction_descriptor;
|
||||
}
|
||||
|
||||
bool TransformationAddImageSampleUnusedComponents::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
auto image_sample_instruction =
|
||||
FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||
|
||||
// The image sample instruction must be defined.
|
||||
if (image_sample_instruction == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The instruction must be an image sample instruction.
|
||||
if (!spvOpcodeIsImageSample(image_sample_instruction->opcode())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t coordinate_id = image_sample_instruction->GetSingleWordInOperand(1);
|
||||
auto coordinate_instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(coordinate_id);
|
||||
auto coordinate_type =
|
||||
ir_context->get_type_mgr()->GetType(coordinate_instruction->type_id());
|
||||
|
||||
// It must be possible to add unused components.
|
||||
if (coordinate_type->AsVector() &&
|
||||
coordinate_type->AsVector()->element_count() == 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto coordinate_with_unused_components_instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(
|
||||
message_.coordinate_with_unused_components_id());
|
||||
|
||||
// The coordinate with unused components instruction must be defined.
|
||||
if (coordinate_with_unused_components_instruction == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It must be an OpCompositeConstruct instruction such that it can be checked
|
||||
// that the original components are present.
|
||||
if (coordinate_with_unused_components_instruction->opcode() !=
|
||||
SpvOpCompositeConstruct) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The first constituent must be the original coordinate.
|
||||
if (coordinate_with_unused_components_instruction->GetSingleWordInOperand(
|
||||
0) != coordinate_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto coordinate_with_unused_components_type =
|
||||
ir_context->get_type_mgr()->GetType(
|
||||
coordinate_with_unused_components_instruction->type_id());
|
||||
|
||||
// |coordinate_with_unused_components_type| must be a vector.
|
||||
if (!coordinate_with_unused_components_type->AsVector()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransformationAddImageSampleUnusedComponents::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
// Sets the coordinate operand.
|
||||
auto image_sample_instruction =
|
||||
FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||
image_sample_instruction->SetInOperand(
|
||||
1, {message_.coordinate_with_unused_components_id()});
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation
|
||||
TransformationAddImageSampleUnusedComponents::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_image_sample_unused_components() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
57
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h
vendored
Normal file
57
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2020 André Perez Maselco
|
||||
//
|
||||
// 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_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_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 TransformationAddImageSampleUnusedComponents : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddImageSampleUnusedComponents(
|
||||
const protobufs::TransformationAddImageSampleUnusedComponents& message);
|
||||
|
||||
TransformationAddImageSampleUnusedComponents(
|
||||
uint32_t coordinate_with_unused_components_id,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor);
|
||||
|
||||
// - |coordinate_with_unused_components_id| must identify a vector such that
|
||||
// the first components match the components of the image sample coordinate.
|
||||
// - |message_.instruction_descriptor| must identify an image sample
|
||||
// instruction
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// Add unused components to an image sample coordinate by replacing the
|
||||
// coordinate with |coordinate_with_unused_components_id|.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddImageSampleUnusedComponents message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
|
||||
@@ -74,8 +74,6 @@ void TransformationAddLocalVariable::Apply(
|
||||
message_.type_id(), message_.function_id(),
|
||||
message_.initializer_id());
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
|
||||
if (message_.value_is_irrelevant()) {
|
||||
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
|
||||
message_.fresh_id());
|
||||
|
||||
@@ -127,8 +127,6 @@ void TransformationPushIdThroughVariable::Apply(
|
||||
message_.initializer_id());
|
||||
}
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.variable_id());
|
||||
|
||||
// Stores value id to variable id.
|
||||
FindInstruction(message_.instruction_descriptor(), ir_context)
|
||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
|
||||
107
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp
vendored
Normal file
107
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2020 Stefano Milizia
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "transformation_record_synonymous_constants.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
namespace {
|
||||
bool IsScalarZeroConstant(const opt::analysis::Constant* constant) {
|
||||
return constant->AsScalarConstant() && constant->IsZero();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TransformationRecordSynonymousConstants::
|
||||
TransformationRecordSynonymousConstants(
|
||||
const protobufs::TransformationRecordSynonymousConstants& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationRecordSynonymousConstants::
|
||||
TransformationRecordSynonymousConstants(uint32_t constant1_id,
|
||||
uint32_t constant2_id) {
|
||||
message_.set_constant1_id(constant1_id);
|
||||
message_.set_constant2_id(constant2_id);
|
||||
}
|
||||
|
||||
bool TransformationRecordSynonymousConstants::IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& /* unused */) const {
|
||||
// The ids must be different
|
||||
if (message_.constant1_id() == message_.constant2_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto constant1 = ir_context->get_constant_mgr()->FindDeclaredConstant(
|
||||
message_.constant1_id());
|
||||
auto constant2 = ir_context->get_constant_mgr()->FindDeclaredConstant(
|
||||
message_.constant2_id());
|
||||
|
||||
// The constants must exist
|
||||
if (constant1 == nullptr || constant2 == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the constants are equal, then they are equivalent
|
||||
if (constant1 == constant2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the constants are two integers (signed or unsigned), they are equal
|
||||
// if they have the same width and the same data words.
|
||||
if (constant1->AsIntConstant() && constant2->AsIntConstant() &&
|
||||
constant1->type()->AsInteger()->width() ==
|
||||
constant2->type()->AsInteger()->width() &&
|
||||
constant1->AsIntConstant()->words() ==
|
||||
constant2->AsIntConstant()->words()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The types must be the same
|
||||
if (!constant1->type()->IsSame(constant2->type())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The constants are equivalent if one is null and the other is a static
|
||||
// constant with value 0.
|
||||
return (constant1->AsNullConstant() && IsScalarZeroConstant(constant2)) ||
|
||||
(IsScalarZeroConstant(constant1) && constant2->AsNullConstant());
|
||||
}
|
||||
|
||||
void TransformationRecordSynonymousConstants::Apply(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const {
|
||||
protobufs::FactDataSynonym fact_data_synonym;
|
||||
// Define the two equivalent data descriptors (just containing the ids)
|
||||
*fact_data_synonym.mutable_data1() =
|
||||
MakeDataDescriptor(message_.constant1_id(), {});
|
||||
*fact_data_synonym.mutable_data2() =
|
||||
MakeDataDescriptor(message_.constant2_id(), {});
|
||||
protobufs::Fact fact;
|
||||
*fact.mutable_data_synonym_fact() = fact_data_synonym;
|
||||
|
||||
// Add the fact to the fact manager
|
||||
transformation_context->GetFactManager()->AddFact(fact, ir_context);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage()
|
||||
const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_record_synonymous_constants() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
59
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h
vendored
Normal file
59
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2020 Stefano Milizia
|
||||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H
|
||||
|
||||
#include "source/fuzz/transformation.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationRecordSynonymousConstants : public Transformation {
|
||||
public:
|
||||
explicit TransformationRecordSynonymousConstants(
|
||||
const protobufs::TransformationRecordSynonymousConstants& message);
|
||||
|
||||
TransformationRecordSynonymousConstants(uint32_t constant1_id,
|
||||
uint32_t constant2_id);
|
||||
|
||||
// - |message_.constant_id| and |message_.synonym_id| are distinct ids
|
||||
// of constants
|
||||
// - |message_.constant_id| and |message_.synonym_id| refer to constants
|
||||
// that are equal or equivalent.
|
||||
// Two integers with the same width and value are equal, even if one is
|
||||
// signed and the other is not.
|
||||
// Constants are equivalent if both of them represent zero-like scalar
|
||||
// values of the same type (for example OpConstant of type int and value
|
||||
// 0 and OpConstantNull of type int).
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// Adds the fact that |message_.constant_id| and |message_.synonym_id|
|
||||
// are synonyms to the fact manager. The module is not changed.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationRecordSynonymousConstants message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS
|
||||
@@ -47,6 +47,8 @@ bool TransformationReplaceLinearAlgebraInstruction::IsApplicable(
|
||||
// It must be a supported linear algebra instruction.
|
||||
if (instruction->opcode() != SpvOpVectorTimesScalar &&
|
||||
instruction->opcode() != SpvOpMatrixTimesScalar &&
|
||||
instruction->opcode() != SpvOpVectorTimesMatrix &&
|
||||
instruction->opcode() != SpvOpMatrixTimesVector &&
|
||||
instruction->opcode() != SpvOpDot) {
|
||||
return false;
|
||||
}
|
||||
@@ -59,9 +61,8 @@ bool TransformationReplaceLinearAlgebraInstruction::IsApplicable(
|
||||
}
|
||||
|
||||
// All ids in |message_.fresh_ids| must be fresh.
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(message_.fresh_ids().size());
|
||||
i++) {
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_ids(i))) {
|
||||
for (uint32_t fresh_id : message_.fresh_ids()) {
|
||||
if (!fuzzerutil::IsFreshId(ir_context, fresh_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +82,12 @@ void TransformationReplaceLinearAlgebraInstruction::Apply(
|
||||
case SpvOpMatrixTimesScalar:
|
||||
ReplaceOpMatrixTimesScalar(ir_context, linear_algebra_instruction);
|
||||
break;
|
||||
case SpvOpVectorTimesMatrix:
|
||||
ReplaceOpVectorTimesMatrix(ir_context, linear_algebra_instruction);
|
||||
break;
|
||||
case SpvOpMatrixTimesVector:
|
||||
ReplaceOpMatrixTimesVector(ir_context, linear_algebra_instruction);
|
||||
break;
|
||||
case SpvOpDot:
|
||||
ReplaceOpDot(ir_context, linear_algebra_instruction);
|
||||
break;
|
||||
@@ -128,6 +135,49 @@ uint32_t TransformationReplaceLinearAlgebraInstruction::GetRequiredFreshIdCount(
|
||||
->AsVector()
|
||||
->element_count());
|
||||
}
|
||||
case SpvOpVectorTimesMatrix: {
|
||||
// For each vector component, 1 OpCompositeExtract instruction will be
|
||||
// inserted. For each matrix column, |1 + vector_component_count|
|
||||
// OpCompositeExtract, |vector_component_count| OpFMul and
|
||||
// |vector_component_count - 1| OpFAdd instructions will be inserted.
|
||||
auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
instruction->GetSingleWordInOperand(0));
|
||||
auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
instruction->GetSingleWordInOperand(1));
|
||||
uint32_t vector_component_count =
|
||||
ir_context->get_type_mgr()
|
||||
->GetType(vector_instruction->type_id())
|
||||
->AsVector()
|
||||
->element_count();
|
||||
uint32_t matrix_column_count =
|
||||
ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_count();
|
||||
return vector_component_count * (3 * matrix_column_count + 1);
|
||||
}
|
||||
case SpvOpMatrixTimesVector: {
|
||||
// For each matrix column, |1 + matrix_row_count| OpCompositeExtract
|
||||
// will be inserted. For each matrix row, |matrix_column_count| OpFMul and
|
||||
// |matrix_column_count - 1| OpFAdd instructions will be inserted. For
|
||||
// each vector component, 1 OpCompositeExtract instruction will be
|
||||
// inserted.
|
||||
auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
instruction->GetSingleWordInOperand(0));
|
||||
uint32_t matrix_column_count =
|
||||
ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_count();
|
||||
uint32_t matrix_row_count = ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_type()
|
||||
->AsVector()
|
||||
->element_count();
|
||||
return 3 * matrix_column_count * matrix_row_count +
|
||||
2 * matrix_column_count - matrix_row_count;
|
||||
}
|
||||
case SpvOpDot:
|
||||
// For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul
|
||||
// will be inserted. The first two OpFMul instructions will result the
|
||||
@@ -280,6 +330,236 @@ void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesScalar(
|
||||
}
|
||||
}
|
||||
|
||||
void TransformationReplaceLinearAlgebraInstruction::ReplaceOpVectorTimesMatrix(
|
||||
opt::IRContext* ir_context,
|
||||
opt::Instruction* linear_algebra_instruction) const {
|
||||
// Gets vector information.
|
||||
auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
linear_algebra_instruction->GetSingleWordInOperand(0));
|
||||
uint32_t vector_component_count = ir_context->get_type_mgr()
|
||||
->GetType(vector_instruction->type_id())
|
||||
->AsVector()
|
||||
->element_count();
|
||||
auto vector_component_type = ir_context->get_type_mgr()
|
||||
->GetType(vector_instruction->type_id())
|
||||
->AsVector()
|
||||
->element_type();
|
||||
|
||||
// Extracts vector components.
|
||||
uint32_t fresh_id_index = 0;
|
||||
std::vector<uint32_t> vector_component_ids(vector_component_count);
|
||||
for (uint32_t i = 0; i < vector_component_count; i++) {
|
||||
vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
vector_component_ids[i],
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
|
||||
}
|
||||
|
||||
// Gets matrix information.
|
||||
auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
linear_algebra_instruction->GetSingleWordInOperand(1));
|
||||
uint32_t matrix_column_count = ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_count();
|
||||
auto matrix_column_type = ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_type();
|
||||
|
||||
std::vector<uint32_t> result_component_ids(matrix_column_count);
|
||||
for (uint32_t i = 0; i < matrix_column_count; i++) {
|
||||
// Extracts matrix column.
|
||||
uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(matrix_column_type),
|
||||
matrix_extract_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
|
||||
|
||||
std::vector<uint32_t> float_multiplication_ids(vector_component_count);
|
||||
for (uint32_t j = 0; j < vector_component_count; j++) {
|
||||
// Extracts column component.
|
||||
uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
column_extract_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {matrix_extract_id}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}})));
|
||||
|
||||
// Multiplies corresponding vector and column components.
|
||||
float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFMul,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
float_multiplication_ids[j],
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}},
|
||||
{SPV_OPERAND_TYPE_ID, {column_extract_id}}})));
|
||||
}
|
||||
|
||||
// Adds the multiplication results.
|
||||
std::vector<uint32_t> float_add_ids;
|
||||
uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
|
||||
float_add_ids.push_back(float_add_id);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFAdd,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
|
||||
{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}})));
|
||||
for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) {
|
||||
float_add_id = message_.fresh_ids(fresh_id_index++);
|
||||
float_add_ids.push_back(float_add_id);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFAdd,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
float_add_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}},
|
||||
{SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}})));
|
||||
}
|
||||
|
||||
result_component_ids[i] = float_add_ids.back();
|
||||
}
|
||||
|
||||
// The OpVectorTimesMatrix instruction is changed to an OpCompositeConstruct
|
||||
// instruction.
|
||||
linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
|
||||
linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
|
||||
linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
|
||||
for (uint32_t i = 2; i < result_component_ids.size(); i++) {
|
||||
linear_algebra_instruction->AddOperand(
|
||||
{SPV_OPERAND_TYPE_ID, {result_component_ids[i]}});
|
||||
}
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(
|
||||
ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1));
|
||||
}
|
||||
|
||||
void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesVector(
|
||||
opt::IRContext* ir_context,
|
||||
opt::Instruction* linear_algebra_instruction) const {
|
||||
// Gets matrix information.
|
||||
auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
linear_algebra_instruction->GetSingleWordInOperand(0));
|
||||
uint32_t matrix_column_count = ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_count();
|
||||
auto matrix_column_type = ir_context->get_type_mgr()
|
||||
->GetType(matrix_instruction->type_id())
|
||||
->AsMatrix()
|
||||
->element_type();
|
||||
uint32_t matrix_row_count = matrix_column_type->AsVector()->element_count();
|
||||
|
||||
// Extracts matrix columns.
|
||||
uint32_t fresh_id_index = 0;
|
||||
std::vector<uint32_t> matrix_column_ids(matrix_column_count);
|
||||
for (uint32_t i = 0; i < matrix_column_count; i++) {
|
||||
matrix_column_ids[i] = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(matrix_column_type),
|
||||
matrix_column_ids[i],
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
|
||||
}
|
||||
|
||||
// Gets vector information.
|
||||
auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
|
||||
linear_algebra_instruction->GetSingleWordInOperand(1));
|
||||
auto vector_component_type = ir_context->get_type_mgr()
|
||||
->GetType(vector_instruction->type_id())
|
||||
->AsVector()
|
||||
->element_type();
|
||||
|
||||
// Extracts vector components.
|
||||
std::vector<uint32_t> vector_component_ids(matrix_column_count);
|
||||
for (uint32_t i = 0; i < matrix_column_count; i++) {
|
||||
vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
vector_component_ids[i],
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
|
||||
}
|
||||
|
||||
std::vector<uint32_t> result_component_ids(matrix_row_count);
|
||||
for (uint32_t i = 0; i < matrix_row_count; i++) {
|
||||
std::vector<uint32_t> float_multiplication_ids(matrix_column_count);
|
||||
for (uint32_t j = 0; j < matrix_column_count; j++) {
|
||||
// Extracts column component.
|
||||
uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
column_extract_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {matrix_column_ids[j]}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
|
||||
|
||||
// Multiplies corresponding vector and column components.
|
||||
float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFMul,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
float_multiplication_ids[j],
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {column_extract_id}},
|
||||
{SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}}})));
|
||||
}
|
||||
|
||||
// Adds the multiplication results.
|
||||
std::vector<uint32_t> float_add_ids;
|
||||
uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
|
||||
float_add_ids.push_back(float_add_id);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFAdd,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
|
||||
{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}})));
|
||||
for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) {
|
||||
float_add_id = message_.fresh_ids(fresh_id_index++);
|
||||
float_add_ids.push_back(float_add_id);
|
||||
linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFAdd,
|
||||
ir_context->get_type_mgr()->GetId(vector_component_type),
|
||||
float_add_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}},
|
||||
{SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}})));
|
||||
}
|
||||
|
||||
result_component_ids[i] = float_add_ids.back();
|
||||
}
|
||||
|
||||
// The OpMatrixTimesVector instruction is changed to an OpCompositeConstruct
|
||||
// instruction.
|
||||
linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
|
||||
linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
|
||||
linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
|
||||
for (uint32_t i = 2; i < result_component_ids.size(); i++) {
|
||||
linear_algebra_instruction->AddOperand(
|
||||
{SPV_OPERAND_TYPE_ID, {result_component_ids[i]}});
|
||||
}
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(
|
||||
ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1));
|
||||
}
|
||||
|
||||
void TransformationReplaceLinearAlgebraInstruction::ReplaceOpDot(
|
||||
opt::IRContext* ir_context,
|
||||
opt::Instruction* linear_algebra_instruction) const {
|
||||
|
||||
@@ -60,6 +60,14 @@ class TransformationReplaceLinearAlgebraInstruction : public Transformation {
|
||||
void ReplaceOpMatrixTimesScalar(opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) const;
|
||||
|
||||
// Replaces an OpVectorTimesMatrix instruction.
|
||||
void ReplaceOpVectorTimesMatrix(opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) const;
|
||||
|
||||
// Replaces an OpMatrixTimesVector instruction.
|
||||
void ReplaceOpMatrixTimesVector(opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) const;
|
||||
|
||||
// Replaces an OpDot instruction.
|
||||
void ReplaceOpDot(opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) const;
|
||||
|
||||
245
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp
vendored
Normal file
245
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
// 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_replace_parameter_with_global.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
opt::Function* GetFunctionFromParameterId(opt::IRContext* ir_context,
|
||||
uint32_t param_id) {
|
||||
auto* param_inst = ir_context->get_def_use_mgr()->GetDef(param_id);
|
||||
assert(param_inst && "Parameter id is invalid");
|
||||
|
||||
for (auto& function : *ir_context->module()) {
|
||||
if (fuzzerutil::InstructionIsFunctionParameter(param_inst, &function)) {
|
||||
return &function;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TransformationReplaceParameterWithGlobal::
|
||||
TransformationReplaceParameterWithGlobal(
|
||||
const protobufs::TransformationReplaceParameterWithGlobal& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationReplaceParameterWithGlobal::
|
||||
TransformationReplaceParameterWithGlobal(
|
||||
uint32_t function_type_fresh_id, uint32_t parameter_id,
|
||||
uint32_t global_variable_fresh_id) {
|
||||
message_.set_function_type_fresh_id(function_type_fresh_id);
|
||||
message_.set_parameter_id(parameter_id);
|
||||
message_.set_global_variable_fresh_id(global_variable_fresh_id);
|
||||
}
|
||||
|
||||
bool TransformationReplaceParameterWithGlobal::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// Check that |parameter_id| is valid.
|
||||
const auto* param_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.parameter_id());
|
||||
if (!param_inst || param_inst->opcode() != SpvOpFunctionParameter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that function exists and is not an entry point.
|
||||
const auto* function =
|
||||
GetFunctionFromParameterId(ir_context, message_.parameter_id());
|
||||
if (!function ||
|
||||
fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We already know that the function has at least one parameter -
|
||||
// |parameter_id|.
|
||||
|
||||
// Check that replaced parameter has valid type.
|
||||
const auto* param_type =
|
||||
ir_context->get_type_mgr()->GetType(param_inst->type_id());
|
||||
assert(param_type && "Parameter has invalid type");
|
||||
if (!CanReplaceFunctionParameterType(*param_type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that initializer for the global variable exists in the module.
|
||||
if (fuzzerutil::MaybeGetZeroConstant(ir_context, param_inst->type_id()) ==
|
||||
0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that pointer type for the global variable exists in the module.
|
||||
if (!fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
|
||||
SpvStorageClassPrivate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()) &&
|
||||
fuzzerutil::IsFreshId(ir_context,
|
||||
message_.global_variable_fresh_id()) &&
|
||||
message_.function_type_fresh_id() !=
|
||||
message_.global_variable_fresh_id();
|
||||
}
|
||||
|
||||
void TransformationReplaceParameterWithGlobal::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
const auto* param_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.parameter_id());
|
||||
assert(param_inst && "Parameter must exist");
|
||||
|
||||
// Create global variable to store parameter's value.
|
||||
//
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
|
||||
// Mark the global variable's pointee as irrelevant if replaced parameter is
|
||||
// irrelevant.
|
||||
fuzzerutil::AddGlobalVariable(
|
||||
ir_context, message_.global_variable_fresh_id(),
|
||||
fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
|
||||
SpvStorageClassPrivate),
|
||||
SpvStorageClassPrivate,
|
||||
fuzzerutil::MaybeGetZeroConstant(ir_context, param_inst->type_id()));
|
||||
|
||||
auto* function =
|
||||
GetFunctionFromParameterId(ir_context, message_.parameter_id());
|
||||
assert(function && "Function must exist");
|
||||
|
||||
// Insert an OpLoad instruction right after OpVariable instructions.
|
||||
auto it = function->begin()->begin();
|
||||
while (it != function->begin()->end() &&
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it)) {
|
||||
++it;
|
||||
}
|
||||
|
||||
assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it) &&
|
||||
"Can't insert OpLoad or OpCopyMemory into the first basic block of "
|
||||
"the function");
|
||||
|
||||
it.InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpLoad, param_inst->type_id(), param_inst->result_id(),
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}}}));
|
||||
|
||||
// Calculate the index of the replaced parameter (we need to know this to
|
||||
// remove operands from the OpFunctionCall).
|
||||
auto params = fuzzerutil::GetParameters(ir_context, function->result_id());
|
||||
auto parameter_index = static_cast<uint32_t>(params.size());
|
||||
for (uint32_t i = 0, n = static_cast<uint32_t>(params.size()); i < n; ++i) {
|
||||
if (params[i]->result_id() == message_.parameter_id()) {
|
||||
parameter_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(parameter_index != params.size() &&
|
||||
"Parameter must exist in the function");
|
||||
|
||||
// Update all relevant OpFunctionCall instructions.
|
||||
ir_context->get_def_use_mgr()->ForEachUser(
|
||||
function->result_id(),
|
||||
[ir_context, parameter_index, this](opt::Instruction* inst) {
|
||||
if (inst->opcode() != SpvOpFunctionCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, inst) &&
|
||||
"Can't insert OpStore right before the function call");
|
||||
|
||||
// Insert an OpStore before the OpFunctionCall. +1 since the first
|
||||
// operand of OpFunctionCall is an id of the function.
|
||||
inst->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpStore, 0, 0,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}},
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{inst->GetSingleWordInOperand(parameter_index + 1)}}}));
|
||||
|
||||
// +1 since the first operand of OpFunctionCall is an id of the
|
||||
// function.
|
||||
inst->RemoveInOperand(parameter_index + 1);
|
||||
});
|
||||
|
||||
// Remove the parameter from the function.
|
||||
function->RemoveParameter(message_.parameter_id());
|
||||
|
||||
// Update function's type.
|
||||
auto* old_function_type = fuzzerutil::GetFunctionType(ir_context, function);
|
||||
assert(old_function_type && "Function has invalid type");
|
||||
|
||||
// Preemptively add function's return type id.
|
||||
std::vector<uint32_t> type_ids = {
|
||||
old_function_type->GetSingleWordInOperand(0)};
|
||||
|
||||
// +1 and -1 since the first operand is the return type id.
|
||||
for (uint32_t i = 1; i < old_function_type->NumInOperands(); ++i) {
|
||||
if (i - 1 != parameter_index) {
|
||||
type_ids.push_back(old_function_type->GetSingleWordInOperand(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (ir_context->get_def_use_mgr()->NumUsers(old_function_type) == 1) {
|
||||
// Change the old type in place. +1 since the first operand is the result
|
||||
// type id of the function.
|
||||
old_function_type->RemoveInOperand(parameter_index + 1);
|
||||
} else {
|
||||
// Find an existing or create a new function type.
|
||||
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 TransformationReplaceParameterWithGlobal::ToMessage()
|
||||
const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_replace_parameter_with_global() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TransformationReplaceParameterWithGlobal::CanReplaceFunctionParameterType(
|
||||
const opt::analysis::Type& type) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403):
|
||||
// Think about other type instructions we can add here.
|
||||
switch (type.kind()) {
|
||||
case opt::analysis::Type::kBool:
|
||||
case opt::analysis::Type::kInteger:
|
||||
case opt::analysis::Type::kFloat:
|
||||
case opt::analysis::Type::kArray:
|
||||
case opt::analysis::Type::kMatrix:
|
||||
case opt::analysis::Type::kVector:
|
||||
return true;
|
||||
case opt::analysis::Type::kStruct:
|
||||
return std::all_of(
|
||||
type.AsStruct()->element_types().begin(),
|
||||
type.AsStruct()->element_types().end(),
|
||||
[](const opt::analysis::Type* element_type) {
|
||||
return CanReplaceFunctionParameterType(*element_type);
|
||||
});
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
67
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h
vendored
Normal file
67
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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_REPLACE_PARAMETER_WITH_GLOBAL_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_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 TransformationReplaceParameterWithGlobal : public Transformation {
|
||||
public:
|
||||
explicit TransformationReplaceParameterWithGlobal(
|
||||
const protobufs::TransformationReplaceParameterWithGlobal& message);
|
||||
|
||||
TransformationReplaceParameterWithGlobal(uint32_t function_type_fresh_id,
|
||||
uint32_t parameter_id,
|
||||
uint32_t global_variable_fresh_id);
|
||||
|
||||
// - |function_type_fresh_id| is a fresh id.
|
||||
// - |parameter_id| is the result id of the parameter to replace.
|
||||
// - |global_variable_fresh_id| is a fresh id.
|
||||
// - |function_type_fresh_id| is not equal to |global_variable_fresh_id|.
|
||||
// - the function that contains |parameter_id| may not be an entry-point
|
||||
// function.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// - Removes parameter with result id |parameter_id| from its function
|
||||
// - Adds a global variable to store the value for the parameter
|
||||
// - Add an OpStore instruction before each function call to
|
||||
// store parameter's value into the variable
|
||||
// - Adds OpLoad at the beginning of the function to load the
|
||||
// value from the variable into the old parameter's id
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
// Returns true if the type of the parameter is supported by this
|
||||
// transformation.
|
||||
static bool CanReplaceFunctionParameterType(const opt::analysis::Type& type);
|
||||
|
||||
private:
|
||||
protobufs::TransformationReplaceParameterWithGlobal message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_
|
||||
20
3rdparty/spirv-tools/source/opcode.cpp
vendored
20
3rdparty/spirv-tools/source/opcode.cpp
vendored
@@ -666,6 +666,26 @@ bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
bool spvOpcodeIsImageSample(const SpvOp opcode) {
|
||||
switch (opcode) {
|
||||
case SpvOpImageSampleImplicitLod:
|
||||
case SpvOpImageSampleExplicitLod:
|
||||
case SpvOpImageSampleDrefImplicitLod:
|
||||
case SpvOpImageSampleDrefExplicitLod:
|
||||
case SpvOpImageSampleProjImplicitLod:
|
||||
case SpvOpImageSampleProjExplicitLod:
|
||||
case SpvOpImageSampleProjDrefImplicitLod:
|
||||
case SpvOpImageSampleProjDrefExplicitLod:
|
||||
case SpvOpImageSparseSampleImplicitLod:
|
||||
case SpvOpImageSparseSampleExplicitLod:
|
||||
case SpvOpImageSparseSampleDrefImplicitLod:
|
||||
case SpvOpImageSparseSampleDrefExplicitLod:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
|
||||
switch (opcode) {
|
||||
case SpvOpMemoryBarrier:
|
||||
|
||||
3
3rdparty/spirv-tools/source/opcode.h
vendored
3
3rdparty/spirv-tools/source/opcode.h
vendored
@@ -137,6 +137,9 @@ bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
|
||||
// Returns true for opcodes that represents linear algebra instructions.
|
||||
bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
|
||||
|
||||
// Returns true for opcodes that represents an image sample instruction.
|
||||
bool spvOpcodeIsImageSample(SpvOp opcode);
|
||||
|
||||
// Returns a vector containing the indices of the memory semantics <id>
|
||||
// operands for |opcode|.
|
||||
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);
|
||||
|
||||
@@ -29,6 +29,12 @@ const uint32_t kCompositeExtractObjectInOperand = 0;
|
||||
const uint32_t kTypePointerStorageClassInIdx = 0;
|
||||
const uint32_t kTypePointerPointeeInIdx = 1;
|
||||
|
||||
bool IsOpenCL100DebugDeclareOrValue(Instruction* di) {
|
||||
auto dbg_opcode = di->GetOpenCL100DebugOpcode();
|
||||
return dbg_opcode == OpenCLDebugInfo100DebugDeclare ||
|
||||
dbg_opcode == OpenCLDebugInfo100DebugValue;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Pass::Status CopyPropagateArrays::Process() {
|
||||
@@ -188,6 +194,8 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
|
||||
return ptr_inst->opcode() == SpvOpVariable &&
|
||||
store_inst->GetSingleWordInOperand(kStorePointerInOperand) ==
|
||||
ptr_inst->result_id();
|
||||
} else if (IsOpenCL100DebugDeclareOrValue(use)) {
|
||||
return true;
|
||||
}
|
||||
// Some other instruction. Be conservative.
|
||||
return false;
|
||||
@@ -492,6 +500,8 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
|
||||
const_mgr,
|
||||
type](Instruction* use,
|
||||
uint32_t) {
|
||||
if (IsOpenCL100DebugDeclareOrValue(use)) return true;
|
||||
|
||||
switch (use->opcode()) {
|
||||
case SpvOpLoad: {
|
||||
analysis::Pointer* pointer_type = type->AsPointer();
|
||||
@@ -565,6 +575,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
|
||||
Instruction* new_ptr_inst) {
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
@@ -580,6 +591,52 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
|
||||
for (auto pair : uses) {
|
||||
Instruction* use = pair.first;
|
||||
uint32_t index = pair.second;
|
||||
|
||||
if (use->IsOpenCL100DebugInstr()) {
|
||||
switch (use->GetOpenCL100DebugOpcode()) {
|
||||
case OpenCLDebugInfo100DebugDeclare: {
|
||||
if (new_ptr_inst->opcode() == SpvOpVariable ||
|
||||
new_ptr_inst->opcode() == SpvOpFunctionParameter) {
|
||||
context()->ForgetUses(use);
|
||||
use->SetOperand(index, {new_ptr_inst->result_id()});
|
||||
context()->AnalyzeUses(use);
|
||||
} else {
|
||||
// Based on the spec, we cannot use a pointer other than OpVariable
|
||||
// or OpFunctionParameter for DebugDeclare. We have to use
|
||||
// DebugValue with Deref.
|
||||
|
||||
context()->ForgetUses(use);
|
||||
|
||||
// Change DebugDeclare to DebugValue.
|
||||
use->SetOperand(
|
||||
index - 2,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugValue)});
|
||||
use->SetOperand(index, {new_ptr_inst->result_id()});
|
||||
|
||||
// Add Deref operation.
|
||||
Instruction* dbg_expr =
|
||||
def_use_mgr->GetDef(use->GetSingleWordOperand(index + 1));
|
||||
auto* deref_expr_instr =
|
||||
context()->get_debug_info_mgr()->DerefDebugExpression(dbg_expr);
|
||||
use->SetOperand(index + 1, {deref_expr_instr->result_id()});
|
||||
|
||||
context()->AnalyzeUses(deref_expr_instr);
|
||||
context()->AnalyzeUses(use);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpenCLDebugInfo100DebugValue:
|
||||
context()->ForgetUses(use);
|
||||
use->SetOperand(index, {new_ptr_inst->result_id()});
|
||||
context()->AnalyzeUses(use);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Don't know how to rewrite instruction");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (use->opcode()) {
|
||||
case SpvOpLoad: {
|
||||
// Replace the actual use.
|
||||
|
||||
@@ -36,6 +36,7 @@ static const uint32_t kDebugValueOperandExpressionIndex = 6;
|
||||
static const uint32_t kDebugOperationOperandOperationIndex = 4;
|
||||
static const uint32_t kOpVariableOperandStorageClassIndex = 2;
|
||||
static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
|
||||
static const uint32_t kDebugOperationOperandOpCodeIndex = 4;
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
@@ -244,6 +245,51 @@ uint32_t DebugInfoManager::BuildDebugInlinedAtChain(
|
||||
return chain_head_id;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
|
||||
if (deref_operation_ != nullptr) return deref_operation_;
|
||||
|
||||
uint32_t result_id = context()->TakeNextId();
|
||||
std::unique_ptr<Instruction> deref_operation(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
|
||||
{SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
|
||||
}));
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
deref_operation_ =
|
||||
context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
|
||||
std::move(deref_operation));
|
||||
|
||||
RegisterDbgInst(deref_operation_);
|
||||
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
|
||||
context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_operation_);
|
||||
return deref_operation_;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
|
||||
assert(dbg_expr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugExpression);
|
||||
std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
|
||||
deref_expr->SetResultId(context()->TakeNextId());
|
||||
deref_expr->InsertOperand(
|
||||
kDebugExpressOperandOperationIndex,
|
||||
{SPV_OPERAND_TYPE_ID, {GetDebugOperationWithDeref()->result_id()}});
|
||||
auto* deref_expr_instr =
|
||||
context()->ext_inst_debuginfo_end()->InsertBefore(std::move(deref_expr));
|
||||
AnalyzeDebugInst(deref_expr_instr);
|
||||
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
|
||||
context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_expr_instr);
|
||||
return deref_expr_instr;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDebugInfoNone() {
|
||||
if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
|
||||
|
||||
@@ -323,6 +369,29 @@ Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
|
||||
std::move(new_inlined_at));
|
||||
}
|
||||
|
||||
bool DebugInfoManager::IsDebugDeclared(uint32_t variable_id) {
|
||||
auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
|
||||
return dbg_decl_itr != var_id_to_dbg_decl_.end();
|
||||
}
|
||||
|
||||
void DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
Instruction* kill_inst = nullptr;
|
||||
auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
|
||||
if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
|
||||
for (auto dbg_decl : dbg_decl_itr->second) {
|
||||
kill_inst = dbg_decl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kill_inst)
|
||||
context()->KillInst(kill_inst);
|
||||
else
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
|
||||
auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
|
||||
assert(dbg_scope_itr != id_to_dbg_inst_.end());
|
||||
@@ -434,6 +503,11 @@ void DebugInfoManager::AddDebugValue(Instruction* scope_and_line,
|
||||
AnalyzeDebugInst(added_dbg_value);
|
||||
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
|
||||
context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_value);
|
||||
if (context()->AreAnalysesValid(
|
||||
IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
|
||||
auto insert_blk = context()->get_instr_block(insert_before);
|
||||
context()->set_instr_block(added_dbg_value, insert_blk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,8 +546,7 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
|
||||
}
|
||||
|
||||
void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax)
|
||||
return;
|
||||
if (!dbg_inst->IsOpenCL100DebugInstr()) return;
|
||||
|
||||
RegisterDbgInst(dbg_inst);
|
||||
|
||||
@@ -484,6 +557,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
RegisterDbgFunction(dbg_inst);
|
||||
}
|
||||
|
||||
if (deref_operation_ == nullptr &&
|
||||
dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation &&
|
||||
dbg_inst->GetSingleWordOperand(kDebugOperationOperandOpCodeIndex) ==
|
||||
OpenCLDebugInfo100Deref) {
|
||||
deref_operation_ = dbg_inst;
|
||||
}
|
||||
|
||||
if (debug_info_none_inst_ == nullptr &&
|
||||
dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
|
||||
debug_info_none_inst_ = dbg_inst;
|
||||
@@ -505,6 +585,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
}
|
||||
|
||||
void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
deref_operation_ = nullptr;
|
||||
debug_info_none_inst_ = nullptr;
|
||||
empty_debug_expr_inst_ = nullptr;
|
||||
module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
|
||||
@@ -513,8 +594,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
// list.
|
||||
if (empty_debug_expr_inst_ != nullptr &&
|
||||
empty_debug_expr_inst_->PreviousNode() != nullptr &&
|
||||
empty_debug_expr_inst_->PreviousNode()->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100InstructionsMax) {
|
||||
empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
|
||||
empty_debug_expr_inst_->InsertBefore(
|
||||
&*context()->module()->ext_inst_debuginfo_begin());
|
||||
}
|
||||
@@ -523,16 +603,14 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
// list.
|
||||
if (debug_info_none_inst_ != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode() != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode()->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100InstructionsMax) {
|
||||
debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
|
||||
debug_info_none_inst_->InsertBefore(
|
||||
&*context()->module()->ext_inst_debuginfo_begin());
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
if (instr == nullptr ||
|
||||
instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax) {
|
||||
if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -554,6 +632,22 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
}
|
||||
}
|
||||
|
||||
if (deref_operation_ == instr) {
|
||||
deref_operation_ = nullptr;
|
||||
for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
|
||||
dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
|
||||
++dbg_instr_itr) {
|
||||
if (instr != &*dbg_instr_itr &&
|
||||
dbg_instr_itr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugOperation &&
|
||||
dbg_instr_itr->GetSingleWordOperand(
|
||||
kDebugOperationOperandOpCodeIndex) == OpenCLDebugInfo100Deref) {
|
||||
deref_operation_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_info_none_inst_ == instr) {
|
||||
debug_info_none_inst_ = nullptr;
|
||||
for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
|
||||
@@ -563,6 +657,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
dbg_instr_itr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInfoNone) {
|
||||
debug_info_none_inst_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,6 +669,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
++dbg_instr_itr) {
|
||||
if (instr != &*dbg_instr_itr && IsEmptyDebugExpression(&*dbg_instr_itr)) {
|
||||
empty_debug_expr_inst_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,10 @@ class DebugInfoManager {
|
||||
uint32_t CreateDebugInlinedAt(const Instruction* line,
|
||||
const DebugScope& scope);
|
||||
|
||||
// Clones DebugExpress instruction |dbg_expr| and add Deref Operation
|
||||
// in the front of the Operation list of |dbg_expr|.
|
||||
Instruction* DerefDebugExpression(Instruction* dbg_expr);
|
||||
|
||||
// Returns a DebugInfoNone instruction.
|
||||
Instruction* GetDebugInfoNone();
|
||||
|
||||
@@ -129,6 +133,12 @@ class DebugInfoManager {
|
||||
uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at,
|
||||
DebugInlinedAtContext* inlined_at_ctx);
|
||||
|
||||
// Return true if |variable_id| has DebugDeclare or DebugVal.
|
||||
bool IsDebugDeclared(uint32_t variable_id);
|
||||
|
||||
// Kill all DebugDeclares for |variable_id|
|
||||
void KillDebugDeclares(uint32_t variable_id);
|
||||
|
||||
// Generates a DebugValue instruction with value |value_id| for every local
|
||||
// variable that is in the scope of |scope_and_line| and whose memory is
|
||||
// |variable_id| and inserts it after the instruction |insert_pos|.
|
||||
@@ -149,6 +159,9 @@ class DebugInfoManager {
|
||||
// does not exists.
|
||||
Instruction* GetDbgInst(uint32_t id);
|
||||
|
||||
// Returns a DebugOperation instruction with OpCode Deref.
|
||||
Instruction* GetDebugOperationWithDeref();
|
||||
|
||||
// Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of
|
||||
// |inst| as a key.
|
||||
void RegisterDbgInst(Instruction* inst);
|
||||
@@ -197,6 +210,9 @@ class DebugInfoManager {
|
||||
std::unordered_map<uint32_t, std::unordered_set<Instruction*>>
|
||||
var_id_to_dbg_decl_;
|
||||
|
||||
// DebugOperation whose OpCode is OpenCLDebugInfo100Deref.
|
||||
Instruction* deref_operation_;
|
||||
|
||||
// DebugInfoNone instruction. We need only a single DebugInfoNone.
|
||||
// To reuse the existing one, we keep it using this member variable.
|
||||
Instruction* debug_info_none_inst_;
|
||||
|
||||
@@ -306,6 +306,10 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
|
||||
void RemoveOperand(uint32_t index) {
|
||||
operands_.erase(operands_.begin() + index);
|
||||
}
|
||||
// Insert an operand before the |index|-th operand
|
||||
void InsertOperand(uint32_t index, Operand&& operand) {
|
||||
operands_.insert(operands_.begin() + index, operand);
|
||||
}
|
||||
|
||||
// The following methods are similar to the above, but are for in operands.
|
||||
uint32_t NumInOperands() const {
|
||||
@@ -535,6 +539,11 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
|
||||
// OpenCLDebugInfo100InstructionsMax.
|
||||
OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const;
|
||||
|
||||
// Returns true if it is an OpenCL.DebugInfo.100 instruction.
|
||||
bool IsOpenCL100DebugInstr() const {
|
||||
return GetOpenCL100DebugOpcode() != OpenCLDebugInfo100InstructionsMax;
|
||||
}
|
||||
|
||||
// Dump this instruction on stderr. Useful when running interactive
|
||||
// debuggers.
|
||||
void Dump() const;
|
||||
|
||||
@@ -31,6 +31,11 @@ const uint32_t kStoreValIdInIdx = 1;
|
||||
bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
|
||||
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
|
||||
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) {
|
||||
auto dbg_op = user->GetOpenCL100DebugOpcode();
|
||||
if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
|
||||
dbg_op == OpenCLDebugInfo100DebugValue) {
|
||||
return true;
|
||||
}
|
||||
SpvOp op = user->opcode();
|
||||
if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
|
||||
if (!HasOnlySupportedRefs(user->result_id())) {
|
||||
@@ -73,10 +78,12 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
|
||||
// variable.
|
||||
if (ptrInst->opcode() == SpvOpVariable) {
|
||||
// If a previous store to same variable, mark the store
|
||||
// for deletion if not still used.
|
||||
// for deletion if not still used. Don't delete store
|
||||
// if debugging; let ssa-rewrite and DCE handle it
|
||||
auto prev_store = var2store_.find(varId);
|
||||
if (prev_store != var2store_.end() &&
|
||||
instructions_to_save.count(prev_store->second) == 0) {
|
||||
instructions_to_save.count(prev_store->second) == 0 &&
|
||||
!context()->get_debug_info_mgr()->IsDebugDeclared(varId)) {
|
||||
instructions_to_kill.push_back(prev_store->second);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,27 @@ bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return RewriteLoads(store_inst, users);
|
||||
bool all_rewritten;
|
||||
bool modified = RewriteLoads(store_inst, users, &all_rewritten);
|
||||
|
||||
// If all uses are rewritten and the variable has a DebugDeclare and the
|
||||
// variable is not an aggregate, add a DebugValue after the store and remove
|
||||
// the DebugDeclare.
|
||||
uint32_t var_id = var_inst->result_id();
|
||||
if (all_rewritten &&
|
||||
context()->get_debug_info_mgr()->IsDebugDeclared(var_id)) {
|
||||
const analysis::Type* var_type =
|
||||
context()->get_type_mgr()->GetType(var_inst->type_id());
|
||||
const analysis::Type* store_type = var_type->AsPointer()->pointee_type();
|
||||
if (!(store_type->AsStruct() || store_type->AsArray())) {
|
||||
context()->get_debug_info_mgr()->AddDebugValue(
|
||||
store_inst, var_id, store_inst->GetSingleWordInOperand(1),
|
||||
store_inst);
|
||||
context()->get_debug_info_mgr()->KillDebugDeclares(var_id);
|
||||
}
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
|
||||
@@ -172,6 +192,14 @@ Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
|
||||
case SpvOpName:
|
||||
case SpvOpCopyObject:
|
||||
break;
|
||||
case SpvOpExtInst: {
|
||||
auto dbg_op = user->GetOpenCL100DebugOpcode();
|
||||
if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
|
||||
dbg_op == OpenCLDebugInfo100DebugValue) {
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
default:
|
||||
if (!user->IsDecoration()) {
|
||||
// Don't know if this instruction modifies the variable.
|
||||
@@ -218,7 +246,8 @@ bool LocalSingleStoreElimPass::FeedsAStore(Instruction* inst) const {
|
||||
}
|
||||
|
||||
bool LocalSingleStoreElimPass::RewriteLoads(
|
||||
Instruction* store_inst, const std::vector<Instruction*>& uses) {
|
||||
Instruction* store_inst, const std::vector<Instruction*>& uses,
|
||||
bool* all_rewritten) {
|
||||
BasicBlock* store_block = context()->get_instr_block(store_inst);
|
||||
DominatorAnalysis* dominator_analysis =
|
||||
context()->GetDominatorAnalysis(store_block->GetParent());
|
||||
@@ -229,16 +258,22 @@ bool LocalSingleStoreElimPass::RewriteLoads(
|
||||
else
|
||||
stored_id = store_inst->GetSingleWordInOperand(kVariableInitIdInIdx);
|
||||
|
||||
std::vector<Instruction*> uses_in_store_block;
|
||||
*all_rewritten = true;
|
||||
bool modified = false;
|
||||
for (Instruction* use : uses) {
|
||||
if (use->opcode() == SpvOpLoad) {
|
||||
if (dominator_analysis->Dominates(store_inst, use)) {
|
||||
modified = true;
|
||||
context()->KillNamesAndDecorates(use->result_id());
|
||||
context()->ReplaceAllUsesWith(use->result_id(), stored_id);
|
||||
context()->KillInst(use);
|
||||
}
|
||||
if (use->opcode() == SpvOpStore) continue;
|
||||
auto dbg_op = use->GetOpenCL100DebugOpcode();
|
||||
if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
|
||||
dbg_op == OpenCLDebugInfo100DebugValue)
|
||||
continue;
|
||||
if (use->opcode() == SpvOpLoad &&
|
||||
dominator_analysis->Dominates(store_inst, use)) {
|
||||
modified = true;
|
||||
context()->KillNamesAndDecorates(use->result_id());
|
||||
context()->ReplaceAllUsesWith(use->result_id(), stored_id);
|
||||
context()->KillInst(use);
|
||||
} else {
|
||||
*all_rewritten = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,9 +89,10 @@ class LocalSingleStoreElimPass : public Pass {
|
||||
bool FeedsAStore(Instruction* inst) const;
|
||||
|
||||
// Replaces all of the loads in |uses| by the value stored in |store_inst|.
|
||||
// The load instructions are then killed.
|
||||
// The load instructions are then killed. |all_rewritten| is true iff all
|
||||
// uses have been rewritten.
|
||||
bool RewriteLoads(Instruction* store_inst,
|
||||
const std::vector<Instruction*>& uses);
|
||||
const std::vector<Instruction*>& uses, bool* all_rewritten);
|
||||
|
||||
// Extensions supported by this pass.
|
||||
std::unordered_set<std::string> extensions_allowlist_;
|
||||
|
||||
4
3rdparty/spirv-tools/source/opt/pass.h
vendored
4
3rdparty/spirv-tools/source/opt/pass.h
vendored
@@ -71,10 +71,6 @@ class Pass {
|
||||
return context()->get_def_use_mgr();
|
||||
}
|
||||
|
||||
analysis::DebugInfoManager* get_debug_info_mgr() const {
|
||||
return context()->get_debug_info_mgr();
|
||||
}
|
||||
|
||||
analysis::DecorationManager* get_decoration_mgr() const {
|
||||
return context()->get_decoration_mgr();
|
||||
}
|
||||
|
||||
@@ -112,10 +112,10 @@ bool ReduceLoadSize::ReplaceExtract(Instruction* inst) {
|
||||
Instruction* new_access_chain = ir_builder.AddAccessChain(
|
||||
pointer_to_result_type_id,
|
||||
composite_inst->GetSingleWordInOperand(kLoadPointerInIdx), ids);
|
||||
Instruction* new_laod =
|
||||
Instruction* new_load =
|
||||
ir_builder.AddLoad(inst->type_id(), new_access_chain->result_id());
|
||||
|
||||
context()->ReplaceAllUsesWith(inst->result_id(), new_laod->result_id());
|
||||
context()->ReplaceAllUsesWith(inst->result_id(), new_load->result_id());
|
||||
context()->KillInst(inst);
|
||||
return true;
|
||||
}
|
||||
@@ -139,6 +139,7 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) {
|
||||
|
||||
all_elements_used =
|
||||
!def_use_mgr->WhileEachUser(op_inst, [&elements_used](Instruction* use) {
|
||||
if (use->IsOpenCL100DebugInstr()) return true;
|
||||
if (use->opcode() != SpvOpCompositeExtract ||
|
||||
use->NumInOperands() == 1) {
|
||||
return false;
|
||||
|
||||
@@ -307,7 +307,8 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) {
|
||||
}
|
||||
if (pass_->IsTargetVar(var_id)) {
|
||||
WriteVariable(var_id, bb, val_id);
|
||||
pass_->get_debug_info_mgr()->AddDebugValue(inst, var_id, val_id, inst);
|
||||
pass_->context()->get_debug_info_mgr()->AddDebugValue(inst, var_id, val_id,
|
||||
inst);
|
||||
|
||||
#if SSA_REWRITE_DEBUGGING_LEVEL > 1
|
||||
std::cerr << "\tFound store '%" << var_id << " = %" << val_id << "': "
|
||||
@@ -490,7 +491,7 @@ bool SSARewriter::ApplyReplacements() {
|
||||
|
||||
// Add DebugValue for the new OpPhi instruction.
|
||||
insert_it->SetDebugScope(local_var->GetDebugScope());
|
||||
pass_->get_debug_info_mgr()->AddDebugValue(
|
||||
pass_->context()->get_debug_info_mgr()->AddDebugValue(
|
||||
&*insert_it, phi_candidate->var_id(), phi_candidate->result_id(),
|
||||
&*insert_it);
|
||||
|
||||
|
||||
98
3rdparty/spirv-tools/source/opt/vector_dce.cpp
vendored
98
3rdparty/spirv-tools/source/opt/vector_dce.cpp
vendored
@@ -52,6 +52,9 @@ void VectorDCE::FindLiveComponents(Function* function,
|
||||
// components are live because of arbitrary nesting of structs.
|
||||
function->ForEachInst(
|
||||
[&work_list, this, live_components](Instruction* current_inst) {
|
||||
if (current_inst->IsOpenCL100DebugInstr()) {
|
||||
return;
|
||||
}
|
||||
if (!HasVectorOrScalarResult(current_inst) ||
|
||||
!context()->IsCombinatorInstruction(current_inst)) {
|
||||
MarkUsesAsLive(current_inst, all_components_live_, live_components,
|
||||
@@ -297,51 +300,60 @@ bool VectorDCE::HasScalarResult(const Instruction* inst) const {
|
||||
bool VectorDCE::RewriteInstructions(
|
||||
Function* function, const VectorDCE::LiveComponentMap& live_components) {
|
||||
bool modified = false;
|
||||
function->ForEachInst(
|
||||
[&modified, this, live_components](Instruction* current_inst) {
|
||||
if (!context()->IsCombinatorInstruction(current_inst)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto live_component = live_components.find(current_inst->result_id());
|
||||
if (live_component == live_components.end()) {
|
||||
// If this instruction is not in live_components then it does not
|
||||
// produce a vector, or it is never referenced and ADCE will remove
|
||||
// it. No point in trying to differentiate.
|
||||
return;
|
||||
}
|
||||
// Kill DebugValue in the middle of the instruction iteration will result
|
||||
// in accessing a dangling pointer. We keep dead DebugValue instructions
|
||||
// in |dead_dbg_value| to kill them once after the iteration.
|
||||
std::vector<Instruction*> dead_dbg_value;
|
||||
|
||||
// If no element in the current instruction is used replace it with an
|
||||
// OpUndef.
|
||||
if (live_component->second.Empty()) {
|
||||
modified = true;
|
||||
uint32_t undef_id = this->Type2Undef(current_inst->type_id());
|
||||
context()->KillNamesAndDecorates(current_inst);
|
||||
context()->ReplaceAllUsesWith(current_inst->result_id(), undef_id);
|
||||
context()->KillInst(current_inst);
|
||||
return;
|
||||
}
|
||||
function->ForEachInst([&modified, this, live_components,
|
||||
&dead_dbg_value](Instruction* current_inst) {
|
||||
if (!context()->IsCombinatorInstruction(current_inst)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (current_inst->opcode()) {
|
||||
case SpvOpCompositeInsert:
|
||||
modified |=
|
||||
RewriteInsertInstruction(current_inst, live_component->second);
|
||||
break;
|
||||
case SpvOpCompositeConstruct:
|
||||
// TODO: The members that are not live can be replaced by an undef
|
||||
// or constant. This will remove uses of those values, and possibly
|
||||
// create opportunities for ADCE.
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
});
|
||||
auto live_component = live_components.find(current_inst->result_id());
|
||||
if (live_component == live_components.end()) {
|
||||
// If this instruction is not in live_components then it does not
|
||||
// produce a vector, or it is never referenced and ADCE will remove
|
||||
// it. No point in trying to differentiate.
|
||||
return;
|
||||
}
|
||||
|
||||
// If no element in the current instruction is used replace it with an
|
||||
// OpUndef.
|
||||
if (live_component->second.Empty()) {
|
||||
modified = true;
|
||||
MarkDebugValueUsesAsDead(current_inst, &dead_dbg_value);
|
||||
uint32_t undef_id = this->Type2Undef(current_inst->type_id());
|
||||
context()->KillNamesAndDecorates(current_inst);
|
||||
context()->ReplaceAllUsesWith(current_inst->result_id(), undef_id);
|
||||
context()->KillInst(current_inst);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (current_inst->opcode()) {
|
||||
case SpvOpCompositeInsert:
|
||||
modified |= RewriteInsertInstruction(
|
||||
current_inst, live_component->second, &dead_dbg_value);
|
||||
break;
|
||||
case SpvOpCompositeConstruct:
|
||||
// TODO: The members that are not live can be replaced by an undef
|
||||
// or constant. This will remove uses of those values, and possibly
|
||||
// create opportunities for ADCE.
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
});
|
||||
for (auto* i : dead_dbg_value) context()->KillInst(i);
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool VectorDCE::RewriteInsertInstruction(
|
||||
Instruction* current_inst, const utils::BitVector& live_components) {
|
||||
Instruction* current_inst, const utils::BitVector& live_components,
|
||||
std::vector<Instruction*>* dead_dbg_value) {
|
||||
// If the value being inserted is not live, then we can skip the insert.
|
||||
|
||||
if (current_inst->NumInOperands() == 2) {
|
||||
@@ -355,6 +367,7 @@ bool VectorDCE::RewriteInsertInstruction(
|
||||
|
||||
uint32_t insert_index = current_inst->GetSingleWordInOperand(2);
|
||||
if (!live_components.Get(insert_index)) {
|
||||
MarkDebugValueUsesAsDead(current_inst, dead_dbg_value);
|
||||
context()->KillNamesAndDecorates(current_inst->result_id());
|
||||
uint32_t composite_id =
|
||||
current_inst->GetSingleWordInOperand(kInsertCompositeIdInIdx);
|
||||
@@ -377,6 +390,15 @@ bool VectorDCE::RewriteInsertInstruction(
|
||||
return false;
|
||||
}
|
||||
|
||||
void VectorDCE::MarkDebugValueUsesAsDead(
|
||||
Instruction* composite, std::vector<Instruction*>* dead_dbg_value) {
|
||||
context()->get_def_use_mgr()->ForEachUser(
|
||||
composite, [&dead_dbg_value](Instruction* use) {
|
||||
if (use->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue)
|
||||
dead_dbg_value->push_back(use);
|
||||
});
|
||||
}
|
||||
|
||||
void VectorDCE::AddItemToWorkListIfNeeded(
|
||||
WorkListItem work_item, VectorDCE::LiveComponentMap* live_components,
|
||||
std::vector<WorkListItem>* work_list) {
|
||||
|
||||
8
3rdparty/spirv-tools/source/opt/vector_dce.h
vendored
8
3rdparty/spirv-tools/source/opt/vector_dce.h
vendored
@@ -73,6 +73,11 @@ class VectorDCE : public MemPass {
|
||||
bool RewriteInstructions(Function* function,
|
||||
const LiveComponentMap& live_components);
|
||||
|
||||
// Makrs all DebugValue instructions that use |composite| for their values as
|
||||
// dead instructions by putting them into |dead_dbg_value|.
|
||||
void MarkDebugValueUsesAsDead(Instruction* composite,
|
||||
std::vector<Instruction*>* dead_dbg_value);
|
||||
|
||||
// Rewrites the OpCompositeInsert instruction |current_inst| to avoid
|
||||
// unnecessary computes given that the only components of the result that are
|
||||
// live are |live_components|.
|
||||
@@ -83,7 +88,8 @@ class VectorDCE : public MemPass {
|
||||
// If the composite input to |current_inst| is not live, then it is replaced
|
||||
// by and OpUndef in |current_inst|.
|
||||
bool RewriteInsertInstruction(Instruction* current_inst,
|
||||
const utils::BitVector& live_components);
|
||||
const utils::BitVector& live_components,
|
||||
std::vector<Instruction*>* dead_dbg_value);
|
||||
|
||||
// Returns true if the result of |inst| is a vector or a scalar.
|
||||
bool HasVectorOrScalarResult(const Instruction* inst) const;
|
||||
|
||||
@@ -35,7 +35,8 @@ AUTHORS = ['The Khronos Group Inc.',
|
||||
'Samsung Inc',
|
||||
'André Perez Maselco',
|
||||
'Vasyl Teliman',
|
||||
'Advanced Micro Devices, Inc.']
|
||||
'Advanced Micro Devices, Inc.',
|
||||
'Stefano Milizia']
|
||||
CURRENT_YEAR='2020'
|
||||
|
||||
YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020)'
|
||||
|
||||
Reference in New Issue
Block a user