Updated spirv-tools.
This commit is contained in:
parent
95926756e0
commit
8580112ecb
@ -1 +1 @@
|
||||
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-60-gdf86bb44"
|
||||
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-67-g9702d47c"
|
||||
|
@ -3,6 +3,7 @@ static const SpvCapability pygen_variable_caps_AddressesPhysicalStorageBufferAdd
|
||||
static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer};
|
||||
static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer, SpvCapabilityPhysicalStorageBufferAddressesEXT};
|
||||
static const SpvCapability pygen_variable_caps_CooperativeMatrixNV[] = {SpvCapabilityCooperativeMatrixNV};
|
||||
static const SpvCapability pygen_variable_caps_DemoteToHelperInvocationEXT[] = {SpvCapabilityDemoteToHelperInvocationEXT};
|
||||
static const SpvCapability pygen_variable_caps_DerivativeControl[] = {SpvCapabilityDerivativeControl};
|
||||
static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue};
|
||||
static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilityFragmentMaskAMD};
|
||||
@ -45,6 +46,7 @@ static const SpvCapability pygen_variable_caps_SubgroupVoteKHR[] = {SpvCapabilit
|
||||
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_ballot[] = {spvtools::Extension::kSPV_AMD_shader_ballot};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_fragment_mask[] = {spvtools::Extension::kSPV_AMD_shader_fragment_mask};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_demote_to_helper_invocation[] = {spvtools::Extension::kSPV_EXT_demote_to_helper_invocation};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_decorate_stringSPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_decorate_string, spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
|
||||
@ -433,6 +435,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"CooperativeMatrixLengthNV", SpvOpCooperativeMatrixLengthNV, 1, pygen_variable_caps_CooperativeMatrixNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu},
|
||||
{"BeginInvocationInterlockEXT", SpvOpBeginInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
|
||||
{"EndInvocationInterlockEXT", SpvOpEndInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
|
||||
{"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
|
||||
{"IsHelperInvocationEXT", SpvOpIsHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupShuffleINTEL", SpvOpSubgroupShuffleINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupShuffleDownINTEL", SpvOpSubgroupShuffleDownINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupShuffleUpINTEL", SpvOpSubgroupShuffleUpINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
|
@ -20,6 +20,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
return "SPV_AMD_shader_trinary_minmax";
|
||||
case Extension::kSPV_AMD_texture_gather_bias_lod:
|
||||
return "SPV_AMD_texture_gather_bias_lod";
|
||||
case Extension::kSPV_EXT_demote_to_helper_invocation:
|
||||
return "SPV_EXT_demote_to_helper_invocation";
|
||||
case Extension::kSPV_EXT_descriptor_indexing:
|
||||
return "SPV_EXT_descriptor_indexing";
|
||||
case Extension::kSPV_EXT_fragment_fully_covered:
|
||||
@ -113,8 +115,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
|
||||
|
||||
bool GetExtensionFromString(const char* str, Extension* extension) {
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
|
||||
const auto b = std::begin(known_ext_strs);
|
||||
const auto e = std::end(known_ext_strs);
|
||||
const auto found = std::equal_range(
|
||||
@ -386,6 +388,8 @@ const char* CapabilityToString(SpvCapability capability) {
|
||||
return "ShaderSMBuiltinsNV";
|
||||
case SpvCapabilityFragmentShaderPixelInterlockEXT:
|
||||
return "FragmentShaderPixelInterlockEXT";
|
||||
case SpvCapabilityDemoteToHelperInvocationEXT:
|
||||
return "DemoteToHelperInvocationEXT";
|
||||
case SpvCapabilitySubgroupShuffleINTEL:
|
||||
return "SubgroupShuffleINTEL";
|
||||
case SpvCapabilitySubgroupBufferBlockIOINTEL:
|
||||
|
@ -8,6 +8,7 @@ kSPV_AMD_shader_fragment_mask,
|
||||
kSPV_AMD_shader_image_load_store_lod,
|
||||
kSPV_AMD_shader_trinary_minmax,
|
||||
kSPV_AMD_texture_gather_bias_lod,
|
||||
kSPV_EXT_demote_to_helper_invocation,
|
||||
kSPV_EXT_descriptor_indexing,
|
||||
kSPV_EXT_fragment_fully_covered,
|
||||
kSPV_EXT_fragment_invocation_density,
|
||||
|
@ -90,6 +90,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_explicit_ver
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_fragment_mask[] = {spvtools::Extension::kSPV_AMD_shader_fragment_mask};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_image_load_store_lod[] = {spvtools::Extension::kSPV_AMD_shader_image_load_store_lod};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_AMD_texture_gather_bias_lod[] = {spvtools::Extension::kSPV_AMD_texture_gather_bias_lod};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_demote_to_helper_invocation[] = {spvtools::Extension::kSPV_EXT_demote_to_helper_invocation};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_descriptor_indexing[] = {spvtools::Extension::kSPV_EXT_descriptor_indexing};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_fully_covered[] = {spvtools::Extension::kSPV_EXT_fragment_fully_covered};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate[] = {spvtools::Extension::kSPV_EXT_fragment_invocation_density, spvtools::Extension::kSPV_NV_shading_rate};
|
||||
@ -817,6 +818,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
|
||||
{"FragmentShaderShadingRateInterlockEXT", 5372, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"ShaderSMBuiltinsNV", 5373, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FragmentShaderPixelInterlockEXT", 5378, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"DemoteToHelperInvocationEXT", 5379, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SubgroupImageBlockIOINTEL", 5570, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
|
||||
|
@ -41,6 +41,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
pseudo_random_generator.h
|
||||
random_generator.h
|
||||
replayer.h
|
||||
transformation.h
|
||||
transformation_add_constant_boolean.h
|
||||
transformation_add_constant_scalar.h
|
||||
transformation_add_dead_break.h
|
||||
@ -69,6 +70,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
pseudo_random_generator.cpp
|
||||
random_generator.cpp
|
||||
replayer.cpp
|
||||
transformation.cpp
|
||||
transformation_add_constant_boolean.cpp
|
||||
transformation_add_constant_scalar.cpp
|
||||
transformation_add_dead_break.cpp
|
||||
|
@ -14,12 +14,60 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ToString(const protobufs::Fact& fact) {
|
||||
assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
|
||||
"Right now this is the only fact.");
|
||||
std::stringstream stream;
|
||||
stream << "("
|
||||
<< fact.constant_uniform_fact()
|
||||
.uniform_buffer_element_descriptor()
|
||||
.descriptor_set()
|
||||
<< ", "
|
||||
<< fact.constant_uniform_fact()
|
||||
.uniform_buffer_element_descriptor()
|
||||
.binding()
|
||||
<< ")[";
|
||||
|
||||
bool first = true;
|
||||
for (auto index : fact.constant_uniform_fact()
|
||||
.uniform_buffer_element_descriptor()
|
||||
.index()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
stream << ", ";
|
||||
}
|
||||
stream << index;
|
||||
}
|
||||
|
||||
stream << "] == [";
|
||||
|
||||
first = true;
|
||||
for (auto constant_word : fact.constant_uniform_fact().constant_word()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
stream << ", ";
|
||||
}
|
||||
stream << constant_word;
|
||||
}
|
||||
|
||||
stream << "]";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// The purpose of this struct is to group the fields and data used to represent
|
||||
// facts about uniform constants.
|
||||
struct FactManager::ConstantUniformFacts {
|
||||
@ -288,16 +336,16 @@ FactManager::FactManager() {
|
||||
|
||||
FactManager::~FactManager() = default;
|
||||
|
||||
bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts,
|
||||
void FactManager::AddFacts(const MessageConsumer& message_consumer,
|
||||
const protobufs::FactSequence& initial_facts,
|
||||
opt::IRContext* context) {
|
||||
for (auto& fact : initial_facts.fact()) {
|
||||
if (!AddFact(fact, context)) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2621) Provide
|
||||
// information about the fact that could not be added.
|
||||
return false;
|
||||
message_consumer(
|
||||
SPV_MSG_WARNING, nullptr, {},
|
||||
("Invalid fact " + ToString(fact) + " ignored.").c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact,
|
||||
|
11
3rdparty/spirv-tools/source/fuzz/fact_manager.h
vendored
11
3rdparty/spirv-tools/source/fuzz/fact_manager.h
vendored
@ -41,11 +41,14 @@ class FactManager {
|
||||
~FactManager();
|
||||
|
||||
// Adds all the facts from |facts|, checking them for validity with respect to
|
||||
// |context|. Returns true if and only if all facts are valid.
|
||||
bool AddFacts(const protobufs::FactSequence& facts, opt::IRContext* context);
|
||||
// |context|. Warnings about invalid facts are communicated via
|
||||
// |message_consumer|; such facts are otherwise ignored.
|
||||
void AddFacts(const MessageConsumer& message_consumer,
|
||||
const protobufs::FactSequence& facts, opt::IRContext* context);
|
||||
|
||||
// Adds |fact| to the fact manager, checking it for validity with respect to
|
||||
// |context|. Returns true if and only if the fact is valid.
|
||||
// Checks the fact for validity with respect to |context|. Returns false,
|
||||
// with no side effects, if the fact is invalid. Otherwise adds |fact| to the
|
||||
// fact manager.
|
||||
bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
|
||||
|
||||
// The fact manager will ultimately be responsible for managing a few distinct
|
||||
|
4
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
4
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
vendored
@ -97,9 +97,7 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
|
||||
FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id);
|
||||
|
||||
FactManager fact_manager;
|
||||
if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
|
||||
return Fuzzer::FuzzerResultStatus::kInitialFactsInvalid;
|
||||
}
|
||||
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
|
||||
|
||||
// Add some essential ingredients to the module if they are not already
|
||||
// present, such as boolean constants.
|
||||
|
1
3rdparty/spirv-tools/source/fuzz/fuzzer.h
vendored
1
3rdparty/spirv-tools/source/fuzz/fuzzer.h
vendored
@ -33,7 +33,6 @@ class Fuzzer {
|
||||
kComplete,
|
||||
kFailedToCreateSpirvToolsInterface,
|
||||
kInitialBinaryInvalid,
|
||||
kInitialFactsInvalid,
|
||||
};
|
||||
|
||||
// Constructs a fuzzer from the given target environment.
|
||||
|
@ -30,7 +30,7 @@ FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default;
|
||||
|
||||
void FuzzerPassAddDeadBreaks::Apply() {
|
||||
// We first collect up lots of possibly-applicable transformations.
|
||||
std::vector<protobufs::TransformationAddDeadBreak> candidate_transformations;
|
||||
std::vector<TransformationAddDeadBreak> candidate_transformations;
|
||||
// We consider each function separately.
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
// For a given function, we find all the merge blocks in that function.
|
||||
@ -51,13 +51,12 @@ void FuzzerPassAddDeadBreaks::Apply() {
|
||||
// merge blocks. This will lead to interesting opportunities being
|
||||
// missed.
|
||||
std::vector<uint32_t> phi_ids;
|
||||
auto candidate_transformation =
|
||||
transformation::MakeTransformationAddDeadBreak(
|
||||
block.id(), merge_block_id,
|
||||
GetFuzzerContext()->GetRandomGenerator()->RandomBool(),
|
||||
std::move(phi_ids));
|
||||
if (transformation::IsApplicable(candidate_transformation,
|
||||
GetIRContext(), *GetFactManager())) {
|
||||
auto candidate_transformation = TransformationAddDeadBreak(
|
||||
block.id(), merge_block_id,
|
||||
GetFuzzerContext()->GetRandomGenerator()->RandomBool(),
|
||||
std::move(phi_ids));
|
||||
if (candidate_transformation.IsApplicable(GetIRContext(),
|
||||
*GetFactManager())) {
|
||||
// Only consider a transformation as a candidate if it is applicable.
|
||||
candidate_transformations.push_back(
|
||||
std::move(candidate_transformation));
|
||||
@ -92,11 +91,9 @@ void FuzzerPassAddDeadBreaks::Apply() {
|
||||
}
|
||||
// If the transformation can be applied, apply it and add it to the
|
||||
// sequence of transformations that have been applied.
|
||||
if (transformation::IsApplicable(transformation, GetIRContext(),
|
||||
*GetFactManager())) {
|
||||
transformation::Apply(transformation, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_dead_break() =
|
||||
transformation;
|
||||
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,15 +48,13 @@ void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
|
||||
"The relevant int type should have been added to the module already.");
|
||||
opt::analysis::IntConstant int_constant(registered_int_type, data);
|
||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
|
||||
protobufs::TransformationAddConstantScalar add_constant_int =
|
||||
transformation::MakeTransformationAddConstantScalar(
|
||||
GetFuzzerContext()->GetFreshId(), int_type_id, data);
|
||||
assert(transformation::IsApplicable(add_constant_int, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
TransformationAddConstantScalar add_constant_int =
|
||||
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
|
||||
int_type_id, data);
|
||||
assert(add_constant_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_constant_int, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
|
||||
add_constant_int;
|
||||
add_constant_int.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = add_constant_int.ToMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,15 +74,14 @@ void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
|
||||
"The relevant float type should have been added to the module already.");
|
||||
opt::analysis::FloatConstant float_constant(registered_float_type, data);
|
||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
|
||||
protobufs::TransformationAddConstantScalar add_constant_float =
|
||||
transformation::MakeTransformationAddConstantScalar(
|
||||
GetFuzzerContext()->GetFreshId(), float_type_id, data);
|
||||
assert(transformation::IsApplicable(add_constant_float, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
TransformationAddConstantScalar add_constant_float =
|
||||
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
|
||||
float_type_id, data);
|
||||
assert(add_constant_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_constant_float, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
|
||||
add_constant_float;
|
||||
add_constant_float.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
add_constant_float.ToMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,15 +90,13 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
// Add boolean type if not present.
|
||||
opt::analysis::Bool temp_bool_type;
|
||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
|
||||
protobufs::TransformationAddTypeBoolean add_type_boolean =
|
||||
transformation::MakeTransformationAddTypeBoolean(
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
assert(transformation::IsApplicable(add_type_boolean, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
auto add_type_boolean =
|
||||
TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
|
||||
assert(add_type_boolean.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_type_boolean, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_type_boolean() =
|
||||
add_type_boolean;
|
||||
add_type_boolean.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
add_type_boolean.ToMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,15 +105,12 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
for (auto is_signed : {true, false}) {
|
||||
opt::analysis::Integer temp_int_type(32, is_signed);
|
||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
|
||||
protobufs::TransformationAddTypeInt add_type_int =
|
||||
transformation::MakeTransformationAddTypeInt(
|
||||
GetFuzzerContext()->GetFreshId(), 32, is_signed);
|
||||
assert(transformation::IsApplicable(add_type_int, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
|
||||
GetFuzzerContext()->GetFreshId(), 32, is_signed);
|
||||
assert(add_type_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_type_int, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_type_int() =
|
||||
add_type_int;
|
||||
add_type_int.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = add_type_int.ToMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,15 +119,12 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
// Add 32-bit float type if not present.
|
||||
opt::analysis::Float temp_float_type(32);
|
||||
if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
|
||||
protobufs::TransformationAddTypeFloat add_type_float =
|
||||
transformation::MakeTransformationAddTypeFloat(
|
||||
GetFuzzerContext()->GetFreshId(), 32);
|
||||
assert(transformation::IsApplicable(add_type_float, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
TransformationAddTypeFloat add_type_float =
|
||||
TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
|
||||
assert(add_type_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_type_float, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_type_float() =
|
||||
add_type_float;
|
||||
add_type_float.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = add_type_float.ToMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,17 +138,14 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
// Add OpConstantTrue/False if not already there.
|
||||
opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
|
||||
if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
|
||||
protobufs::TransformationAddConstantBoolean add_constant_boolean =
|
||||
transformation::MakeTransformationAddConstantBoolean(
|
||||
GetFuzzerContext()->GetFreshId(), boolean_value);
|
||||
assert(transformation::IsApplicable(add_constant_boolean, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
TransformationAddConstantBoolean add_constant_boolean(
|
||||
GetFuzzerContext()->GetFreshId(), boolean_value);
|
||||
assert(add_constant_boolean.IsApplicable(GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_constant_boolean, GetIRContext(),
|
||||
GetFactManager());
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_add_constant_boolean() = add_constant_boolean;
|
||||
add_constant_boolean.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
add_constant_boolean.ToMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,15 +182,13 @@ void FuzzerPassAddUsefulConstructs::Apply() {
|
||||
opt::analysis::Pointer uniform_pointer(element_type,
|
||||
SpvStorageClassUniform);
|
||||
if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
|
||||
auto add_pointer = transformation::MakeTransformationAddTypePointer(
|
||||
GetFuzzerContext()->GetFreshId(), SpvStorageClassUniform,
|
||||
element_type_id);
|
||||
assert(transformation::IsApplicable(add_pointer, GetIRContext(),
|
||||
*GetFactManager()) &&
|
||||
auto add_pointer =
|
||||
TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
|
||||
SpvStorageClassUniform, element_type_id);
|
||||
assert(add_pointer.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"Should be applicable by construction.");
|
||||
transformation::Apply(add_pointer, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_add_type_pointer() =
|
||||
add_pointer;
|
||||
add_pointer.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = add_pointer.ToMessage();
|
||||
}
|
||||
std::vector<uint32_t> words;
|
||||
for (auto word : fact_and_type_id.first.constant_word()) {
|
||||
|
@ -80,25 +80,20 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
|
||||
// We can now make a transformation that will replace |bool_constant_use|
|
||||
// with an expression of the form (written using infix notation):
|
||||
// |lhs_id| |comparison_opcode| |rhs_id|
|
||||
auto transformation = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
bool_constant_use, lhs_id, rhs_id, comparison_opcode,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
auto transformation = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
bool_constant_use, lhs_id, rhs_id, comparison_opcode,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
// The transformation should be applicable by construction.
|
||||
assert(transformation::IsApplicable(transformation, GetIRContext(),
|
||||
*GetFactManager()));
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()));
|
||||
|
||||
// Applying this transformation yields a pointer to the new instruction that
|
||||
// computes the result of the binary expression.
|
||||
auto binary_operator_instruction =
|
||||
transformation::Apply(transformation, GetIRContext(), GetFactManager());
|
||||
transformation.ApplyWithResult(GetIRContext(), GetFactManager());
|
||||
|
||||
// Add this transformation to the sequence of transformations that have been
|
||||
// applied.
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_replace_boolean_constant_with_constant_binary() =
|
||||
transformation;
|
||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
||||
|
||||
// Having made a binary expression, there may now be opportunities to further
|
||||
// obfuscate the constants used as the LHS and RHS of the expression (e.g. by
|
||||
@ -331,17 +326,13 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
|
||||
static_cast<uint32_t>(uniform_descriptors.size()))];
|
||||
// Create, apply and record a transformation to replace the constant use with
|
||||
// the result of a load from the chosen uniform.
|
||||
auto transformation =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
auto transformation = TransformationReplaceConstantWithUniform(
|
||||
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
// Transformation should be applicable by construction.
|
||||
assert(transformation::IsApplicable(transformation, GetIRContext(),
|
||||
*GetFactManager()));
|
||||
transformation::Apply(transformation, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_replace_constant_with_uniform() = transformation;
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()));
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
||||
}
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
||||
|
@ -65,14 +65,11 @@ void FuzzerPassPermuteBlocks::Apply() {
|
||||
// The loop is guaranteed to terminate because a block cannot be pushed
|
||||
// down indefinitely.
|
||||
while (true) {
|
||||
protobufs::TransformationMoveBlockDown message;
|
||||
message.set_block_id(*id);
|
||||
if (transformation::IsApplicable(message, GetIRContext(),
|
||||
*GetFactManager())) {
|
||||
transformation::Apply(message, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()
|
||||
->add_transformation()
|
||||
->mutable_move_block_down() = message;
|
||||
TransformationMoveBlockDown transformation(*id);
|
||||
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
transformation.ToMessage();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -80,17 +80,15 @@ void FuzzerPassSplitBlocks::Apply() {
|
||||
auto base_offset = base_offset_pairs
|
||||
[GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
|
||||
static_cast<uint32_t>(base_offset_pairs.size()))];
|
||||
auto message = transformation::MakeTransformationSplitBlock(
|
||||
base_offset.first, base_offset.second,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
auto transformation =
|
||||
TransformationSplitBlock(base_offset.first, base_offset.second,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
// If the position we have chosen turns out to be a valid place to split
|
||||
// the block, we apply the split. Otherwise the block just doesn't get
|
||||
// split.
|
||||
if (transformation::IsApplicable(message, GetIRContext(),
|
||||
*GetFactManager())) {
|
||||
transformation::Apply(message, GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation()->mutable_split_block() =
|
||||
message;
|
||||
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() = transformation.ToMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
130
3rdparty/spirv-tools/source/fuzz/replayer.cpp
vendored
130
3rdparty/spirv-tools/source/fuzz/replayer.cpp
vendored
@ -18,6 +18,7 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_add_constant_boolean.h"
|
||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
||||
#include "source/fuzz/transformation_add_dead_break.h"
|
||||
@ -35,121 +36,6 @@
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if and only if the precondition for |transformation| holds, with
|
||||
// respect to the given |context| and |fact_manager|.
|
||||
bool IsApplicable(const protobufs::Transformation& transformation,
|
||||
opt::IRContext* context, const FactManager& fact_manager) {
|
||||
switch (transformation.transformation_case()) {
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
|
||||
return transformation::IsApplicable(transformation.add_constant_boolean(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
|
||||
return transformation::IsApplicable(transformation.add_constant_scalar(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
|
||||
return transformation::IsApplicable(transformation.add_dead_break(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
|
||||
return transformation::IsApplicable(transformation.add_type_boolean(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeFloat:
|
||||
return transformation::IsApplicable(transformation.add_type_float(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeInt:
|
||||
return transformation::IsApplicable(transformation.add_type_int(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kAddTypePointer:
|
||||
return transformation::IsApplicable(transformation.add_type_pointer(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
return transformation::IsApplicable(transformation.move_block_down(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceBooleanConstantWithConstantBinary:
|
||||
return transformation::IsApplicable(
|
||||
transformation.replace_boolean_constant_with_constant_binary(),
|
||||
context, fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceConstantWithUniform:
|
||||
return transformation::IsApplicable(
|
||||
transformation.replace_constant_with_uniform(), context,
|
||||
fact_manager);
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
return transformation::IsApplicable(transformation.split_block(), context,
|
||||
fact_manager);
|
||||
default:
|
||||
assert(transformation.transformation_case() ==
|
||||
protobufs::Transformation::TRANSFORMATION_NOT_SET &&
|
||||
"Unhandled transformation type.");
|
||||
assert(false && "An unset transformation was encountered.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Requires that IsApplicable holds. Applies |transformation| to the given
|
||||
// |context| and |fact_manager|.
|
||||
void Apply(const protobufs::Transformation& transformation,
|
||||
opt::IRContext* context, FactManager* fact_manager) {
|
||||
switch (transformation.transformation_case()) {
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
|
||||
transformation::Apply(transformation.add_constant_boolean(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
|
||||
transformation::Apply(transformation.add_constant_scalar(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
|
||||
transformation::Apply(transformation.add_dead_break(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
|
||||
transformation::Apply(transformation.add_type_boolean(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeFloat:
|
||||
transformation::Apply(transformation.add_type_float(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeInt:
|
||||
transformation::Apply(transformation.add_type_int(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kAddTypePointer:
|
||||
transformation::Apply(transformation.add_type_pointer(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
transformation::Apply(transformation.move_block_down(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceBooleanConstantWithConstantBinary:
|
||||
transformation::Apply(
|
||||
transformation.replace_boolean_constant_with_constant_binary(),
|
||||
context, fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceConstantWithUniform:
|
||||
transformation::Apply(transformation.replace_constant_with_uniform(),
|
||||
context, fact_manager);
|
||||
break;
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
transformation::Apply(transformation.split_block(), context,
|
||||
fact_manager);
|
||||
break;
|
||||
default:
|
||||
assert(transformation.transformation_case() ==
|
||||
protobufs::Transformation::TRANSFORMATION_NOT_SET &&
|
||||
"Unhandled transformation type.");
|
||||
assert(false && "An unset transformation was encountered.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct Replayer::Impl {
|
||||
explicit Impl(spv_target_env env) : target_env(env) {}
|
||||
|
||||
@ -195,18 +81,18 @@ Replayer::ReplayerResultStatus Replayer::Run(
|
||||
assert(ir_context);
|
||||
|
||||
FactManager fact_manager;
|
||||
if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
|
||||
return Replayer::ReplayerResultStatus::kInitialFactsInvalid;
|
||||
}
|
||||
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
|
||||
|
||||
// Consider the transformation proto messages in turn.
|
||||
for (auto& transformation : transformation_sequence_in.transformation()) {
|
||||
for (auto& message : transformation_sequence_in.transformation()) {
|
||||
auto transformation = Transformation::FromMessage(message);
|
||||
|
||||
// Check whether the transformation can be applied.
|
||||
if (IsApplicable(transformation, ir_context.get(), fact_manager)) {
|
||||
if (transformation->IsApplicable(ir_context.get(), fact_manager)) {
|
||||
// The transformation is applicable, so apply it, and copy it to the
|
||||
// sequence of transformations that were applied.
|
||||
Apply(transformation, ir_context.get(), &fact_manager);
|
||||
*transformation_sequence_out->add_transformation() = transformation;
|
||||
transformation->Apply(ir_context.get(), &fact_manager);
|
||||
*transformation_sequence_out->add_transformation() = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
1
3rdparty/spirv-tools/source/fuzz/replayer.h
vendored
1
3rdparty/spirv-tools/source/fuzz/replayer.h
vendored
@ -33,7 +33,6 @@ class Replayer {
|
||||
kComplete,
|
||||
kFailedToCreateSpirvToolsInterface,
|
||||
kInitialBinaryInvalid,
|
||||
kInitialFactsInvalid,
|
||||
};
|
||||
|
||||
// Constructs a replayer from the given target environment.
|
||||
|
80
3rdparty/spirv-tools/source/fuzz/transformation.cpp
vendored
Normal file
80
3rdparty/spirv-tools/source/fuzz/transformation.cpp
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "source/util/make_unique.h"
|
||||
#include "transformation_add_constant_boolean.h"
|
||||
#include "transformation_add_constant_scalar.h"
|
||||
#include "transformation_add_dead_break.h"
|
||||
#include "transformation_add_type_boolean.h"
|
||||
#include "transformation_add_type_float.h"
|
||||
#include "transformation_add_type_int.h"
|
||||
#include "transformation_add_type_pointer.h"
|
||||
#include "transformation_move_block_down.h"
|
||||
#include "transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "transformation_replace_constant_with_uniform.h"
|
||||
#include "transformation_split_block.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
Transformation::~Transformation() = default;
|
||||
|
||||
std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
const protobufs::Transformation& message) {
|
||||
switch (message.transformation_case()) {
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
|
||||
return MakeUnique<TransformationAddConstantBoolean>(
|
||||
message.add_constant_boolean());
|
||||
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
|
||||
return MakeUnique<TransformationAddConstantScalar>(
|
||||
message.add_constant_scalar());
|
||||
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
|
||||
return MakeUnique<TransformationAddDeadBreak>(message.add_dead_break());
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
|
||||
return MakeUnique<TransformationAddTypeBoolean>(
|
||||
message.add_type_boolean());
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeFloat:
|
||||
return MakeUnique<TransformationAddTypeFloat>(message.add_type_float());
|
||||
case protobufs::Transformation::TransformationCase::kAddTypeInt:
|
||||
return MakeUnique<TransformationAddTypeInt>(message.add_type_int());
|
||||
case protobufs::Transformation::TransformationCase::kAddTypePointer:
|
||||
return MakeUnique<TransformationAddTypePointer>(
|
||||
message.add_type_pointer());
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
return MakeUnique<TransformationMoveBlockDown>(message.move_block_down());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceBooleanConstantWithConstantBinary:
|
||||
return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(
|
||||
message.replace_boolean_constant_with_constant_binary());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceConstantWithUniform:
|
||||
return MakeUnique<TransformationReplaceConstantWithUniform>(
|
||||
message.replace_constant_with_uniform());
|
||||
case protobufs::Transformation::TransformationCase::kSplitBlock:
|
||||
return MakeUnique<TransformationSplitBlock>(message.split_block());
|
||||
default:
|
||||
assert(message.transformation_case() ==
|
||||
protobufs::Transformation::TRANSFORMATION_NOT_SET &&
|
||||
"Unhandled transformation type.");
|
||||
assert(false && "An unset transformation was encountered.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
91
3rdparty/spirv-tools/source/fuzz/transformation.h
vendored
Normal file
91
3rdparty/spirv-tools/source/fuzz/transformation.h
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Rules for transformations
|
||||
// -------------------------
|
||||
//
|
||||
// - Immutability: a transformation must be immutable.
|
||||
// - Ability to copy and serialize: to ensure that a copy of a transformation,
|
||||
// possibly saved out to disk and read back again, is indistinguishable
|
||||
// from the original transformation, thus a transformation must depend
|
||||
// only on well-defined pieces of state, such as instruction ids. It must
|
||||
// not rely on state such as pointers to instructions and blocks.
|
||||
// - Determinism: the effect of a transformation on a module be a deterministic
|
||||
// function of the module and the transformation. Any randomization should
|
||||
// be applied before creating the transformation, not during its
|
||||
// application.
|
||||
// - Well-defined and precondition: the 'IsApplicable' method should only
|
||||
// return true if the transformation can be cleanly applied to the given
|
||||
// module, to mutate it into a valid and semantically-equivalent module, as
|
||||
// long as the module is initially valid.
|
||||
// - Ability to test precondition on any valid module: 'IsApplicable' should be
|
||||
// designed so that it is safe to ask whether a transformation is
|
||||
// applicable to an arbitrary valid module. For example, if a
|
||||
// transformation involves a block id, 'IsApplicable' should check whether
|
||||
// the module indeed has a block with that id, and return false if not. It
|
||||
// must not assume that there is such a block.
|
||||
// - Documented precondition: while the implementation of 'IsApplicable' should
|
||||
// should codify the precondition, the method should be commented in the
|
||||
// header file for a transformation with a precise English description of
|
||||
// the precondition.
|
||||
// - Documented effect: while the implementation of 'Apply' should codify the
|
||||
// effect of the transformation, the method should be commented in the
|
||||
// header file for a transformation with a precise English description of
|
||||
// the effect.
|
||||
|
||||
class Transformation {
|
||||
public:
|
||||
// A precondition that determines whether the transformation can be cleanly
|
||||
// applied in a semantics-preserving manner to the SPIR-V module given by
|
||||
// |context|, in the presence of facts captured by |fact_manager|.
|
||||
// Preconditions for individual transformations must be documented in the
|
||||
// associated header file using precise English. The fact manager is used to
|
||||
// provide access to facts about the module that are known to be true, on
|
||||
// which the precondition may depend.
|
||||
virtual bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const = 0;
|
||||
|
||||
// Requires that IsApplicable(context, fact_manager) holds. Applies the
|
||||
// transformation, mutating |context| and possibly updating |fact_manager|
|
||||
// with new facts established by the transformation.
|
||||
virtual void Apply(opt::IRContext* context,
|
||||
FactManager* fact_manager) const = 0;
|
||||
|
||||
// Turns the transformation into a protobuf message for serialization.
|
||||
virtual protobufs::Transformation ToMessage() const = 0;
|
||||
|
||||
virtual ~Transformation();
|
||||
|
||||
// Factory method to obtain a transformation object from the protobuf
|
||||
// representation of a transformation given by |message|.
|
||||
static std::unique_ptr<Transformation> FromMessage(
|
||||
const protobufs::Transformation& message);
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_H_
|
@ -19,42 +19,46 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddConstantBoolean::TransformationAddConstantBoolean(
|
||||
const protobufs::TransformationAddConstantBoolean& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message,
|
||||
IRContext* context, const FactManager& /*unused*/) {
|
||||
TransformationAddConstantBoolean::TransformationAddConstantBoolean(
|
||||
uint32_t fresh_id, bool is_true) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_is_true(is_true);
|
||||
}
|
||||
|
||||
bool TransformationAddConstantBoolean::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
opt::analysis::Bool bool_type;
|
||||
if (!context->get_type_mgr()->GetId(&bool_type)) {
|
||||
// No OpTypeBool is present.
|
||||
return false;
|
||||
}
|
||||
return fuzzerutil::IsFreshId(context, message.fresh_id());
|
||||
return fuzzerutil::IsFreshId(context, message_.fresh_id());
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddConstantBoolean& message,
|
||||
IRContext* context, FactManager* /*unused*/) {
|
||||
void TransformationAddConstantBoolean::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
opt::analysis::Bool bool_type;
|
||||
// Add the boolean constant to the module, ensuring the module's id bound is
|
||||
// high enough.
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
context->module()->AddGlobalValue(
|
||||
message.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
|
||||
message.fresh_id(), context->get_type_mgr()->GetId(&bool_type));
|
||||
message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
|
||||
message_.fresh_id(), context->get_type_mgr()->GetId(&bool_type));
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddConstantBoolean
|
||||
MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true) {
|
||||
protobufs::TransformationAddConstantBoolean result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_is_true(is_true);
|
||||
protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_constant_boolean() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,27 +17,34 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |fresh_id| must not be used by the module.
|
||||
// - The module must already contain OpTypeBool.
|
||||
bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddConstantBoolean : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddConstantBoolean(
|
||||
const protobufs::TransformationAddConstantBoolean& message);
|
||||
|
||||
// - Adds OpConstantTrue (OpConstantFalse) to the module with id |fresh_id|
|
||||
// if |is_true| holds (does not hold).
|
||||
void Apply(const protobufs::TransformationAddConstantBoolean& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddConstantBoolean(uint32_t fresh_id, bool is_true);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddConstantBoolean
|
||||
MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true);
|
||||
// - |message_.fresh_id| must not be used by the module.
|
||||
// - The module must already contain OpTypeBool.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// - Adds OpConstantTrue (OpConstantFalse) to the module with id
|
||||
// |message_.fresh_id| if |message_.is_true| holds (does not hold).
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddConstantBoolean message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,19 +18,29 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddConstantScalar::TransformationAddConstantScalar(
|
||||
const spvtools::fuzz::protobufs::TransformationAddConstantScalar& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
TransformationAddConstantScalar::TransformationAddConstantScalar(
|
||||
uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_type_id(type_id);
|
||||
for (auto word : words) {
|
||||
message_.add_word(word);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransformationAddConstantScalar::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The id needs to be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
// The type id for the scalar must exist and be a type.
|
||||
auto type = context->get_type_mgr()->GetType(message.type_id());
|
||||
auto type = context->get_type_mgr()->GetType(message_.type_id());
|
||||
if (!type) {
|
||||
return false;
|
||||
}
|
||||
@ -47,37 +57,31 @@ bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
|
||||
|
||||
// The number of words provided by the transformation needs to match the
|
||||
// width of the type.
|
||||
return static_cast<uint32_t>(message.word().size()) == words;
|
||||
return static_cast<uint32_t>(message_.word().size()) == words;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddConstantScalar& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationAddConstantScalar::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
opt::Instruction::OperandList operand_list;
|
||||
for (auto word : message.word()) {
|
||||
for (auto word : message_.word()) {
|
||||
operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}});
|
||||
}
|
||||
context->module()->AddGlobalValue(
|
||||
MakeUnique<opt::Instruction>(context, SpvOpConstant, message.type_id(),
|
||||
message.fresh_id(), operand_list));
|
||||
MakeUnique<opt::Instruction>(context, SpvOpConstant, message_.type_id(),
|
||||
message_.fresh_id(), operand_list));
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar(
|
||||
uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words) {
|
||||
protobufs::TransformationAddConstantScalar result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_type_id(type_id);
|
||||
for (auto word : words) {
|
||||
result.add_word(word);
|
||||
}
|
||||
protobufs::Transformation TransformationAddConstantScalar::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_constant_scalar() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -19,27 +19,36 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module
|
||||
// - |message.type_id| must be the id of a floating-point or integer type
|
||||
// - The size of |message.word| must be compatible with the width of this type
|
||||
bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddConstantScalar : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddConstantScalar(
|
||||
const protobufs::TransformationAddConstantScalar& message);
|
||||
|
||||
// Adds a new OpConstant instruction with the given type and words.
|
||||
void Apply(const protobufs::TransformationAddConstantScalar& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddConstantScalar(uint32_t fresh_id, uint32_t type_id,
|
||||
std::vector<uint32_t> words);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar(
|
||||
uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words);
|
||||
// - |message_.fresh_id| must not be used by the module
|
||||
// - |message_.type_id| must be the id of a floating-point or integer type
|
||||
// - The size of |message_.word| must be compatible with the width of this
|
||||
// type
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds a new OpConstant instruction with the given type and words.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddConstantScalar message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -21,15 +21,24 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::BasicBlock;
|
||||
using opt::IRContext;
|
||||
using opt::Instruction;
|
||||
TransformationAddDeadBreak::TransformationAddDeadBreak(
|
||||
const spvtools::fuzz::protobufs::TransformationAddDeadBreak& message)
|
||||
: message_(message) {}
|
||||
|
||||
namespace {
|
||||
TransformationAddDeadBreak::TransformationAddDeadBreak(
|
||||
uint32_t from_block, uint32_t to_block, bool break_condition_value,
|
||||
std::vector<uint32_t> phi_id) {
|
||||
message_.set_from_block(from_block);
|
||||
message_.set_to_block(to_block);
|
||||
message_.set_break_condition_value(break_condition_value);
|
||||
for (auto id : phi_id) {
|
||||
message_.add_phi_id(id);
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock* MaybeFindBlock(IRContext* context, uint32_t maybe_block_id) {
|
||||
opt::BasicBlock* TransformationAddDeadBreak::MaybeFindBlock(
|
||||
opt::IRContext* context, uint32_t maybe_block_id) const {
|
||||
auto inst = context->get_def_use_mgr()->GetDef(maybe_block_id);
|
||||
if (inst == nullptr) {
|
||||
// No instruction defining this id was found.
|
||||
@ -43,14 +52,15 @@ BasicBlock* MaybeFindBlock(IRContext* context, uint32_t maybe_block_id) {
|
||||
return context->cfg()->block(maybe_block_id);
|
||||
}
|
||||
|
||||
bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
|
||||
IRContext* context, BasicBlock* bb_from, BasicBlock* bb_to) {
|
||||
bool TransformationAddDeadBreak::PhiIdsOk(opt::IRContext* context,
|
||||
opt::BasicBlock* bb_from,
|
||||
opt::BasicBlock* bb_to) const {
|
||||
if (bb_from->IsSuccessor(bb_to)) {
|
||||
// There is already an edge from |from_block| to |to_block|, so there is
|
||||
// no need to extend OpPhi instructions. Do not allow phi ids to be
|
||||
// present. This might turn out to be too strict; perhaps it would be OK
|
||||
// just to ignore the ids in this case.
|
||||
return message.phi_id().empty();
|
||||
return message_.phi_id().empty();
|
||||
}
|
||||
// The break would add a previously non-existent edge from |from_block| to
|
||||
// |to_block|, so we go through the given phi ids and check that they exactly
|
||||
@ -65,14 +75,14 @@ bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
|
||||
// a non-OpPhi then we have seen them all.
|
||||
break;
|
||||
}
|
||||
if (phi_index == static_cast<uint32_t>(message.phi_id().size())) {
|
||||
if (phi_index == static_cast<uint32_t>(message_.phi_id().size())) {
|
||||
// Not enough phi ids have been provided to account for the OpPhi
|
||||
// instructions.
|
||||
return false;
|
||||
}
|
||||
// Look for an instruction defining the next phi id.
|
||||
Instruction* phi_extension =
|
||||
context->get_def_use_mgr()->GetDef(message.phi_id()[phi_index]);
|
||||
opt::Instruction* phi_extension =
|
||||
context->get_def_use_mgr()->GetDef(message_.phi_id()[phi_index]);
|
||||
if (!phi_extension) {
|
||||
// The id given to extend this OpPhi does not exist.
|
||||
return false;
|
||||
@ -101,28 +111,26 @@ bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
|
||||
// Reject the transformation if not all of the ids for extending OpPhi
|
||||
// instructions are needed. This might turn out to be stricter than necessary;
|
||||
// perhaps it would be OK just to not use the ids in this case.
|
||||
return phi_index == static_cast<uint32_t>(message.phi_id().size());
|
||||
return phi_index == static_cast<uint32_t>(message_.phi_id().size());
|
||||
}
|
||||
|
||||
bool FromBlockIsInLoopContinueConstruct(
|
||||
const protobufs::TransformationAddDeadBreak& message, IRContext* context,
|
||||
uint32_t maybe_loop_header) {
|
||||
bool TransformationAddDeadBreak::FromBlockIsInLoopContinueConstruct(
|
||||
opt::IRContext* context, uint32_t maybe_loop_header) const {
|
||||
// We deem a block to be part of a loop's continue construct if the loop's
|
||||
// continue target dominates the block.
|
||||
auto containing_construct_block = context->cfg()->block(maybe_loop_header);
|
||||
if (containing_construct_block->IsLoopHeader()) {
|
||||
auto continue_target = containing_construct_block->ContinueBlockId();
|
||||
if (context->GetDominatorAnalysis(containing_construct_block->GetParent())
|
||||
->Dominates(continue_target, message.from_block())) {
|
||||
->Dominates(continue_target, message_.from_block())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AddingBreakRespectsStructuredControlFlow(
|
||||
const protobufs::TransformationAddDeadBreak& message, IRContext* context,
|
||||
BasicBlock* bb_from) {
|
||||
bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
|
||||
opt::IRContext* context, opt::BasicBlock* bb_from) const {
|
||||
// Look at the structured control flow associated with |from_block| and
|
||||
// check whether it is contained in an appropriate construct with merge id
|
||||
// |to_block| such that a break from |from_block| to |to_block| is legal.
|
||||
@ -146,7 +154,7 @@ bool AddingBreakRespectsStructuredControlFlow(
|
||||
if (bb_from->IsLoopHeader()) {
|
||||
// Case (1) holds if |to_block| is the merge block for the loop;
|
||||
// otherwise no case holds
|
||||
return bb_from->MergeBlockId() == message.to_block();
|
||||
return bb_from->MergeBlockId() == message_.to_block();
|
||||
}
|
||||
|
||||
// Both cases (2) and (3) require that |from_block| is inside some
|
||||
@ -154,14 +162,14 @@ bool AddingBreakRespectsStructuredControlFlow(
|
||||
|
||||
auto containing_construct =
|
||||
context->GetStructuredCFGAnalysis()->ContainingConstruct(
|
||||
message.from_block());
|
||||
message_.from_block());
|
||||
if (!containing_construct) {
|
||||
// |from_block| is not in a construct from which we can break.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consider case (2)
|
||||
if (message.to_block() ==
|
||||
if (message_.to_block() ==
|
||||
context->cfg()->block(containing_construct)->MergeBlockId()) {
|
||||
// This looks like an instance of case (2).
|
||||
// However, the structured CFG analysis regards the continue construct of a
|
||||
@ -172,27 +180,24 @@ bool AddingBreakRespectsStructuredControlFlow(
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2577): We do not
|
||||
// currently allow a dead break from a back edge block, but we could and
|
||||
// ultimately should.
|
||||
return !FromBlockIsInLoopContinueConstruct(message, context,
|
||||
containing_construct);
|
||||
return !FromBlockIsInLoopContinueConstruct(context, containing_construct);
|
||||
}
|
||||
|
||||
// Case (3) holds if and only if |to_block| is the merge block for this
|
||||
// innermost loop that contains |from_block|
|
||||
auto containing_loop_header =
|
||||
context->GetStructuredCFGAnalysis()->ContainingLoop(message.from_block());
|
||||
context->GetStructuredCFGAnalysis()->ContainingLoop(
|
||||
message_.from_block());
|
||||
if (containing_loop_header &&
|
||||
message.to_block() ==
|
||||
message_.to_block() ==
|
||||
context->cfg()->block(containing_loop_header)->MergeBlockId()) {
|
||||
return !FromBlockIsInLoopContinueConstruct(message, context,
|
||||
containing_loop_header);
|
||||
return !FromBlockIsInLoopContinueConstruct(context, containing_loop_header);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
|
||||
IRContext* context, const FactManager& /*unused*/) {
|
||||
bool TransformationAddDeadBreak::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
// First, we check that a constant with the same value as
|
||||
// |break_condition_value| is present.
|
||||
opt::analysis::Bool bool_type;
|
||||
@ -202,7 +207,7 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
|
||||
return false;
|
||||
}
|
||||
opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
|
||||
message.break_condition_value());
|
||||
message_.break_condition_value());
|
||||
if (!context->get_constant_mgr()->FindConstant(&bool_constant)) {
|
||||
// The required constant is not present, so the transformation cannot be
|
||||
// applied.
|
||||
@ -210,11 +215,11 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
|
||||
}
|
||||
|
||||
// Check that |from_block| and |to_block| really are block ids
|
||||
BasicBlock* bb_from = MaybeFindBlock(context, message.from_block());
|
||||
opt::BasicBlock* bb_from = MaybeFindBlock(context, message_.from_block());
|
||||
if (bb_from == nullptr) {
|
||||
return false;
|
||||
}
|
||||
BasicBlock* bb_to = MaybeFindBlock(context, message.to_block());
|
||||
opt::BasicBlock* bb_to = MaybeFindBlock(context, message_.to_block());
|
||||
if (bb_to == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -229,36 +234,36 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
|
||||
assert(bb_from != nullptr &&
|
||||
"We should have found a block if this line of code is reached.");
|
||||
assert(
|
||||
bb_from->id() == message.from_block() &&
|
||||
bb_from->id() == message_.from_block() &&
|
||||
"The id of the block we found should match the source id for the break.");
|
||||
assert(bb_to != nullptr &&
|
||||
"We should have found a block if this line of code is reached.");
|
||||
assert(
|
||||
bb_to->id() == message.to_block() &&
|
||||
bb_to->id() == message_.to_block() &&
|
||||
"The id of the block we found should match the target id for the break.");
|
||||
|
||||
// Check whether the data passed to extend OpPhi instructions is appropriate.
|
||||
if (!PhiIdsOk(message, context, bb_from, bb_to)) {
|
||||
if (!PhiIdsOk(context, bb_from, bb_to)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally, check that adding the break would respect the rules of structured
|
||||
// control flow.
|
||||
return AddingBreakRespectsStructuredControlFlow(message, context, bb_from);
|
||||
return AddingBreakRespectsStructuredControlFlow(context, bb_from);
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddDeadBreak& message,
|
||||
IRContext* context, FactManager* /*unused*/) {
|
||||
void TransformationAddDeadBreak::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
// Get the id of the boolean constant to be used as the break condition.
|
||||
opt::analysis::Bool bool_type;
|
||||
opt::analysis::BoolConstant bool_constant(
|
||||
context->get_type_mgr()->GetRegisteredType(&bool_type)->AsBool(),
|
||||
message.break_condition_value());
|
||||
message_.break_condition_value());
|
||||
uint32_t bool_id = context->get_constant_mgr()->FindDeclaredConstant(
|
||||
&bool_constant, context->get_type_mgr()->GetId(&bool_type));
|
||||
|
||||
auto bb_from = context->cfg()->block(message.from_block());
|
||||
auto bb_to = context->cfg()->block(message.to_block());
|
||||
auto bb_from = context->cfg()->block(message_.from_block());
|
||||
auto bb_to = context->cfg()->block(message_.to_block());
|
||||
const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to);
|
||||
auto successor = bb_from->terminator()->GetSingleWordInOperand(0);
|
||||
assert(bb_from->terminator()->opcode() == SpvOpBranch &&
|
||||
@ -272,9 +277,9 @@ void Apply(const protobufs::TransformationAddDeadBreak& message,
|
||||
bb_from->terminator()->SetInOperands(
|
||||
{{SPV_OPERAND_TYPE_ID, {bool_id}},
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{message.break_condition_value() ? successor : message.to_block()}},
|
||||
{message_.break_condition_value() ? successor : message_.to_block()}},
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{message.break_condition_value() ? message.to_block() : successor}}});
|
||||
{message_.break_condition_value() ? message_.to_block() : successor}}});
|
||||
|
||||
// Update OpPhi instructions in the target block if this break adds a
|
||||
// previously non-existent edge from source to target.
|
||||
@ -284,33 +289,25 @@ void Apply(const protobufs::TransformationAddDeadBreak& message,
|
||||
if (inst.opcode() != SpvOpPhi) {
|
||||
break;
|
||||
}
|
||||
assert(phi_index < static_cast<uint32_t>(message.phi_id().size()) &&
|
||||
assert(phi_index < static_cast<uint32_t>(message_.phi_id().size()) &&
|
||||
"There should be exactly one phi id per OpPhi instruction.");
|
||||
inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.phi_id()[phi_index]}});
|
||||
inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.from_block()}});
|
||||
inst.AddOperand({SPV_OPERAND_TYPE_ID, {message_.phi_id()[phi_index]}});
|
||||
inst.AddOperand({SPV_OPERAND_TYPE_ID, {message_.from_block()}});
|
||||
phi_index++;
|
||||
}
|
||||
assert(phi_index == static_cast<uint32_t>(message.phi_id().size()) &&
|
||||
assert(phi_index == static_cast<uint32_t>(message_.phi_id().size()) &&
|
||||
"There should be exactly one phi id per OpPhi instruction.");
|
||||
}
|
||||
|
||||
// Invalidate all analyses
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak(
|
||||
uint32_t from_block, uint32_t to_block, bool break_condition_value,
|
||||
std::vector<uint32_t> phi_id) {
|
||||
protobufs::TransformationAddDeadBreak result;
|
||||
result.set_from_block(from_block);
|
||||
result.set_to_block(to_block);
|
||||
result.set_break_condition_value(break_condition_value);
|
||||
for (auto id : phi_id) {
|
||||
result.add_phi_id(id);
|
||||
}
|
||||
protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_dead_break() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -19,42 +19,70 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.from_block| must be the id of a block a in the given module.
|
||||
// - |message.to_block| must be the id of a block b in the given module.
|
||||
// - if |message.break_condition_value| holds (does not hold) then
|
||||
// OpConstantTrue (OpConstantFalse) must be present in the module
|
||||
// - |message.phi_ids| must be a list of ids that are all available at
|
||||
// |message.from_block|
|
||||
// - a and b must be in the same function.
|
||||
// - b must be a merge block.
|
||||
// - a must end with an unconditional branch to some block c.
|
||||
// - replacing this branch with a conditional branch to b or c, with
|
||||
// the boolean constant associated with |message.break_condition_value| as
|
||||
// the condition, and the ids in |message.phi_ids| used to extend
|
||||
// any OpPhi instructions at b as a result of the edge from a, must
|
||||
// maintain validity of the module.
|
||||
bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddDeadBreak : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddDeadBreak(
|
||||
const protobufs::TransformationAddDeadBreak& message);
|
||||
|
||||
// Replaces the terminator of a with a conditional branch to b or c.
|
||||
// The boolean constant associated with |message.break_condition_value| is used
|
||||
// as the condition, and the order of b and c is arranged such that control is
|
||||
// guaranteed to jump to c.
|
||||
void Apply(const protobufs::TransformationAddDeadBreak& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddDeadBreak(uint32_t from_block, uint32_t to_block,
|
||||
bool break_condition_value,
|
||||
std::vector<uint32_t> phi_id);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak(
|
||||
uint32_t from_block, uint32_t to_block, bool break_condition_value,
|
||||
std::vector<uint32_t> phi_ids);
|
||||
// - |message.from_block| must be the id of a block a in the given module.
|
||||
// - |message.to_block| must be the id of a block b in the given module.
|
||||
// - if |message.break_condition_value| holds (does not hold) then
|
||||
// OpConstantTrue (OpConstantFalse) must be present in the module
|
||||
// - |message.phi_ids| must be a list of ids that are all available at
|
||||
// |message.from_block|
|
||||
// - a and b must be in the same function.
|
||||
// - b must be a merge block.
|
||||
// - a must end with an unconditional branch to some block c.
|
||||
// - replacing this branch with a conditional branch to b or c, with
|
||||
// the boolean constant associated with |message.break_condition_value| as
|
||||
// the condition, and the ids in |message.phi_ids| used to extend
|
||||
// any OpPhi instructions at b as a result of the edge from a, must
|
||||
// maintain validity of the module.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Replaces the terminator of a with a conditional branch to b or c.
|
||||
// The boolean constant associated with |message.break_condition_value| is
|
||||
// used as the condition, and the order of b and c is arranged such that
|
||||
// control is guaranteed to jump to c.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
// Return the block with id |maybe_block_id| if it exists, and nullptr
|
||||
// otherwise.
|
||||
opt::BasicBlock* MaybeFindBlock(opt::IRContext* context,
|
||||
uint32_t maybe_block_id) const;
|
||||
|
||||
// Returns true if and only if the phi ids associated with |message_| are
|
||||
// sufficient to allow an edge from |bb_from| to |bb_to| to be added.
|
||||
bool PhiIdsOk(opt::IRContext* context, opt::BasicBlock* bb_from,
|
||||
opt::BasicBlock* bb_to) const;
|
||||
|
||||
// Returns true if and only if |message_.from_block| is in the continue
|
||||
// construct of a loop headed at |maybe_loop_header|.
|
||||
bool FromBlockIsInLoopContinueConstruct(opt::IRContext* context,
|
||||
uint32_t maybe_loop_header) const;
|
||||
|
||||
// Returns true if and only if adding an edge from |bb_from| to
|
||||
// |message_.to_block| respects structured control flow.
|
||||
bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* context,
|
||||
opt::BasicBlock* bb_from) const;
|
||||
|
||||
protobufs::TransformationAddDeadBreak message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,15 +18,20 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddTypeBoolean::TransformationAddTypeBoolean(
|
||||
const spvtools::fuzz::protobufs::TransformationAddTypeBoolean& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
}
|
||||
|
||||
bool TransformationAddTypeBoolean::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -35,24 +40,22 @@ bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
|
||||
return context->get_type_mgr()->GetId(&bool_type) == 0;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddTypeBoolean& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationAddTypeBoolean::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
opt::Instruction::OperandList empty_operands;
|
||||
context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpTypeBool, 0, message.fresh_id(), empty_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean(
|
||||
uint32_t fresh_id) {
|
||||
protobufs::TransformationAddTypeBoolean result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_type_boolean() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,26 +17,33 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module.
|
||||
// - The module must not yet declare OpTypeBoolean
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddTypeBoolean : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddTypeBoolean(
|
||||
const protobufs::TransformationAddTypeBoolean& message);
|
||||
|
||||
// Adds OpTypeBoolean with |message.fresh_id| as result id.
|
||||
void Apply(const protobufs::TransformationAddTypeBoolean& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
explicit TransformationAddTypeBoolean(uint32_t fresh_id);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean(
|
||||
uint32_t fresh_id);
|
||||
// - |message_.fresh_id| must not be used by the module.
|
||||
// - The module must not yet declare OpTypeBoolean
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds OpTypeBoolean with |message_.fresh_id| as result id.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddTypeBoolean message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,44 +18,48 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddTypeFloat::TransformationAddTypeFloat(uint32_t fresh_id,
|
||||
uint32_t width) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_width(width);
|
||||
}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeFloat& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
TransformationAddTypeFloat::TransformationAddTypeFloat(
|
||||
const spvtools::fuzz::protobufs::TransformationAddTypeFloat& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool TransformationAddTypeFloat::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Applicable if there is no float type with this width already declared in
|
||||
// the module.
|
||||
opt::analysis::Float float_type(message.width());
|
||||
opt::analysis::Float float_type(message_.width());
|
||||
return context->get_type_mgr()->GetId(&float_type) == 0;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddTypeFloat& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationAddTypeFloat::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
opt::Instruction::OperandList width = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}}};
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}};
|
||||
context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpTypeFloat, 0, message.fresh_id(), width));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
context, SpvOpTypeFloat, 0, message_.fresh_id(), width));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat(
|
||||
uint32_t fresh_id, uint32_t width) {
|
||||
protobufs::TransformationAddTypeFloat result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_width(width);
|
||||
protobufs::Transformation TransformationAddTypeFloat::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_type_float() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,27 +17,34 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module
|
||||
// - The module must not contain an OpTypeFloat instruction with width
|
||||
// |message.width|
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeFloat& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddTypeFloat : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddTypeFloat(
|
||||
const protobufs::TransformationAddTypeFloat& message);
|
||||
|
||||
// Adds an OpTypeFloat instruction to the module with the given width
|
||||
void Apply(const protobufs::TransformationAddTypeFloat& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddTypeFloat(uint32_t fresh_id, uint32_t width);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat(
|
||||
uint32_t fresh_id, uint32_t width);
|
||||
// - |message_.fresh_id| must not be used by the module
|
||||
// - The module must not contain an OpTypeFloat instruction with width
|
||||
// |message_.width|
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds an OpTypeFloat instruction to the module with the given width
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddTypeFloat message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,46 +18,51 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddTypeInt::TransformationAddTypeInt(
|
||||
const spvtools::fuzz::protobufs::TransformationAddTypeInt& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeInt& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
TransformationAddTypeInt::TransformationAddTypeInt(uint32_t fresh_id,
|
||||
uint32_t width,
|
||||
bool is_signed) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_width(width);
|
||||
message_.set_is_signed(is_signed);
|
||||
}
|
||||
|
||||
bool TransformationAddTypeInt::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Applicable if there is no int type with this width and signedness already
|
||||
// declared in the module.
|
||||
opt::analysis::Integer int_type(message.width(), message.is_signed());
|
||||
opt::analysis::Integer int_type(message_.width(), message_.is_signed());
|
||||
return context->get_type_mgr()->GetId(&int_type) == 0;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddTypeInt& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationAddTypeInt::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
opt::Instruction::OperandList in_operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.is_signed() ? 1u : 0u}}};
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.is_signed() ? 1u : 0u}}};
|
||||
context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpTypeInt, 0, message.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
context, SpvOpTypeInt, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt(
|
||||
uint32_t fresh_id, uint32_t width, bool is_signed) {
|
||||
protobufs::TransformationAddTypeInt result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_width(width);
|
||||
result.set_is_signed(is_signed);
|
||||
protobufs::Transformation TransformationAddTypeInt::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_type_int() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,28 +17,35 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module
|
||||
// - The module must not contain an OpTypeInt instruction with width
|
||||
// |message.width| and signedness |message.is_signed|
|
||||
bool IsApplicable(const protobufs::TransformationAddTypeInt& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddTypeInt : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddTypeInt(
|
||||
const protobufs::TransformationAddTypeInt& message);
|
||||
|
||||
// Adds an OpTypeInt instruction to the module with the given width and
|
||||
// signedness.
|
||||
void Apply(const protobufs::TransformationAddTypeInt& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, bool is_signed);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt(
|
||||
uint32_t fresh_id, uint32_t width, bool is_signed);
|
||||
// - |message_.fresh_id| must not be used by the module
|
||||
// - The module must not contain an OpTypeInt instruction with width
|
||||
// |message_.width| and signedness |message.is_signed|
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds an OpTypeInt instruction to the module with the given width and
|
||||
// signedness.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddTypeInt message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,44 +18,48 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::IRContext;
|
||||
TransformationAddTypePointer::TransformationAddTypePointer(
|
||||
const spvtools::fuzz::protobufs::TransformationAddTypePointer& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
|
||||
IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) {
|
||||
TransformationAddTypePointer::TransformationAddTypePointer(
|
||||
uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_storage_class(storage_class);
|
||||
message_.set_base_type_id(base_type_id);
|
||||
}
|
||||
|
||||
bool TransformationAddTypePointer::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
// The id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
// The base type must be known.
|
||||
return context->get_type_mgr()->GetType(message.base_type_id()) != nullptr;
|
||||
return context->get_type_mgr()->GetType(message_.base_type_id()) != nullptr;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationAddTypePointer& message,
|
||||
IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationAddTypePointer::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
// Add the pointer type.
|
||||
opt::Instruction::OperandList in_operands = {
|
||||
{SPV_OPERAND_TYPE_STORAGE_CLASS, {message.storage_class()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message.base_type_id()}}};
|
||||
{SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}};
|
||||
context->module()->AddType(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpTypePointer, 0, message.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
// We have added an instruction to the module, so need to be careful about the
|
||||
// validity of existing analyses.
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
|
||||
uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
|
||||
protobufs::TransformationAddTypePointer result;
|
||||
result.set_fresh_id(fresh_id);
|
||||
result.set_storage_class(storage_class);
|
||||
result.set_base_type_id(base_type_id);
|
||||
protobufs::Transformation TransformationAddTypePointer::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_add_type_pointer() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,27 +17,36 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id| must not be used by the module
|
||||
// - |message.base_type_id| must be the result id of an OpType[...] instruction
|
||||
bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationAddTypePointer : public Transformation {
|
||||
public:
|
||||
explicit TransformationAddTypePointer(
|
||||
const protobufs::TransformationAddTypePointer& message);
|
||||
|
||||
// Adds an OpTypePointer instruction with the given storage class and base type
|
||||
// to the module.
|
||||
void Apply(const protobufs::TransformationAddTypePointer& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class,
|
||||
uint32_t base_type_id);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
|
||||
uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id);
|
||||
// - |message_.fresh_id| must not be used by the module
|
||||
// - |message_.base_type_id| must be the result id of an OpType[...]
|
||||
// instruction
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds an OpTypePointer instruction with the given storage class and base
|
||||
// type to the module.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationAddTypePointer message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -18,19 +18,23 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::BasicBlock;
|
||||
using opt::IRContext;
|
||||
TransformationMoveBlockDown::TransformationMoveBlockDown(
|
||||
const spvtools::fuzz::protobufs::TransformationMoveBlockDown& message)
|
||||
: message_(message) {}
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
|
||||
IRContext* context, const FactManager& /*unused*/) {
|
||||
TransformationMoveBlockDown::TransformationMoveBlockDown(uint32_t id) {
|
||||
message_.set_block_id(id);
|
||||
}
|
||||
|
||||
bool TransformationMoveBlockDown::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
// Go through every block in every function, looking for a block whose id
|
||||
// matches that of the block we want to consider moving down.
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto block_it = function.begin(); block_it != function.end();
|
||||
++block_it) {
|
||||
if (block_it->id() == message.block_id()) {
|
||||
if (block_it->id() == message_.block_id()) {
|
||||
// We have found a match.
|
||||
if (block_it == function.begin()) {
|
||||
// The block is the first one appearing in the function. We are not
|
||||
@ -38,7 +42,12 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
|
||||
return false;
|
||||
}
|
||||
// Record the block we would like to consider moving down.
|
||||
BasicBlock* block_matching_id = &*block_it;
|
||||
opt::BasicBlock* block_matching_id = &*block_it;
|
||||
if (!context->GetDominatorAnalysis(&function)->IsReachable(
|
||||
block_matching_id)) {
|
||||
// The block is not reachable. We are not allowed to move it down.
|
||||
return false;
|
||||
}
|
||||
// Now see whether there is some block following that block in program
|
||||
// order.
|
||||
++block_it;
|
||||
@ -48,7 +57,7 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
|
||||
// apply.
|
||||
return false;
|
||||
}
|
||||
BasicBlock* next_block_in_program_order = &*block_it;
|
||||
opt::BasicBlock* next_block_in_program_order = &*block_it;
|
||||
// We can move the block of interest down if and only if it does not
|
||||
// dominate the block that comes next.
|
||||
return !context->GetDominatorAnalysis(&function)->Dominates(
|
||||
@ -62,26 +71,26 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
|
||||
return false;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationMoveBlockDown& message,
|
||||
IRContext* context, FactManager* /*unused*/) {
|
||||
void TransformationMoveBlockDown::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
// Go through every block in every function, looking for a block whose id
|
||||
// matches that of the block we want to move down.
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto block_it = function.begin(); block_it != function.end();
|
||||
++block_it) {
|
||||
if (block_it->id() == message.block_id()) {
|
||||
if (block_it->id() == message_.block_id()) {
|
||||
++block_it;
|
||||
assert(block_it != function.end() &&
|
||||
"To be able to move a block down, it needs to have a "
|
||||
"program-order successor.");
|
||||
function.MoveBasicBlockToAfter(message.block_id(), &*block_it);
|
||||
function.MoveBasicBlockToAfter(message_.block_id(), &*block_it);
|
||||
// It is prudent to invalidate analyses after changing block ordering in
|
||||
// case any of them depend on it, but the ones that definitely do not
|
||||
// depend on ordering can be preserved. These include the following,
|
||||
// which can likely be extended.
|
||||
context->InvalidateAnalysesExceptFor(
|
||||
IRContext::Analysis::kAnalysisDefUse |
|
||||
IRContext::Analysis::kAnalysisDominatorAnalysis);
|
||||
opt::IRContext::Analysis::kAnalysisDefUse |
|
||||
opt::IRContext::Analysis::kAnalysisDominatorAnalysis);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -90,13 +99,11 @@ void Apply(const protobufs::TransformationMoveBlockDown& message,
|
||||
assert(false && "No block was found to move down.");
|
||||
}
|
||||
|
||||
protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown(
|
||||
uint32_t id) {
|
||||
protobufs::TransformationMoveBlockDown result;
|
||||
result.set_block_id(id);
|
||||
protobufs::Transformation TransformationMoveBlockDown::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_move_block_down() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,29 +17,37 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |block_id| must be the id of a block b in the given module.
|
||||
// - b must not be the first nor last block appearing, in program order,
|
||||
// in a function.
|
||||
// - b must not dominate the block that follows it in program order.
|
||||
bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationMoveBlockDown : public Transformation {
|
||||
public:
|
||||
explicit TransformationMoveBlockDown(
|
||||
const protobufs::TransformationMoveBlockDown& message);
|
||||
|
||||
// The block with id |block_id| is moved down; i.e. the program order
|
||||
// between it and the block that follows it is swapped.
|
||||
void Apply(const protobufs::TransformationMoveBlockDown& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
explicit TransformationMoveBlockDown(uint32_t id);
|
||||
|
||||
// Creates a protobuf message to move down the block with id |id|.
|
||||
protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown(
|
||||
uint32_t id);
|
||||
// - |message_.block_id| must be the id of a block b in the given module.
|
||||
// - b must not be the first nor last block appearing, in program order,
|
||||
// in a function.
|
||||
// - b must not dominate the block that follows it in program order.
|
||||
// - b must be reachable.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// The block with id |message_.block_id| is moved down; i.e. the program order
|
||||
// between it and the block that follows it is swapped.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationMoveBlockDown message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -110,19 +109,35 @@ bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop,
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
|
||||
message,
|
||||
opt::IRContext* context, const FactManager& /*unused*/) {
|
||||
TransformationReplaceBooleanConstantWithConstantBinary::
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const spvtools::fuzz::protobufs::
|
||||
TransformationReplaceBooleanConstantWithConstantBinary& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationReplaceBooleanConstantWithConstantBinary::
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
|
||||
uint32_t rhs_id, SpvOp comparison_opcode,
|
||||
uint32_t fresh_id_for_binary_operation) {
|
||||
*message_.mutable_id_use_descriptor() = id_use_descriptor;
|
||||
message_.set_lhs_id(lhs_id);
|
||||
message_.set_rhs_id(rhs_id);
|
||||
message_.set_opcode(comparison_opcode);
|
||||
message_.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation);
|
||||
}
|
||||
|
||||
bool TransformationReplaceBooleanConstantWithConstantBinary::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
// The id for the binary result must be fresh
|
||||
if (!fuzzerutil::IsFreshId(context,
|
||||
message.fresh_id_for_binary_operation())) {
|
||||
message_.fresh_id_for_binary_operation())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The used id must be for a boolean constant
|
||||
auto boolean_constant = context->get_def_use_mgr()->GetDef(
|
||||
message.id_use_descriptor().id_of_interest());
|
||||
message_.id_use_descriptor().id_of_interest());
|
||||
if (!boolean_constant) {
|
||||
return false;
|
||||
}
|
||||
@ -132,7 +147,8 @@ bool IsApplicable(
|
||||
}
|
||||
|
||||
// The left-hand-side id must correspond to a constant instruction.
|
||||
auto lhs_constant_inst = context->get_def_use_mgr()->GetDef(message.lhs_id());
|
||||
auto lhs_constant_inst =
|
||||
context->get_def_use_mgr()->GetDef(message_.lhs_id());
|
||||
if (!lhs_constant_inst) {
|
||||
return false;
|
||||
}
|
||||
@ -141,7 +157,8 @@ bool IsApplicable(
|
||||
}
|
||||
|
||||
// The right-hand-side id must correspond to a constant instruction.
|
||||
auto rhs_constant_inst = context->get_def_use_mgr()->GetDef(message.rhs_id());
|
||||
auto rhs_constant_inst =
|
||||
context->get_def_use_mgr()->GetDef(message_.rhs_id());
|
||||
if (!rhs_constant_inst) {
|
||||
return false;
|
||||
}
|
||||
@ -156,12 +173,12 @@ bool IsApplicable(
|
||||
|
||||
// The expression 'LHS opcode RHS' must evaluate to the boolean constant.
|
||||
auto lhs_constant =
|
||||
context->get_constant_mgr()->FindDeclaredConstant(message.lhs_id());
|
||||
context->get_constant_mgr()->FindDeclaredConstant(message_.lhs_id());
|
||||
auto rhs_constant =
|
||||
context->get_constant_mgr()->FindDeclaredConstant(message.rhs_id());
|
||||
context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id());
|
||||
bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue);
|
||||
|
||||
const SpvOp binary_opcode = static_cast<SpvOp>(message.opcode());
|
||||
const SpvOp binary_opcode = static_cast<SpvOp>(message_.opcode());
|
||||
|
||||
// We consider the floating point, signed and unsigned integer cases
|
||||
// separately. In each case the logic is very similar.
|
||||
@ -220,25 +237,29 @@ bool IsApplicable(
|
||||
}
|
||||
|
||||
// The id use descriptor must identify some instruction
|
||||
return transformation::FindInstruction(message.id_use_descriptor(),
|
||||
return transformation::FindInstruction(message_.id_use_descriptor(),
|
||||
context) != nullptr;
|
||||
}
|
||||
|
||||
opt::Instruction* Apply(
|
||||
const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
|
||||
message,
|
||||
opt::IRContext* context, FactManager* /*unused*/) {
|
||||
void TransformationReplaceBooleanConstantWithConstantBinary::Apply(
|
||||
opt::IRContext* context, FactManager* fact_manager) const {
|
||||
ApplyWithResult(context, fact_manager);
|
||||
}
|
||||
|
||||
opt::Instruction*
|
||||
TransformationReplaceBooleanConstantWithConstantBinary::ApplyWithResult(
|
||||
opt::IRContext* context, FactManager* /*unused*/) const {
|
||||
opt::analysis::Bool bool_type;
|
||||
opt::Instruction::OperandList operands = {
|
||||
{SPV_OPERAND_TYPE_ID, {message.lhs_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message.rhs_id()}}};
|
||||
{SPV_OPERAND_TYPE_ID, {message_.lhs_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.rhs_id()}}};
|
||||
auto binary_instruction = MakeUnique<opt::Instruction>(
|
||||
context, static_cast<SpvOp>(message.opcode()),
|
||||
context, static_cast<SpvOp>(message_.opcode()),
|
||||
context->get_type_mgr()->GetId(&bool_type),
|
||||
message.fresh_id_for_binary_operation(), operands);
|
||||
message_.fresh_id_for_binary_operation(), operands);
|
||||
opt::Instruction* result = binary_instruction.get();
|
||||
auto instruction_containing_constant_use =
|
||||
transformation::FindInstruction(message.id_use_descriptor(), context);
|
||||
transformation::FindInstruction(message_.id_use_descriptor(), context);
|
||||
|
||||
// We want to insert the new instruction before the instruction that contains
|
||||
// the use of the boolean, but we need to go backwards one more instruction if
|
||||
@ -255,28 +276,20 @@ opt::Instruction* Apply(
|
||||
instruction_before_which_to_insert->InsertBefore(
|
||||
std::move(binary_instruction));
|
||||
instruction_containing_constant_use->SetInOperand(
|
||||
message.id_use_descriptor().in_operand_index(),
|
||||
{message.fresh_id_for_binary_operation()});
|
||||
message_.id_use_descriptor().in_operand_index(),
|
||||
{message_.fresh_id_for_binary_operation()});
|
||||
fuzzerutil::UpdateModuleIdBound(context,
|
||||
message.fresh_id_for_binary_operation());
|
||||
message_.fresh_id_for_binary_operation());
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
return result;
|
||||
}
|
||||
|
||||
protobufs::TransformationReplaceBooleanConstantWithConstantBinary
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
|
||||
uint32_t rhs_id, SpvOp comparison_opcode,
|
||||
uint32_t fresh_id_for_binary_operation) {
|
||||
protobufs::TransformationReplaceBooleanConstantWithConstantBinary result;
|
||||
*result.mutable_id_use_descriptor() = id_use_descriptor;
|
||||
result.set_lhs_id(lhs_id);
|
||||
result.set_rhs_id(rhs_id);
|
||||
result.set_opcode(comparison_opcode);
|
||||
result.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation);
|
||||
protobufs::Transformation
|
||||
TransformationReplaceBooleanConstantWithConstantBinary::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_replace_boolean_constant_with_constant_binary() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,42 +17,53 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |message.fresh_id_for_binary_operation| must not already be used by the
|
||||
// module.
|
||||
// - |message.id_use_descriptor| must identify a use of a boolean constant c.
|
||||
// - |message.lhs_id| and |message.rhs_id| must be the ids of constant
|
||||
// instructions with the same type
|
||||
// - |message.opcode| must be suitable for applying to |message.lhs_id| and
|
||||
// |message.rhs_id|, and the result must evaluate to the boolean constant c.
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
|
||||
message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationReplaceBooleanConstantWithConstantBinary
|
||||
: public Transformation {
|
||||
public:
|
||||
explicit TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
|
||||
message);
|
||||
|
||||
// A new instruction is added before the boolean constant usage that computes
|
||||
// the result of applying |message.opcode| to |message.lhs_id| and
|
||||
// |message.rhs_id| is added, with result id
|
||||
// |message.fresh_id_for_binary_operation|. The boolean constant usage is
|
||||
// replaced with this result id.
|
||||
opt::Instruction* Apply(
|
||||
const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
|
||||
message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
|
||||
uint32_t rhs_id, SpvOp comparison_opcode,
|
||||
uint32_t fresh_id_for_binary_operation);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationReplaceBooleanConstantWithConstantBinary
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
|
||||
uint32_t rhs_id, SpvOp comparison_opcode,
|
||||
uint32_t fresh_id_for_binary_operation);
|
||||
// - |message_.fresh_id_for_binary_operation| must not already be used by the
|
||||
// module.
|
||||
// - |message_.id_use_descriptor| must identify a use of a boolean constant c.
|
||||
// - |message_.lhs_id| and |message.rhs_id| must be the ids of constant
|
||||
// instructions with the same type
|
||||
// - |message_.opcode| must be suitable for applying to |message.lhs_id| and
|
||||
// |message_.rhs_id|, and the result must evaluate to the boolean constant
|
||||
// c.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// A new instruction is added before the boolean constant usage that computes
|
||||
// the result of applying |message_.opcode| to |message_.lhs_id| and
|
||||
// |message_.rhs_id| is added, with result id
|
||||
// |message_.fresh_id_for_binary_operation|. The boolean constant usage is
|
||||
// replaced with this result id.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
// The same as Apply, except that the newly-added binary instruction is
|
||||
// returned.
|
||||
opt::Instruction* ApplyWithResult(opt::IRContext* context,
|
||||
FactManager* fact_manager) const;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationReplaceBooleanConstantWithConstantBinary message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -19,18 +19,32 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
namespace {
|
||||
TransformationReplaceConstantWithUniform::
|
||||
TransformationReplaceConstantWithUniform(
|
||||
const spvtools::fuzz::protobufs::
|
||||
TransformationReplaceConstantWithUniform& message)
|
||||
: message_(message) {}
|
||||
|
||||
std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) {
|
||||
TransformationReplaceConstantWithUniform::
|
||||
TransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) {
|
||||
*message_.mutable_id_use_descriptor() = std::move(id_use);
|
||||
*message_.mutable_uniform_descriptor() = std::move(uniform_descriptor);
|
||||
message_.set_fresh_id_for_access_chain(fresh_id_for_access_chain);
|
||||
message_.set_fresh_id_for_load(fresh_id_for_load);
|
||||
}
|
||||
|
||||
std::unique_ptr<opt::Instruction>
|
||||
TransformationReplaceConstantWithUniform::MakeAccessChainInstruction(
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) const {
|
||||
// The input operands for the access chain.
|
||||
opt::Instruction::OperandList operands_for_access_chain;
|
||||
|
||||
opt::Instruction* uniform_variable =
|
||||
FindUniformVariable(message.uniform_descriptor(), context, false);
|
||||
FindUniformVariable(message_.uniform_descriptor(), context, false);
|
||||
|
||||
// The first input operand is the id of the uniform variable.
|
||||
operands_for_access_chain.push_back(
|
||||
@ -44,7 +58,7 @@ std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
|
||||
auto registered_int_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
|
||||
auto int_type_id = context->get_type_mgr()->GetId(&int_type);
|
||||
for (auto index : message.uniform_descriptor().index()) {
|
||||
for (auto index : message_.uniform_descriptor().index()) {
|
||||
opt::analysis::IntConstant int_constant(registered_int_type, {index});
|
||||
auto constant_id = context->get_constant_mgr()->FindDeclaredConstant(
|
||||
&int_constant, int_type_id);
|
||||
@ -62,43 +76,40 @@ std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
|
||||
|
||||
return MakeUnique<opt::Instruction>(
|
||||
context, SpvOpAccessChain, pointer_to_uniform_constant_type_id,
|
||||
message.fresh_id_for_access_chain(), operands_for_access_chain);
|
||||
message_.fresh_id_for_access_chain(), operands_for_access_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<opt::Instruction> MakeLoadInstruction(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) {
|
||||
std::unique_ptr<opt::Instruction>
|
||||
TransformationReplaceConstantWithUniform::MakeLoadInstruction(
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) const {
|
||||
opt::Instruction::OperandList operands_for_load = {
|
||||
{SPV_OPERAND_TYPE_ID, {message.fresh_id_for_access_chain()}}};
|
||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id_for_access_chain()}}};
|
||||
return MakeUnique<opt::Instruction>(context, SpvOpLoad, constant_type_id,
|
||||
message.fresh_id_for_load(),
|
||||
message_.fresh_id_for_load(),
|
||||
operands_for_load);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
bool TransformationReplaceConstantWithUniform::IsApplicable(
|
||||
spvtools::opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& fact_manager) {
|
||||
const spvtools::fuzz::FactManager& fact_manager) const {
|
||||
// The following is really an invariant of the transformation rather than
|
||||
// merely a requirement of the precondition. We check it here since we cannot
|
||||
// check it in the message constructor.
|
||||
assert(message.fresh_id_for_access_chain() != message.fresh_id_for_load() &&
|
||||
// check it in the message_ constructor.
|
||||
assert(message_.fresh_id_for_access_chain() != message_.fresh_id_for_load() &&
|
||||
"Fresh ids for access chain and load result cannot be the same.");
|
||||
|
||||
// The ids for the access chain and load instructions must both be fresh.
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_access_chain())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_access_chain())) {
|
||||
return false;
|
||||
}
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_load())) {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_load())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The id specified in the id use descriptor must be that of a declared scalar
|
||||
// constant.
|
||||
auto declared_constant = context->get_constant_mgr()->FindDeclaredConstant(
|
||||
message.id_use_descriptor().id_of_interest());
|
||||
message_.id_use_descriptor().id_of_interest());
|
||||
if (!declared_constant) {
|
||||
return false;
|
||||
}
|
||||
@ -110,7 +121,7 @@ bool IsApplicable(
|
||||
// by the uniform buffer element descriptor will hold a scalar value.
|
||||
auto constant_id_associated_with_uniform =
|
||||
fact_manager.GetConstantFromUniformDescriptor(
|
||||
context, message.uniform_descriptor());
|
||||
context, message_.uniform_descriptor());
|
||||
if (!constant_id_associated_with_uniform) {
|
||||
return false;
|
||||
}
|
||||
@ -138,7 +149,7 @@ bool IsApplicable(
|
||||
// The id use descriptor must identify some instruction with respect to the
|
||||
// module.
|
||||
auto instruction_using_constant =
|
||||
transformation::FindInstruction(message.id_use_descriptor(), context);
|
||||
transformation::FindInstruction(message_.id_use_descriptor(), context);
|
||||
if (!instruction_using_constant) {
|
||||
return false;
|
||||
}
|
||||
@ -161,7 +172,7 @@ bool IsApplicable(
|
||||
auto registered_int_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
|
||||
auto int_type_id = context->get_type_mgr()->GetId(&int_type);
|
||||
for (auto index : message.uniform_descriptor().index()) {
|
||||
for (auto index : message_.uniform_descriptor().index()) {
|
||||
opt::analysis::IntConstant int_constant(registered_int_type, {index});
|
||||
if (!context->get_constant_mgr()->FindDeclaredConstant(&int_constant,
|
||||
int_type_id)) {
|
||||
@ -172,59 +183,53 @@ bool IsApplicable(
|
||||
return true;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
spvtools::opt::IRContext* context,
|
||||
spvtools::fuzz::FactManager* /*unused*/) {
|
||||
void TransformationReplaceConstantWithUniform::Apply(
|
||||
spvtools::opt::IRContext* context,
|
||||
spvtools::fuzz::FactManager* /*unused*/) const {
|
||||
// Get the instruction that contains the id use we wish to replace.
|
||||
auto instruction_containing_constant_use =
|
||||
transformation::FindInstruction(message.id_use_descriptor(), context);
|
||||
transformation::FindInstruction(message_.id_use_descriptor(), context);
|
||||
assert(instruction_containing_constant_use &&
|
||||
"Precondition requires that the id use can be found.");
|
||||
assert(instruction_containing_constant_use->GetSingleWordInOperand(
|
||||
message.id_use_descriptor().in_operand_index()) ==
|
||||
message.id_use_descriptor().id_of_interest() &&
|
||||
message_.id_use_descriptor().in_operand_index()) ==
|
||||
message_.id_use_descriptor().id_of_interest() &&
|
||||
"Does not appear to be a usage of the desired id.");
|
||||
|
||||
// The id of the type for the constant whose use we wish to replace.
|
||||
auto constant_type_id =
|
||||
context->get_def_use_mgr()
|
||||
->GetDef(message.id_use_descriptor().id_of_interest())
|
||||
->GetDef(message_.id_use_descriptor().id_of_interest())
|
||||
->type_id();
|
||||
|
||||
// Add an access chain instruction to target the uniform element.
|
||||
instruction_containing_constant_use->InsertBefore(
|
||||
MakeAccessChainInstruction(message, context, constant_type_id));
|
||||
MakeAccessChainInstruction(context, constant_type_id));
|
||||
|
||||
// Add a load from this access chain.
|
||||
instruction_containing_constant_use->InsertBefore(
|
||||
MakeLoadInstruction(message, context, constant_type_id));
|
||||
MakeLoadInstruction(context, constant_type_id));
|
||||
|
||||
// Adjust the instruction containing the usage of the constant so that this
|
||||
// usage refers instead to the result of the load.
|
||||
instruction_containing_constant_use->SetInOperand(
|
||||
message.id_use_descriptor().in_operand_index(),
|
||||
{message.fresh_id_for_load()});
|
||||
message_.id_use_descriptor().in_operand_index(),
|
||||
{message_.fresh_id_for_load()});
|
||||
|
||||
// Update the module id bound to reflect the new instructions.
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_load());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_access_chain());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id_for_load());
|
||||
fuzzerutil::UpdateModuleIdBound(context,
|
||||
message_.fresh_id_for_access_chain());
|
||||
|
||||
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::TransformationReplaceConstantWithUniform
|
||||
MakeTransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) {
|
||||
protobufs::TransformationReplaceConstantWithUniform result;
|
||||
*result.mutable_id_use_descriptor() = std::move(id_use);
|
||||
*result.mutable_uniform_descriptor() = std::move(uniform_descriptor);
|
||||
result.set_fresh_id_for_access_chain(fresh_id_for_access_chain);
|
||||
result.set_fresh_id_for_load(fresh_id_for_load);
|
||||
protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage()
|
||||
const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_replace_constant_with_uniform() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -20,53 +20,71 @@
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/id_use_descriptor.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |fresh_id_for_access_chain| and |fresh_id_for_load| must be distinct fresh
|
||||
// ids.
|
||||
// - |uniform_descriptor| specifies a result id and a list of integer literal
|
||||
// indices.
|
||||
// As an example, suppose |uniform_descriptor| is (18, [0, 1, 0])
|
||||
// It is required that:
|
||||
// - the result id (18 in our example) is the id of some uniform variable
|
||||
// - the module contains an integer constant instruction corresponding to
|
||||
// each of the literal indices; in our example there must thus be
|
||||
// OpConstant instructions %A and %B say for each of 0 and 1
|
||||
// - it is legitimate to index into the uniform variable using the
|
||||
// sequence of indices; in our example this means indexing into %18 using
|
||||
// the sequence %A %B %A
|
||||
// - the module contains a uniform pointer type corresponding to the type
|
||||
// of the uniform data element obtained by following these indices
|
||||
// - |id_use_descriptor| identifies the use of some id %C. It is required that:
|
||||
// - this use does indeed exist in the module
|
||||
// - %C is an OpConstant
|
||||
// - According to the fact manager, the uniform data element specified by
|
||||
// |uniform_descriptor| holds a value with the same type and value as %C
|
||||
bool IsApplicable(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationReplaceConstantWithUniform : public Transformation {
|
||||
public:
|
||||
explicit TransformationReplaceConstantWithUniform(
|
||||
const protobufs::TransformationReplaceConstantWithUniform& message);
|
||||
|
||||
// - Introduces two new instructions:
|
||||
// - An access chain targeting the uniform data element specified by
|
||||
// |uniform_descriptor|, with result id |fresh_id_for_access_chain|
|
||||
// - A load from this access chain, with id |fresh_id_for_load|
|
||||
// - Replaces the id use specified by |id_use_descriptor| with
|
||||
// |fresh_id_for_load|
|
||||
void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load);
|
||||
|
||||
// Helper factory to create a transformation message.
|
||||
protobufs::TransformationReplaceConstantWithUniform
|
||||
MakeTransformationReplaceConstantWithUniform(
|
||||
protobufs::IdUseDescriptor id_use,
|
||||
protobufs::UniformBufferElementDescriptor uniform_descriptor,
|
||||
uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load);
|
||||
// - |message_.fresh_id_for_access_chain| and |message_.fresh_id_for_load|
|
||||
// must be distinct fresh ids.
|
||||
// - |message_.uniform_descriptor| specifies a result id and a list of integer
|
||||
// literal indices.
|
||||
// As an example, suppose |message_.uniform_descriptor| is (18, [0, 1, 0])
|
||||
// It is required that:
|
||||
// - the result id (18 in our example) is the id of some uniform variable
|
||||
// - the module contains an integer constant instruction corresponding to
|
||||
// each of the literal indices; in our example there must thus be
|
||||
// OpConstant instructions %A and %B say for each of 0 and 1
|
||||
// - it is legitimate to index into the uniform variable using the
|
||||
// sequence of indices; in our example this means indexing into %18
|
||||
// using the sequence %A %B %A
|
||||
// - the module contains a uniform pointer type corresponding to the type
|
||||
// of the uniform data element obtained by following these indices
|
||||
// - |message_.id_use_descriptor| identifies the use of some id %C. It is
|
||||
// required that:
|
||||
// - this use does indeed exist in the module
|
||||
// - %C is an OpConstant
|
||||
// - According to the fact manager, the uniform data element specified by
|
||||
// |message_.uniform_descriptor| holds a value with the same type and
|
||||
// value as %C
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// - Introduces two new instructions:
|
||||
// - An access chain targeting the uniform data element specified by
|
||||
// |message_.uniform_descriptor|, with result id
|
||||
// |message_.fresh_id_for_access_chain|
|
||||
// - A load from this access chain, with id |message_.fresh_id_for_load|
|
||||
// - Replaces the id use specified by |message_.id_use_descriptor| with
|
||||
// |message_.fresh_id_for_load|
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
// Helper method to create an access chain for the uniform element associated
|
||||
// with the transformation.
|
||||
std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) const;
|
||||
|
||||
// Helper to create a load instruction.
|
||||
std::unique_ptr<opt::Instruction> MakeLoadInstruction(
|
||||
spvtools::opt::IRContext* context, uint32_t constant_type_id) const;
|
||||
|
||||
protobufs::TransformationReplaceConstantWithUniform message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -21,32 +21,31 @@
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
using opt::BasicBlock;
|
||||
using opt::IRContext;
|
||||
using opt::Instruction;
|
||||
using opt::Operand;
|
||||
TransformationSplitBlock::TransformationSplitBlock(
|
||||
const spvtools::fuzz::protobufs::TransformationSplitBlock& message)
|
||||
: message_(message) {}
|
||||
|
||||
namespace {
|
||||
TransformationSplitBlock::TransformationSplitBlock(uint32_t result_id,
|
||||
uint32_t offset,
|
||||
uint32_t fresh_id) {
|
||||
message_.set_result_id(result_id);
|
||||
message_.set_offset(offset);
|
||||
message_.set_fresh_id(fresh_id);
|
||||
}
|
||||
|
||||
// Returns:
|
||||
// - (true, block->end()) if the relevant instruction is in this block
|
||||
// but inapplicable
|
||||
// - (true, it) if 'it' is an iterator for the relevant instruction
|
||||
// - (false, _) otherwise.
|
||||
std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
|
||||
const protobufs::TransformationSplitBlock& message, BasicBlock* block) {
|
||||
std::pair<bool, opt::BasicBlock::iterator>
|
||||
TransformationSplitBlock::FindInstToSplitBefore(opt::BasicBlock* block) const {
|
||||
// There are three possibilities:
|
||||
// (1) the transformation wants to split at some offset from the block's
|
||||
// label.
|
||||
// (2) the transformation wants to split at some offset from a
|
||||
// non-label instruction inside the block.
|
||||
// (3) the split associated with this transformation has nothing to do with
|
||||
// (3) the split assocaiated with this transformation has nothing to do with
|
||||
// this block
|
||||
if (message.result_id() == block->id()) {
|
||||
if (message_.result_id() == block->id()) {
|
||||
// Case (1).
|
||||
if (message.offset() == 0) {
|
||||
if (message_.offset() == 0) {
|
||||
// The offset is not allowed to be 0: this would mean splitting before the
|
||||
// block's label.
|
||||
// By returning (true, block->end()), we indicate that we did find the
|
||||
@ -57,16 +56,17 @@ std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
|
||||
// Conceptually, the first instruction in the block is [label + 1].
|
||||
// We thus start from 1 when applying the offset.
|
||||
auto inst_it = block->begin();
|
||||
for (uint32_t i = 1; i < message.offset() && inst_it != block->end(); i++) {
|
||||
for (uint32_t i = 1; i < message_.offset() && inst_it != block->end();
|
||||
i++) {
|
||||
++inst_it;
|
||||
}
|
||||
// This is either the desired instruction, or the end of the block.
|
||||
return {true, inst_it};
|
||||
}
|
||||
for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) {
|
||||
if (message.result_id() == inst_it->result_id()) {
|
||||
if (message_.result_id() == inst_it->result_id()) {
|
||||
// Case (2): we have found the base instruction; we now apply the offset.
|
||||
for (uint32_t i = 0; i < message.offset() && inst_it != block->end();
|
||||
for (uint32_t i = 0; i < message_.offset() && inst_it != block->end();
|
||||
i++) {
|
||||
++inst_it;
|
||||
}
|
||||
@ -78,18 +78,16 @@ std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
|
||||
return {false, block->end()};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsApplicable(const protobufs::TransformationSplitBlock& message,
|
||||
IRContext* context, const FactManager& /*unused*/) {
|
||||
if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
|
||||
bool TransformationSplitBlock::IsApplicable(
|
||||
opt::IRContext* context, const FactManager& /*unused*/) const {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
// We require the id for the new block to be unused.
|
||||
return false;
|
||||
}
|
||||
// Consider every block in every function.
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto& block : function) {
|
||||
auto maybe_split_before = FindInstToSplitBefore(message, &block);
|
||||
auto maybe_split_before = FindInstToSplitBefore(&block);
|
||||
if (!maybe_split_before.first) {
|
||||
continue;
|
||||
}
|
||||
@ -125,11 +123,11 @@ bool IsApplicable(const protobufs::TransformationSplitBlock& message,
|
||||
return false;
|
||||
}
|
||||
|
||||
void Apply(const protobufs::TransformationSplitBlock& message,
|
||||
IRContext* context, FactManager* /*unused*/) {
|
||||
void TransformationSplitBlock::Apply(opt::IRContext* context,
|
||||
FactManager* /*unused*/) const {
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto& block : function) {
|
||||
auto maybe_split_before = FindInstToSplitBefore(message, &block);
|
||||
auto maybe_split_before = FindInstToSplitBefore(&block);
|
||||
if (!maybe_split_before.first) {
|
||||
continue;
|
||||
}
|
||||
@ -138,20 +136,21 @@ void Apply(const protobufs::TransformationSplitBlock& message,
|
||||
"instruction to split on.");
|
||||
// We need to make sure the module's id bound is large enough to add the
|
||||
// fresh id.
|
||||
fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
// Split the block.
|
||||
auto new_bb = block.SplitBasicBlock(context, message.fresh_id(),
|
||||
auto new_bb = block.SplitBasicBlock(context, message_.fresh_id(),
|
||||
maybe_split_before.second);
|
||||
// The split does not automatically add a branch between the two parts of
|
||||
// the original block, so we add one.
|
||||
block.AddInstruction(MakeUnique<Instruction>(
|
||||
block.AddInstruction(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpBranch, 0, 0,
|
||||
std::initializer_list<Operand>{Operand(
|
||||
spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message.fresh_id()})}));
|
||||
std::initializer_list<opt::Operand>{
|
||||
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{message_.fresh_id()})}));
|
||||
// If we split before OpPhi instructions, we need to update their
|
||||
// predecessor operand so that the block they used to be inside is now the
|
||||
// predecessor.
|
||||
new_bb->ForEachPhiInst([&block](Instruction* phi_inst) {
|
||||
new_bb->ForEachPhiInst([&block](opt::Instruction* phi_inst) {
|
||||
// The following assertion is a sanity check. It is guaranteed to hold
|
||||
// if IsApplicable holds.
|
||||
assert(phi_inst->NumInOperands() == 2 &&
|
||||
@ -160,7 +159,8 @@ void Apply(const protobufs::TransformationSplitBlock& message,
|
||||
phi_inst->SetInOperand(1, {block.id()});
|
||||
});
|
||||
// Invalidate all analyses
|
||||
context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
context->InvalidateAnalysesExceptFor(
|
||||
opt::IRContext::Analysis::kAnalysisNone);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -169,15 +169,11 @@ void Apply(const protobufs::TransformationSplitBlock& message,
|
||||
"transformation.");
|
||||
}
|
||||
|
||||
protobufs::TransformationSplitBlock MakeTransformationSplitBlock(
|
||||
uint32_t result_id, uint32_t offset, uint32_t fresh_id) {
|
||||
protobufs::TransformationSplitBlock result;
|
||||
result.set_result_id(result_id);
|
||||
result.set_offset(offset);
|
||||
result.set_fresh_id(fresh_id);
|
||||
protobufs::Transformation TransformationSplitBlock::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_split_block() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
@ -17,35 +17,52 @@
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace transformation {
|
||||
|
||||
// - |result_id| must be the result id of an instruction 'base' in some
|
||||
// block 'blk'.
|
||||
// - 'blk' must contain an instruction 'inst' located |offset| instructions
|
||||
// after 'inst' (if |offset| = 0 then 'inst' = 'base').
|
||||
// - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards
|
||||
// appear in a new block that 'blk' directly jumps to must be valid.
|
||||
// - |fresh_id| must not be used by the module.
|
||||
bool IsApplicable(const protobufs::TransformationSplitBlock& message,
|
||||
opt::IRContext* context, const FactManager& fact_manager);
|
||||
class TransformationSplitBlock : public Transformation {
|
||||
public:
|
||||
explicit TransformationSplitBlock(
|
||||
const protobufs::TransformationSplitBlock& message);
|
||||
|
||||
// - A new block with label |fresh_id| is inserted right after 'blk' in
|
||||
// program order.
|
||||
// - All instructions of 'blk' from 'inst' onwards are moved into the new
|
||||
// block.
|
||||
// - 'blk' is made to jump unconditionally to the new block.
|
||||
void Apply(const protobufs::TransformationSplitBlock& message,
|
||||
opt::IRContext* context, FactManager* fact_manager);
|
||||
TransformationSplitBlock(uint32_t result_id, uint32_t offset,
|
||||
uint32_t fresh_id);
|
||||
|
||||
// Creates a protobuf message representing a block-splitting transformation.
|
||||
protobufs::TransformationSplitBlock MakeTransformationSplitBlock(
|
||||
uint32_t result_id, uint32_t offset, uint32_t fresh_id);
|
||||
// - |message_.result_id| must be the result id of an instruction 'base' in
|
||||
// some block 'blk'.
|
||||
// - 'blk' must contain an instruction 'inst' located |message_.offset|
|
||||
// instructions after 'inst' (if |message_.offset| = 0 then 'inst' =
|
||||
// 'base').
|
||||
// - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards
|
||||
// appear in a new block that 'blk' directly jumps to must be valid.
|
||||
// - |message_.fresh_id| must not be used by the module.
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// - A new block with label |message_.fresh_id| is inserted right after 'blk'
|
||||
// in program order.
|
||||
// - All instructions of 'blk' from 'inst' onwards are moved into the new
|
||||
// block.
|
||||
// - 'blk' is made to jump unconditionally to the new block.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
// Returns:
|
||||
// - (true, block->end()) if the relevant instruction is in this block
|
||||
// but inapplicable
|
||||
// - (true, it) if 'it' is an iterator for the relevant instruction
|
||||
// - (false, _) otherwise.
|
||||
std::pair<bool, opt::BasicBlock::iterator> FindInstToSplitBefore(
|
||||
opt::BasicBlock* block) const;
|
||||
|
||||
protobufs::TransformationSplitBlock message_;
|
||||
};
|
||||
|
||||
} // namespace transformation
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
|
10
3rdparty/spirv-tools/source/opt/ir_context.cpp
vendored
10
3rdparty/spirv-tools/source/opt/ir_context.cpp
vendored
@ -678,12 +678,18 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
|
||||
case SpvBuiltInVertexIndex:
|
||||
case SpvBuiltInInstanceIndex:
|
||||
case SpvBuiltInPrimitiveId:
|
||||
case SpvBuiltInInvocationId:
|
||||
case SpvBuiltInGlobalInvocationId: {
|
||||
case SpvBuiltInInvocationId: {
|
||||
analysis::Integer uint_ty(32, false);
|
||||
reg_type = type_mgr->GetRegisteredType(&uint_ty);
|
||||
break;
|
||||
}
|
||||
case SpvBuiltInGlobalInvocationId: {
|
||||
analysis::Integer uint_ty(32, false);
|
||||
analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
|
||||
analysis::Vector v3uint_ty(reg_uint_ty, 3);
|
||||
reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false && "unhandled builtin");
|
||||
return 0;
|
||||
|
30
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
30
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
@ -234,6 +234,36 @@ bool spvIsWebGPUEnv(spv_target_env env) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spvIsOpenGLEnv(spv_target_env env) {
|
||||
switch (env) {
|
||||
case SPV_ENV_UNIVERSAL_1_0:
|
||||
case SPV_ENV_VULKAN_1_0:
|
||||
case SPV_ENV_UNIVERSAL_1_1:
|
||||
case SPV_ENV_UNIVERSAL_1_2:
|
||||
case SPV_ENV_UNIVERSAL_1_3:
|
||||
case SPV_ENV_VULKAN_1_1:
|
||||
case SPV_ENV_OPENCL_1_2:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_1_2:
|
||||
case SPV_ENV_OPENCL_2_0:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_0:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_1:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_2:
|
||||
case SPV_ENV_OPENCL_2_1:
|
||||
case SPV_ENV_OPENCL_2_2:
|
||||
case SPV_ENV_WEBGPU_0:
|
||||
case SPV_ENV_UNIVERSAL_1_4:
|
||||
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
|
||||
return false;
|
||||
case SPV_ENV_OPENGL_4_0:
|
||||
case SPV_ENV_OPENGL_4_1:
|
||||
case SPV_ENV_OPENGL_4_2:
|
||||
case SPV_ENV_OPENGL_4_3:
|
||||
case SPV_ENV_OPENGL_4_5:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spvIsVulkanOrWebGPUEnv(spv_target_env env) {
|
||||
return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env);
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ bool spvIsOpenCLEnv(spv_target_env env);
|
||||
// Returns true if |env| is an WEBGPU environment, false otherwise.
|
||||
bool spvIsWebGPUEnv(spv_target_env env);
|
||||
|
||||
// Returns true if |env| is an OPENGL environment, false otherwise.
|
||||
bool spvIsOpenGLEnv(spv_target_env env);
|
||||
|
||||
// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise.
|
||||
bool spvIsVulkanOrWebGPUEnv(spv_target_env env);
|
||||
|
||||
|
@ -910,6 +910,25 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
}
|
||||
}
|
||||
|
||||
if (spvIsOpenGLEnv(vstate.context()->target_env)) {
|
||||
bool has_block = hasDecoration(var_id, SpvDecorationBlock, vstate);
|
||||
bool has_buffer_block =
|
||||
hasDecoration(var_id, SpvDecorationBufferBlock, vstate);
|
||||
if ((uniform && (has_block || has_buffer_block)) ||
|
||||
(storage_buffer && has_block)) {
|
||||
auto entry_points = vstate.EntryPointReferences(var_id);
|
||||
if (!entry_points.empty() &&
|
||||
!hasDecoration(var_id, SpvDecorationBinding, vstate)) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
|
||||
<< (uniform ? "Uniform" : "Storage Buffer") << " id '"
|
||||
<< var_id << "' is missing Binding decoration.\n"
|
||||
<< "From ARB_gl_spirv extension:\n"
|
||||
<< "Uniform and shader storage block variables must "
|
||||
<< "also be decorated with a *Binding*.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool phys_storage_buffer =
|
||||
storageClass == SpvStorageClassPhysicalStorageBufferEXT;
|
||||
if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
|
||||
@ -1440,6 +1459,11 @@ spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(vstate.context()->target_env)) {
|
||||
// Strip the array, if present.
|
||||
if (vstate.GetIdOpcode(type_id) == SpvOpTypeArray) {
|
||||
type_id = vstate.FindDef(type_id)->word(2u);
|
||||
}
|
||||
|
||||
if (!vstate.IsIntScalarOrVectorType(type_id) &&
|
||||
!vstate.IsFloatScalarOrVectorType(type_id)) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
|
@ -45,52 +45,40 @@ TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// True and false can both be added as neither is present.
|
||||
ASSERT_TRUE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddConstantBoolean(7, true),
|
||||
ASSERT_TRUE(TransformationAddConstantBoolean(7, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddConstantBoolean(7, false),
|
||||
ASSERT_TRUE(TransformationAddConstantBoolean(7, false).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
|
||||
// Id 5 is already taken.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddConstantBoolean(5, true),
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(5, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
|
||||
auto add_true = transformation::MakeTransformationAddConstantBoolean(7, true);
|
||||
auto add_false =
|
||||
transformation::MakeTransformationAddConstantBoolean(8, false);
|
||||
auto add_true = TransformationAddConstantBoolean(7, true);
|
||||
auto add_false = TransformationAddConstantBoolean(8, false);
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(add_true, context.get(), fact_manager));
|
||||
transformation::Apply(add_true, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_true.IsApplicable(context.get(), fact_manager));
|
||||
add_true.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Having added true, we cannot add it again with the same id.
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(add_true, context.get(), fact_manager));
|
||||
ASSERT_FALSE(add_true.IsApplicable(context.get(), fact_manager));
|
||||
// But we can add it with a different id.
|
||||
auto add_true_again =
|
||||
transformation::MakeTransformationAddConstantBoolean(100, true);
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_true_again, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_true_again, context.get(), &fact_manager);
|
||||
auto add_true_again = TransformationAddConstantBoolean(100, true);
|
||||
ASSERT_TRUE(add_true_again.IsApplicable(context.get(), fact_manager));
|
||||
add_true_again.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(add_false, context.get(), fact_manager));
|
||||
transformation::Apply(add_false, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_false.IsApplicable(context.get(), fact_manager));
|
||||
add_false.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Having added false, we cannot add it again with the same id.
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(add_false, context.get(), fact_manager));
|
||||
ASSERT_FALSE(add_false.IsApplicable(context.get(), fact_manager));
|
||||
// But we can add it with a different id.
|
||||
auto add_false_again =
|
||||
transformation::MakeTransformationAddConstantBoolean(101, false);
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_false_again, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_false_again, context.get(), &fact_manager);
|
||||
auto add_false_again = TransformationAddConstantBoolean(101, false);
|
||||
ASSERT_TRUE(add_false_again.IsApplicable(context.get(), fact_manager));
|
||||
add_false_again.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
@ -142,11 +130,9 @@ TEST(TransformationAddConstantBooleanTest, NoOpTypeBoolPresent) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Neither true nor false can be added as OpTypeBool is not present.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddConstantBoolean(6, true),
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(6, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddConstantBoolean(6, false),
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(6, false).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
}
|
||||
|
||||
|
@ -67,97 +67,75 @@ TEST(TransformationAddConstantScalarTest, BasicTest) {
|
||||
uint32_t uint_for_float[2];
|
||||
memcpy(uint_for_float, float_values, sizeof(float_values));
|
||||
|
||||
auto add_signed_int_1 =
|
||||
transformation::MakeTransformationAddConstantScalar(100, 6, {1});
|
||||
auto add_signed_int_10 =
|
||||
transformation::MakeTransformationAddConstantScalar(101, 6, {10});
|
||||
auto add_unsigned_int_2 =
|
||||
transformation::MakeTransformationAddConstantScalar(102, 10, {2});
|
||||
auto add_unsigned_int_20 =
|
||||
transformation::MakeTransformationAddConstantScalar(103, 10, {20});
|
||||
auto add_float_3 = transformation::MakeTransformationAddConstantScalar(
|
||||
104, 14, {uint_for_float[0]});
|
||||
auto add_float_30 = transformation::MakeTransformationAddConstantScalar(
|
||||
105, 14, {uint_for_float[1]});
|
||||
auto add_signed_int_1 = TransformationAddConstantScalar(100, 6, {1});
|
||||
auto add_signed_int_10 = TransformationAddConstantScalar(101, 6, {10});
|
||||
auto add_unsigned_int_2 = TransformationAddConstantScalar(102, 10, {2});
|
||||
auto add_unsigned_int_20 = TransformationAddConstantScalar(103, 10, {20});
|
||||
auto add_float_3 =
|
||||
TransformationAddConstantScalar(104, 14, {uint_for_float[0]});
|
||||
auto add_float_30 =
|
||||
TransformationAddConstantScalar(105, 14, {uint_for_float[1]});
|
||||
auto bad_add_float_30_id_already_used =
|
||||
transformation::MakeTransformationAddConstantScalar(104, 14,
|
||||
{uint_for_float[1]});
|
||||
auto bad_id_already_used =
|
||||
transformation::MakeTransformationAddConstantScalar(1, 6, {1});
|
||||
auto bad_no_data =
|
||||
transformation::MakeTransformationAddConstantScalar(100, 6, {});
|
||||
auto bad_too_much_data =
|
||||
transformation::MakeTransformationAddConstantScalar(100, 6, {1, 2});
|
||||
TransformationAddConstantScalar(104, 14, {uint_for_float[1]});
|
||||
auto bad_id_already_used = TransformationAddConstantScalar(1, 6, {1});
|
||||
auto bad_no_data = TransformationAddConstantScalar(100, 6, {});
|
||||
auto bad_too_much_data = TransformationAddConstantScalar(100, 6, {1, 2});
|
||||
auto bad_type_id_does_not_exist =
|
||||
transformation::MakeTransformationAddConstantScalar(108, 2020,
|
||||
{uint_for_float[0]});
|
||||
auto bad_type_id_is_not_a_type =
|
||||
transformation::MakeTransformationAddConstantScalar(109, 9, {0});
|
||||
auto bad_type_id_is_void =
|
||||
transformation::MakeTransformationAddConstantScalar(110, 2, {0});
|
||||
auto bad_type_id_is_pointer =
|
||||
transformation::MakeTransformationAddConstantScalar(111, 11, {0});
|
||||
TransformationAddConstantScalar(108, 2020, {uint_for_float[0]});
|
||||
auto bad_type_id_is_not_a_type = TransformationAddConstantScalar(109, 9, {0});
|
||||
auto bad_type_id_is_void = TransformationAddConstantScalar(110, 2, {0});
|
||||
auto bad_type_id_is_pointer = TransformationAddConstantScalar(111, 11, {0});
|
||||
|
||||
// Id is already in use.
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_id_already_used, context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(bad_id_already_used.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// At least one word of data must be provided.
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(bad_no_data, context.get(), fact_manager));
|
||||
ASSERT_FALSE(bad_no_data.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot give two data words for a 32-bit type.
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_too_much_data, context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(bad_too_much_data.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id does not exist
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is not a type
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_a_type,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_not_a_type.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is void
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_void, context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(bad_type_id_is_void.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is pointer
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_pointer,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_pointer.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_signed_int_1, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_signed_int_1, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_signed_int_1.IsApplicable(context.get(), fact_manager));
|
||||
add_signed_int_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_signed_int_10, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_signed_int_10, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_signed_int_10.IsApplicable(context.get(), fact_manager));
|
||||
add_signed_int_10.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_2, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_unsigned_int_2, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_unsigned_int_2.IsApplicable(context.get(), fact_manager));
|
||||
add_unsigned_int_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_20, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_unsigned_int_20, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_unsigned_int_20.IsApplicable(context.get(), fact_manager));
|
||||
add_unsigned_int_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(add_float_3, context.get(), fact_manager));
|
||||
transformation::Apply(add_float_3, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_float_3.IsApplicable(context.get(), fact_manager));
|
||||
add_float_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(add_float_30, context.get(), fact_manager));
|
||||
transformation::Apply(add_float_30, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_float_30.IsApplicable(context.get(), fact_manager));
|
||||
add_float_30.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_add_float_30_id_already_used,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(bad_add_float_30_id_already_used.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,20 +44,17 @@ TEST(TransformationAddTypeBooleanTest, BasicTest) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddTypeBoolean(1), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationAddTypeBoolean(1).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
auto add_type_bool = transformation::MakeTransformationAddTypeBoolean(100);
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(add_type_bool, context.get(), fact_manager));
|
||||
transformation::Apply(add_type_bool, context.get(), &fact_manager);
|
||||
auto add_type_bool = TransformationAddTypeBoolean(100);
|
||||
ASSERT_TRUE(add_type_bool.IsApplicable(context.get(), fact_manager));
|
||||
add_type_bool.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have this type now.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddTypeBoolean(101), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationAddTypeBoolean(101).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
|
@ -44,21 +44,17 @@ TEST(TransformationAddTypeFloatTest, BasicTest) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddTypeFloat(1, 32), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationAddTypeFloat(1, 32).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
auto add_type_float_32 =
|
||||
transformation::MakeTransformationAddTypeFloat(100, 32);
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_type_float_32, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(add_type_float_32, context.get(), &fact_manager);
|
||||
auto add_type_float_32 = TransformationAddTypeFloat(100, 32);
|
||||
ASSERT_TRUE(add_type_float_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_float_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have this type now.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddTypeFloat(101, 32), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationAddTypeFloat(101, 32).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
|
@ -44,34 +44,29 @@ TEST(TransformationAddTypeIntTest, BasicTest) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationAddTypeInt(1, 32, false), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationAddTypeInt(1, 32, false)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto add_type_signed_int_32 =
|
||||
transformation::MakeTransformationAddTypeInt(100, 32, true);
|
||||
auto add_type_unsigned_int_32 =
|
||||
transformation::MakeTransformationAddTypeInt(101, 32, false);
|
||||
auto add_type_signed_int_32_again =
|
||||
transformation::MakeTransformationAddTypeInt(102, 32, true);
|
||||
auto add_type_signed_int_32 = TransformationAddTypeInt(100, 32, true);
|
||||
auto add_type_unsigned_int_32 = TransformationAddTypeInt(101, 32, false);
|
||||
auto add_type_signed_int_32_again = TransformationAddTypeInt(102, 32, true);
|
||||
auto add_type_unsigned_int_32_again =
|
||||
transformation::MakeTransformationAddTypeInt(103, 32, false);
|
||||
TransformationAddTypeInt(103, 32, false);
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_type_signed_int_32,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(add_type_signed_int_32, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(add_type_signed_int_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_signed_int_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(add_type_unsigned_int_32,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(add_type_unsigned_int_32, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(
|
||||
add_type_unsigned_int_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_unsigned_int_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have these types now.
|
||||
ASSERT_FALSE(transformation::IsApplicable(add_type_signed_int_32_again,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(add_type_unsigned_int_32_again,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
add_type_signed_int_32_again.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
add_type_unsigned_int_32_again.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
|
@ -99,46 +99,35 @@ TEST(TransformationAddTypePointerTest, BasicTest) {
|
||||
FactManager fact_manager;
|
||||
|
||||
auto bad_type_id_does_not_exist =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
100, SpvStorageClassFunction, 101);
|
||||
TransformationAddTypePointer(100, SpvStorageClassFunction, 101);
|
||||
auto bad_type_id_is_not_type =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
100, SpvStorageClassFunction, 23);
|
||||
TransformationAddTypePointer(100, SpvStorageClassFunction, 23);
|
||||
auto bad_result_id_is_not_fresh =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
17, SpvStorageClassFunction, 21);
|
||||
TransformationAddTypePointer(17, SpvStorageClassFunction, 21);
|
||||
|
||||
auto good_new_private_pointer_to_t =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
101, SpvStorageClassPrivate, 7);
|
||||
TransformationAddTypePointer(101, SpvStorageClassPrivate, 7);
|
||||
auto good_new_uniform_pointer_to_t =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
102, SpvStorageClassUniform, 7);
|
||||
TransformationAddTypePointer(102, SpvStorageClassUniform, 7);
|
||||
auto good_another_function_pointer_to_s =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
103, SpvStorageClassFunction, 8);
|
||||
TransformationAddTypePointer(103, SpvStorageClassFunction, 8);
|
||||
auto good_new_uniform_pointer_to_s =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
104, SpvStorageClassUniform, 8);
|
||||
TransformationAddTypePointer(104, SpvStorageClassUniform, 8);
|
||||
auto good_another_private_pointer_to_float =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
105, SpvStorageClassPrivate, 21);
|
||||
TransformationAddTypePointer(105, SpvStorageClassPrivate, 21);
|
||||
auto good_new_private_pointer_to_private_pointer_to_float =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
106, SpvStorageClassPrivate, 105);
|
||||
TransformationAddTypePointer(106, SpvStorageClassPrivate, 105);
|
||||
auto good_new_uniform_pointer_to_vec2 =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
107, SpvStorageClassUniform, 24);
|
||||
TransformationAddTypePointer(107, SpvStorageClassUniform, 24);
|
||||
auto good_new_private_pointer_to_uniform_pointer_to_vec2 =
|
||||
transformation::MakeTransformationAddTypePointer(
|
||||
108, SpvStorageClassPrivate, 107);
|
||||
TransformationAddTypePointer(108, SpvStorageClassPrivate, 107);
|
||||
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_type,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(bad_result_id_is_not_fresh,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_not_type.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_result_id_is_not_fresh.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
for (auto& transformation :
|
||||
{good_new_private_pointer_to_t, good_new_uniform_pointer_to_t,
|
||||
@ -147,9 +136,8 @@ TEST(TransformationAddTypePointerTest, BasicTest) {
|
||||
good_new_private_pointer_to_private_pointer_to_float,
|
||||
good_new_uniform_pointer_to_vec2,
|
||||
good_new_private_pointer_to_uniform_pointer_to_vec2}) {
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(transformation, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
|
@ -54,9 +54,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible1) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = transformation::MakeTransformationMoveBlockDown(11);
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
auto transformation = TransformationMoveBlockDown(11);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
|
||||
@ -92,9 +91,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = transformation::MakeTransformationMoveBlockDown(5);
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
auto transformation = TransformationMoveBlockDown(5);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
|
||||
@ -132,9 +130,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = transformation::MakeTransformationMoveBlockDown(100);
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
auto transformation = TransformationMoveBlockDown(100);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
|
||||
@ -176,81 +173,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = transformation::MakeTransformationMoveBlockDown(12);
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, MovePossible) {
|
||||
// Block 11 can be moved down as it does not dominate block 12 (both are
|
||||
// unreachable).
|
||||
std::string before_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
%11 = OpLabel
|
||||
OpReturn
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
%11 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, before_transformation, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = transformation::MakeTransformationMoveBlockDown(11);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(transformation, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
auto transformation = TransformationMoveBlockDown(12);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
@ -357,17 +281,17 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
// The block ids are: 5 14 20 23 21 25 29 32 30 15
|
||||
// We make a transformation to move each of them down, plus a transformation
|
||||
// to move a non-block, 27, down.
|
||||
auto move_down_5 = transformation::MakeTransformationMoveBlockDown(5);
|
||||
auto move_down_14 = transformation::MakeTransformationMoveBlockDown(14);
|
||||
auto move_down_20 = transformation::MakeTransformationMoveBlockDown(20);
|
||||
auto move_down_23 = transformation::MakeTransformationMoveBlockDown(23);
|
||||
auto move_down_21 = transformation::MakeTransformationMoveBlockDown(21);
|
||||
auto move_down_25 = transformation::MakeTransformationMoveBlockDown(25);
|
||||
auto move_down_29 = transformation::MakeTransformationMoveBlockDown(29);
|
||||
auto move_down_32 = transformation::MakeTransformationMoveBlockDown(32);
|
||||
auto move_down_30 = transformation::MakeTransformationMoveBlockDown(30);
|
||||
auto move_down_15 = transformation::MakeTransformationMoveBlockDown(15);
|
||||
auto move_down_27 = transformation::MakeTransformationMoveBlockDown(27);
|
||||
auto move_down_5 = TransformationMoveBlockDown(5);
|
||||
auto move_down_14 = TransformationMoveBlockDown(14);
|
||||
auto move_down_20 = TransformationMoveBlockDown(20);
|
||||
auto move_down_23 = TransformationMoveBlockDown(23);
|
||||
auto move_down_21 = TransformationMoveBlockDown(21);
|
||||
auto move_down_25 = TransformationMoveBlockDown(25);
|
||||
auto move_down_29 = TransformationMoveBlockDown(29);
|
||||
auto move_down_32 = TransformationMoveBlockDown(32);
|
||||
auto move_down_30 = TransformationMoveBlockDown(30);
|
||||
auto move_down_15 = TransformationMoveBlockDown(15);
|
||||
auto move_down_27 = TransformationMoveBlockDown(27);
|
||||
|
||||
// Dominance is as follows:
|
||||
// 5 dominates everything else
|
||||
@ -382,180 +306,110 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
// 15 dominates nothing
|
||||
|
||||
// Current ordering: 5 14 20 23 21 25 29 32 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Let's bubble 20 all the way down.
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 20 21 25 29 32 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 20 25 29 32 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 20 29 32 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 20 32 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 20 30 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 30 20 15
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_20, context.get(), &fact_manager);
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_bubbling_20_down = R"(
|
||||
@ -631,103 +485,63 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 30 15 20
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_23, context.get(), &fact_manager);
|
||||
move_down_23.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 21 23 25 29 32 30 15 20
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_23, context.get(), &fact_manager);
|
||||
move_down_23.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 21 25 23 29 32 30 15 20
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_21, context.get(), &fact_manager);
|
||||
move_down_21.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 25 21 23 29 32 30 15 20
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
transformation::Apply(move_down_14, context.get(), &fact_manager);
|
||||
move_down_14.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_more_shuffling = R"(
|
||||
@ -803,26 +617,52 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get()));
|
||||
|
||||
// Final ordering: 5 25 14 21 23 29 32 30 15 20
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_5, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_25, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_14, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_21, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_23, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_29, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_32, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_30, context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(move_down_15, context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
transformation::IsApplicable(move_down_20, context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, DoNotMoveUnreachable) {
|
||||
// Block 6 is unreachable, so cannot be moved down.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%10 = OpTypeInt 32 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %10
|
||||
OpBranch %8
|
||||
%8 = OpLabel
|
||||
%9 = OpCopyObject %10 %7
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(6);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -192,16 +192,12 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
std::vector<SpvOp> uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual};
|
||||
|
||||
#define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
|
||||
ASSERT_TRUE(transformation::IsApplicable( \
|
||||
transformation:: \
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID), \
|
||||
context.get(), fact_manager)); \
|
||||
ASSERT_FALSE(transformation::IsApplicable( \
|
||||
transformation:: \
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID), \
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
|
||||
.IsApplicable(context.get(), fact_manager)); \
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID) \
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
#define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \
|
||||
LARGE_ID) \
|
||||
@ -251,72 +247,58 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
}
|
||||
|
||||
// Target id is not fresh
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// LHS id does not exist
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// RHS id does not exist
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// LHS and RHS ids do not match type
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Opcode not appropriate
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFDiv, 200),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFDiv, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto replace_true_with_double_comparison = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
auto replace_true_with_double_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100);
|
||||
auto replace_true_with_uint32_comparison = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
auto replace_true_with_uint32_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101);
|
||||
auto replace_false_with_float_comparison = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
auto replace_false_with_float_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102);
|
||||
auto replace_false_with_sint64_comparison = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
auto replace_false_with_sint64_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_false[1], 33, 31, SpvOpSLessThan, 103);
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(replace_true_with_double_comparison,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(replace_true_with_double_comparison, context.get(),
|
||||
&fact_manager);
|
||||
ASSERT_TRUE(replace_true_with_double_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_true_with_double_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(transformation::IsApplicable(replace_true_with_uint32_comparison,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(replace_true_with_uint32_comparison, context.get(),
|
||||
&fact_manager);
|
||||
ASSERT_TRUE(replace_true_with_uint32_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_true_with_uint32_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(transformation::IsApplicable(replace_false_with_float_comparison,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(replace_false_with_float_comparison, context.get(),
|
||||
&fact_manager);
|
||||
ASSERT_TRUE(replace_false_with_float_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_false_with_float_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(transformation::IsApplicable(replace_false_with_sint64_comparison,
|
||||
context.get(), fact_manager));
|
||||
transformation::Apply(replace_false_with_sint64_comparison, context.get(),
|
||||
&fact_manager);
|
||||
ASSERT_TRUE(replace_false_with_sint64_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_false_with_sint64_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
@ -432,11 +414,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
fuzzerutil::UpdateModuleIdBound(context.get(), 200);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
// The transformation is not applicable because %200 is NaN.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
if (std::numeric_limits<double>::has_infinity) {
|
||||
double positive_infinity_double = std::numeric_limits<double>::infinity();
|
||||
@ -451,11 +431,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
// Even though the double constant %11 is less than the infinity %201, the
|
||||
// transformation is restricted to only apply to finite values.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
if (std::numeric_limits<float>::has_infinity) {
|
||||
float positive_infinity_float = std::numeric_limits<float>::infinity();
|
||||
@ -478,11 +456,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
// Even though the negative infinity at %203 is less than the positive
|
||||
// infinity %202, the transformation is restricted to only apply to finite
|
||||
// values.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
}
|
||||
|
||||
@ -558,21 +534,17 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
auto use_of_false_in_while =
|
||||
transformation::MakeIdUseDescriptor(21, SpvOpBranchConditional, 0, 16, 0);
|
||||
|
||||
auto replacement_1 = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
|
||||
auto replacement_2 = transformation::
|
||||
MakeTransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
|
||||
auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
|
||||
auto replacement_2 = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(replacement_1, context.get(), fact_manager));
|
||||
transformation::Apply(replacement_1, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
|
||||
replacement_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(replacement_2, context.get(), fact_manager));
|
||||
transformation::Apply(replacement_2, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
|
||||
replacement_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
|
@ -124,35 +124,32 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
|
||||
|
||||
// These transformations work: they match the facts.
|
||||
auto transformation_use_of_9_in_store =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_a, 100, 101);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_9_in_store,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_9_in_store, blockname_a,
|
||||
100, 101);
|
||||
ASSERT_TRUE(transformation_use_of_9_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
auto transformation_use_of_11_in_add =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_add, blockname_b, 102, 103);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_11_in_add,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_11_in_add, blockname_b,
|
||||
102, 103);
|
||||
ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
auto transformation_use_of_14_in_add =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_14_in_add, blockname_c, 104, 105);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_14_in_add,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_14_in_add, blockname_c,
|
||||
104, 105);
|
||||
ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
// The transformations are not applicable if we change which uniforms are
|
||||
// applied to which constants.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_b, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_add, blockname_c, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_14_in_add, blockname_a, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_b, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
|
||||
blockname_c, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_14_in_add,
|
||||
blockname_a, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// The following transformations do not apply because the uniform descriptors
|
||||
// are not sensible.
|
||||
@ -160,37 +157,31 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
|
||||
MakeUniformBufferElementDescriptor(1, 2, {0});
|
||||
protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor2 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {5});
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// The following transformation does not apply because the id descriptor is
|
||||
// not sensible.
|
||||
protobufs::IdUseDescriptor nonsense_id_use_descriptor =
|
||||
transformation::MakeIdUseDescriptor(9, SpvOpIAdd, 0, 15, 0);
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
nonsense_id_use_descriptor, blockname_a, 101, 102),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
|
||||
nonsense_id_use_descriptor, blockname_a, 101, 102)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// The following transformations do not apply because the ids are not fresh.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_add, blockname_b, 15, 103),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_add, blockname_b, 102, 15),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
|
||||
blockname_b, 15, 103)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
|
||||
blockname_b, 102, 15)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Apply the use of 9 in a store.
|
||||
transformation::Apply(transformation_use_of_9_in_store, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_9_in_store.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
std::string after_replacing_use_of_9_in_store = R"(
|
||||
OpCapability Shader
|
||||
@ -241,11 +232,10 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_replacing_use_of_9_in_store, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_11_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
// Apply the use of 11 in an add.
|
||||
transformation::Apply(transformation_use_of_11_in_add, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_11_in_add.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
std::string after_replacing_use_of_11_in_add = R"(
|
||||
OpCapability Shader
|
||||
@ -298,11 +288,10 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_replacing_use_of_11_in_add, context.get()));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_14_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
// Apply the use of 15 in an add.
|
||||
transformation::Apply(transformation_use_of_14_in_add, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_14_in_add.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
std::string after_replacing_use_of_14_in_add = R"(
|
||||
OpCapability Shader
|
||||
@ -498,82 +487,78 @@ TEST(TransformationReplaceConstantWithUniformTest, NestedStruct) {
|
||||
|
||||
// These transformations work: they match the facts.
|
||||
auto transformation_use_of_13_in_store =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_13_in_store, blockname_1, 100, 101);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_13_in_store, blockname_1,
|
||||
100, 101);
|
||||
ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
auto transformation_use_of_15_in_add =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_15_in_add, blockname_2, 102, 103);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_15_in_add, blockname_2,
|
||||
102, 103);
|
||||
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
auto transformation_use_of_17_in_add =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_17_in_add, blockname_3, 104, 105);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_17_in_add, blockname_3,
|
||||
104, 105);
|
||||
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
auto transformation_use_of_20_in_store =
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_20_in_store, blockname_4, 106, 107);
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
TransformationReplaceConstantWithUniform(use_of_20_in_store, blockname_4,
|
||||
106, 107);
|
||||
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
transformation::Apply(transformation_use_of_13_in_store, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_13_in_store.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
transformation::Apply(transformation_use_of_15_in_add, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_15_in_add.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
transformation::Apply(transformation_use_of_17_in_add, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_17_in_add.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
transformation::Apply(transformation_use_of_20_in_store, context.get(),
|
||||
&fact_manager);
|
||||
transformation_use_of_20_in_store.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_17_in_add,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_20_in_store,
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation_use_of_20_in_store.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
@ -722,10 +707,9 @@ TEST(TransformationReplaceConstantWithUniformTest, NoUniformIntPointerPresent) {
|
||||
|
||||
// This transformation is not available because no uniform pointer to integer
|
||||
// type is present:
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_0, 100, 101),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_0, 100, 101)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) {
|
||||
@ -798,10 +782,9 @@ TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) {
|
||||
|
||||
// This transformation is not available because no constant is present for the
|
||||
// index 1 required to index into the uniform buffer:
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_9, 100, 101),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_9, 100, 101)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceConstantWithUniformTest,
|
||||
@ -873,10 +856,9 @@ TEST(TransformationReplaceConstantWithUniformTest,
|
||||
|
||||
// This transformation is not available because no integer type is present to
|
||||
// allow a constant index to be expressed:
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_3, 100, 101),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_3, 100, 101)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceConstantWithUniformTest,
|
||||
@ -960,25 +942,21 @@ TEST(TransformationReplaceConstantWithUniformTest,
|
||||
transformation::MakeIdUseDescriptor(11, SpvOpStore, 1, 10, 1);
|
||||
|
||||
// These are right:
|
||||
ASSERT_TRUE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_9, 100, 101),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_store, blockname_10, 102, 103),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_9, 100, 101)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
|
||||
blockname_10, 102, 103)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// These are wrong because the constants do not match the facts about
|
||||
// uniforms.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_11_in_store, blockname_9, 100, 101),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
use_of_9_in_store, blockname_10, 102, 103),
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
|
||||
blockname_9, 100, 101)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
|
||||
blockname_10, 102, 103)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) {
|
||||
@ -1239,83 +1217,65 @@ TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) {
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 100, uniform_h_x));
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200, uniform_h_y));
|
||||
|
||||
std::vector<protobufs::TransformationReplaceConstantWithUniform>
|
||||
transformations;
|
||||
std::vector<TransformationReplaceConstantWithUniform> transformations;
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(18, SpvOpStore, 1, 20, 0),
|
||||
uniform_f_a_4, 200, 201));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(22, SpvOpStore, 1, 23, 0),
|
||||
uniform_f_a_3, 202, 203));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(25, SpvOpStore, 1, 26, 0),
|
||||
uniform_f_a_2, 204, 205));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(28, SpvOpStore, 1, 29, 0),
|
||||
uniform_f_a_1, 206, 207));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(31, SpvOpStore, 1, 32, 0),
|
||||
uniform_f_a_0, 208, 209));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(18, SpvOpStore, 1, 20, 0),
|
||||
uniform_f_a_4, 200, 201));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(22, SpvOpStore, 1, 23, 0),
|
||||
uniform_f_a_3, 202, 203));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(25, SpvOpStore, 1, 26, 0),
|
||||
uniform_f_a_2, 204, 205));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(28, SpvOpStore, 1, 29, 0),
|
||||
uniform_f_a_1, 206, 207));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(31, SpvOpStore, 1, 32, 0),
|
||||
uniform_f_a_0, 208, 209));
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(30, SpvOpStore, 1, 35, 0),
|
||||
uniform_f_b_w, 210, 211));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(27, SpvOpStore, 1, 37, 0),
|
||||
uniform_f_b_z, 212, 213));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(24, SpvOpStore, 1, 39, 0),
|
||||
uniform_f_b_y, 214, 215));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(21, SpvOpStore, 1, 41, 0),
|
||||
uniform_f_b_x, 216, 217));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(30, SpvOpStore, 1, 35, 0),
|
||||
uniform_f_b_w, 210, 211));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(27, SpvOpStore, 1, 37, 0),
|
||||
uniform_f_b_z, 212, 213));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(24, SpvOpStore, 1, 39, 0),
|
||||
uniform_f_b_y, 214, 215));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(21, SpvOpStore, 1, 41, 0),
|
||||
uniform_f_b_x, 216, 217));
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(44, SpvOpStore, 1, 45, 0),
|
||||
uniform_f_c_z, 220, 221));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(46, SpvOpStore, 1, 47, 0),
|
||||
uniform_f_c_y, 222, 223));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(48, SpvOpStore, 1, 49, 0),
|
||||
uniform_f_c_x, 224, 225));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(44, SpvOpStore, 1, 45, 0),
|
||||
uniform_f_c_z, 220, 221));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(46, SpvOpStore, 1, 47, 0),
|
||||
uniform_f_c_y, 222, 223));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(48, SpvOpStore, 1, 49, 0),
|
||||
uniform_f_c_x, 224, 225));
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(50, SpvOpStore, 1, 52, 0),
|
||||
uniform_f_d, 226, 227));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(50, SpvOpStore, 1, 52, 0),
|
||||
uniform_f_d, 226, 227));
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(53, SpvOpStore, 1, 54, 0),
|
||||
uniform_h_x, 228, 229));
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(55, SpvOpStore, 1, 56, 0),
|
||||
uniform_h_y, 230, 231));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(53, SpvOpStore, 1, 54, 0),
|
||||
uniform_h_x, 228, 229));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(55, SpvOpStore, 1, 56, 0),
|
||||
uniform_h_y, 230, 231));
|
||||
|
||||
transformations.emplace_back(
|
||||
transformation::MakeTransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(42, SpvOpStore, 1, 43, 0),
|
||||
uniform_g, 218, 219));
|
||||
transformations.emplace_back(TransformationReplaceConstantWithUniform(
|
||||
transformation::MakeIdUseDescriptor(42, SpvOpStore, 1, 43, 0), uniform_g,
|
||||
218, 219));
|
||||
|
||||
for (auto& transformation : transformations) {
|
||||
ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
|
||||
fact_manager));
|
||||
transformation::Apply(transformation, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
|
@ -90,57 +90,44 @@ TEST(TransformationSplitBlockTest, NotApplicable) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// No split before OpVariable
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(8, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(8, 1, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(8, 0, 100).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(8, 1, 100).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
// No split before OpLabel
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(14, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(14, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if base instruction is outside a function
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(1, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(1, 4, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(1, 35, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(1, 0, 100).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(1, 4, 100).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(1, 35, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if block is loop header
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if base instruction does not exist
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(88, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(88, 22, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(88, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(88, 22, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if offset is too large (goes into another block)
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(18, 3, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(18, 3, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if id in use
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(18, 0, 27), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(18, 0, 14), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(18, 0, 27).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(18, 0, 14).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
|
||||
@ -201,10 +188,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto split_1 = transformation::MakeTransformationSplitBlock(5, 3, 100);
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(split_1, context.get(), fact_manager));
|
||||
transformation::Apply(split_1, context.get(), &fact_manager);
|
||||
auto split_1 = TransformationSplitBlock(5, 3, 100);
|
||||
ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager));
|
||||
split_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_1 = R"(
|
||||
@ -249,10 +235,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split_1, context.get()));
|
||||
|
||||
auto split_2 = transformation::MakeTransformationSplitBlock(11, 1, 101);
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(split_2, context.get(), fact_manager));
|
||||
transformation::Apply(split_2, context.get(), &fact_manager);
|
||||
auto split_2 = TransformationSplitBlock(11, 1, 101);
|
||||
ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager));
|
||||
split_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_2 = R"(
|
||||
@ -299,10 +284,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split_2, context.get()));
|
||||
|
||||
auto split_3 = transformation::MakeTransformationSplitBlock(14, 0, 102);
|
||||
ASSERT_TRUE(
|
||||
transformation::IsApplicable(split_3, context.get(), fact_manager));
|
||||
transformation::Apply(split_3, context.get(), &fact_manager);
|
||||
auto split_3 = TransformationSplitBlock(14, 0, 102);
|
||||
ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager));
|
||||
split_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_3 = R"(
|
||||
@ -415,16 +399,14 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Illegal to split between the merge and the conditional branch.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(14, 2, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(12, 3, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(14, 2, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(12, 3, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto split = transformation::MakeTransformationSplitBlock(14, 1, 100);
|
||||
ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
|
||||
transformation::Apply(split, context.get(), &fact_manager);
|
||||
auto split = TransformationSplitBlock(14, 1, 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
@ -541,16 +523,14 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Illegal to split between the merge and the conditional branch.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(9, 2, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(15, 3, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(9, 2, 100).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(15, 3, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto split = transformation::MakeTransformationSplitBlock(9, 1, 100);
|
||||
ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
|
||||
transformation::Apply(split, context.get(), &fact_manager);
|
||||
auto split = TransformationSplitBlock(9, 1, 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
@ -674,15 +654,12 @@ TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) {
|
||||
|
||||
// We cannot split before OpPhi instructions, since the number of incoming
|
||||
// blocks may not appropriately match after splitting.
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(26, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(),
|
||||
fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(26, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
|
||||
@ -724,12 +701,11 @@ TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_TRUE(transformation::IsApplicable(
|
||||
transformation::MakeTransformationSplitBlock(21, 0, 100), context.get(),
|
||||
fact_manager));
|
||||
auto split = transformation::MakeTransformationSplitBlock(20, 1, 100);
|
||||
ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
|
||||
transformation::Apply(split, context.get(), &fact_manager);
|
||||
ASSERT_TRUE(TransformationSplitBlock(21, 0, 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
auto split = TransformationSplitBlock(20, 1, 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
|
@ -8276,6 +8276,328 @@ OpFunctionEnd
|
||||
true, 7u, 23u, true, true, 2u);
|
||||
}
|
||||
|
||||
TEST_F(InstBindlessTest,
|
||||
InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) {
|
||||
// #version 450
|
||||
// #extension GL_EXT_nonuniform_qualifier : enable
|
||||
//
|
||||
// layout (local_size_x = 1, local_size_y = 1) in;
|
||||
//
|
||||
// layout(set = 0, binding = 0, std140) buffer Input {
|
||||
// uint index;
|
||||
// float red;
|
||||
// } sbo;
|
||||
//
|
||||
// layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[];
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
|
||||
// }
|
||||
|
||||
const std::string defs_before =
|
||||
R"(OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpSource GLSL 450
|
||||
OpSourceExtension "GL_EXT_nonuniform_qualifier"
|
||||
OpName %main "main"
|
||||
OpName %Input "Input"
|
||||
OpMemberName %Input 0 "index"
|
||||
OpMemberName %Input 1 "red"
|
||||
OpName %sbo "sbo"
|
||||
OpName %images "images"
|
||||
OpMemberDecorate %Input 0 Offset 0
|
||||
OpMemberDecorate %Input 1 Offset 4
|
||||
OpDecorate %Input BufferBlock
|
||||
OpDecorate %sbo DescriptorSet 0
|
||||
OpDecorate %sbo Binding 0
|
||||
OpDecorate %images DescriptorSet 0
|
||||
OpDecorate %images Binding 1
|
||||
OpDecorate %images NonWritable
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%Input = OpTypeStruct %uint %float
|
||||
%_ptr_Uniform_Input = OpTypePointer Uniform %Input
|
||||
%sbo = OpVariable %_ptr_Uniform_Input Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
|
||||
%_runtimearr_13 = OpTypeRuntimeArray %13
|
||||
%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
|
||||
%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
|
||||
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
|
||||
%v2int = OpTypeVector %int 2
|
||||
%25 = OpConstantComposite %v2int %int_0 %int_0
|
||||
%v4float = OpTypeVector %float 4
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
)";
|
||||
|
||||
const std::string defs_after =
|
||||
R"(OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpSource GLSL 450
|
||||
OpSourceExtension "GL_EXT_nonuniform_qualifier"
|
||||
OpName %main "main"
|
||||
OpName %Input "Input"
|
||||
OpMemberName %Input 0 "index"
|
||||
OpMemberName %Input 1 "red"
|
||||
OpName %sbo "sbo"
|
||||
OpName %images "images"
|
||||
OpMemberDecorate %Input 0 Offset 0
|
||||
OpMemberDecorate %Input 1 Offset 4
|
||||
OpDecorate %Input BufferBlock
|
||||
OpDecorate %sbo DescriptorSet 0
|
||||
OpDecorate %sbo Binding 0
|
||||
OpDecorate %images DescriptorSet 0
|
||||
OpDecorate %images Binding 1
|
||||
OpDecorate %images NonWritable
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_39 Block
|
||||
OpMemberDecorate %_struct_39 0 Offset 0
|
||||
OpDecorate %41 DescriptorSet 7
|
||||
OpDecorate %41 Binding 1
|
||||
OpDecorate %_struct_63 Block
|
||||
OpMemberDecorate %_struct_63 0 Offset 0
|
||||
OpMemberDecorate %_struct_63 1 Offset 4
|
||||
OpDecorate %65 DescriptorSet 7
|
||||
OpDecorate %65 Binding 0
|
||||
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%Input = OpTypeStruct %uint %float
|
||||
%_ptr_Uniform_Input = OpTypePointer Uniform %Input
|
||||
%sbo = OpVariable %_ptr_Uniform_Input Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
|
||||
%_runtimearr_13 = OpTypeRuntimeArray %13
|
||||
%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
|
||||
%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
|
||||
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
|
||||
%v2int = OpTypeVector %int 2
|
||||
%20 = OpConstantComposite %v2int %int_0 %int_0
|
||||
%v4float = OpTypeVector %float 4
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%34 = OpTypeFunction %uint %uint %uint
|
||||
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||
%_struct_39 = OpTypeStruct %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39
|
||||
%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer
|
||||
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||
%bool = OpTypeBool
|
||||
%57 = OpTypeFunction %void %uint %uint %uint %uint
|
||||
%_struct_63 = OpTypeStruct %uint %_runtimearr_uint
|
||||
%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63
|
||||
%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer
|
||||
%uint_10 = OpConstant %uint 10
|
||||
%uint_4 = OpConstant %uint 4
|
||||
%uint_23 = OpConstant %uint 23
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_5 = OpConstant %uint 5
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%v3uint = OpTypeVector %uint 3
|
||||
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
|
||||
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
|
||||
%uint_6 = OpConstant %uint 6
|
||||
%uint_7 = OpConstant %uint 7
|
||||
%uint_8 = OpConstant %uint 8
|
||||
%uint_9 = OpConstant %uint 9
|
||||
%uint_50 = OpConstant %uint 50
|
||||
%112 = OpConstantNull %v4float
|
||||
%115 = OpTypeFunction %uint %uint %uint %uint %uint
|
||||
%uint_47 = OpConstant %uint 47
|
||||
%140 = OpConstantNull %uint
|
||||
%uint_53 = OpConstant %uint 53
|
||||
)";
|
||||
|
||||
const std::string func_before =
|
||||
R"(%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
|
||||
%20 = OpLoad %uint %19
|
||||
%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
|
||||
%23 = OpLoad %13 %22
|
||||
%27 = OpImageRead %v4float %23 %25
|
||||
%29 = OpCompositeExtract %float %27 0
|
||||
%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
|
||||
OpStore %31 %29
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string func_after =
|
||||
R"(%main = OpFunction %void None %7
|
||||
%24 = OpLabel
|
||||
%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
|
||||
%132 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
|
||||
%133 = OpINotEqual %bool %132 %uint_0
|
||||
OpSelectionMerge %134 None
|
||||
OpBranchConditional %133 %135 %136
|
||||
%135 = OpLabel
|
||||
%137 = OpLoad %uint %25
|
||||
OpBranch %134
|
||||
%136 = OpLabel
|
||||
%139 = OpFunctionCall %void %56 %uint_47 %uint_1 %uint_0 %uint_0
|
||||
OpBranch %134
|
||||
%134 = OpLabel
|
||||
%141 = OpPhi %uint %137 %135 %140 %136
|
||||
%27 = OpAccessChain %_ptr_UniformConstant_13 %images %141
|
||||
%28 = OpLoad %13 %27
|
||||
%48 = OpFunctionCall %uint %33 %uint_1 %uint_1
|
||||
%50 = OpULessThan %bool %141 %48
|
||||
OpSelectionMerge %51 None
|
||||
OpBranchConditional %50 %52 %53
|
||||
%52 = OpLabel
|
||||
%54 = OpLoad %13 %27
|
||||
%142 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_1 %141
|
||||
%143 = OpINotEqual %bool %142 %uint_0
|
||||
OpSelectionMerge %144 None
|
||||
OpBranchConditional %143 %145 %146
|
||||
%145 = OpLabel
|
||||
%147 = OpLoad %13 %27
|
||||
%148 = OpImageRead %v4float %147 %20
|
||||
OpBranch %144
|
||||
%146 = OpLabel
|
||||
%149 = OpFunctionCall %void %56 %uint_50 %uint_1 %141 %uint_0
|
||||
OpBranch %144
|
||||
%144 = OpLabel
|
||||
%150 = OpPhi %v4float %148 %145 %112 %146
|
||||
OpBranch %51
|
||||
%53 = OpLabel
|
||||
%111 = OpFunctionCall %void %56 %uint_50 %uint_0 %141 %48
|
||||
OpBranch %51
|
||||
%51 = OpLabel
|
||||
%113 = OpPhi %v4float %150 %144 %112 %53
|
||||
%30 = OpCompositeExtract %float %113 0
|
||||
%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
|
||||
%151 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
|
||||
%152 = OpINotEqual %bool %151 %uint_0
|
||||
OpSelectionMerge %153 None
|
||||
OpBranchConditional %152 %154 %155
|
||||
%154 = OpLabel
|
||||
OpStore %31 %30
|
||||
OpBranch %153
|
||||
%155 = OpLabel
|
||||
%157 = OpFunctionCall %void %56 %uint_53 %uint_1 %uint_0 %uint_0
|
||||
OpBranch %153
|
||||
%153 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string new_funcs =
|
||||
R"(%33 = OpFunction %uint None %34
|
||||
%35 = OpFunctionParameter %uint
|
||||
%36 = OpFunctionParameter %uint
|
||||
%37 = OpLabel
|
||||
%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35
|
||||
%44 = OpLoad %uint %43
|
||||
%45 = OpIAdd %uint %44 %36
|
||||
%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45
|
||||
%47 = OpLoad %uint %46
|
||||
OpReturnValue %47
|
||||
OpFunctionEnd
|
||||
%56 = OpFunction %void None %57
|
||||
%58 = OpFunctionParameter %uint
|
||||
%59 = OpFunctionParameter %uint
|
||||
%60 = OpFunctionParameter %uint
|
||||
%61 = OpFunctionParameter %uint
|
||||
%62 = OpLabel
|
||||
%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0
|
||||
%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10
|
||||
%70 = OpIAdd %uint %69 %uint_10
|
||||
%71 = OpArrayLength %uint %65 1
|
||||
%72 = OpULessThanEqual %bool %70 %71
|
||||
OpSelectionMerge %73 None
|
||||
OpBranchConditional %72 %74 %73
|
||||
%74 = OpLabel
|
||||
%75 = OpIAdd %uint %69 %uint_0
|
||||
%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75
|
||||
OpStore %76 %uint_10
|
||||
%78 = OpIAdd %uint %69 %uint_1
|
||||
%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78
|
||||
OpStore %79 %uint_23
|
||||
%81 = OpIAdd %uint %69 %uint_2
|
||||
%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81
|
||||
OpStore %82 %58
|
||||
%85 = OpIAdd %uint %69 %uint_3
|
||||
%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85
|
||||
OpStore %86 %uint_5
|
||||
%90 = OpLoad %v3uint %gl_GlobalInvocationID
|
||||
%91 = OpCompositeExtract %uint %90 0
|
||||
%92 = OpCompositeExtract %uint %90 1
|
||||
%93 = OpCompositeExtract %uint %90 2
|
||||
%94 = OpIAdd %uint %69 %uint_4
|
||||
%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94
|
||||
OpStore %95 %91
|
||||
%96 = OpIAdd %uint %69 %uint_5
|
||||
%97 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %96
|
||||
OpStore %97 %92
|
||||
%99 = OpIAdd %uint %69 %uint_6
|
||||
%100 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %99
|
||||
OpStore %100 %93
|
||||
%102 = OpIAdd %uint %69 %uint_7
|
||||
%103 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %102
|
||||
OpStore %103 %59
|
||||
%105 = OpIAdd %uint %69 %uint_8
|
||||
%106 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %105
|
||||
OpStore %106 %60
|
||||
%108 = OpIAdd %uint %69 %uint_9
|
||||
%109 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %108
|
||||
OpStore %109 %61
|
||||
OpBranch %73
|
||||
%73 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%114 = OpFunction %uint None %115
|
||||
%116 = OpFunctionParameter %uint
|
||||
%117 = OpFunctionParameter %uint
|
||||
%118 = OpFunctionParameter %uint
|
||||
%119 = OpFunctionParameter %uint
|
||||
%120 = OpLabel
|
||||
%121 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %116
|
||||
%122 = OpLoad %uint %121
|
||||
%123 = OpIAdd %uint %122 %117
|
||||
%124 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %123
|
||||
%125 = OpLoad %uint %124
|
||||
%126 = OpIAdd %uint %125 %118
|
||||
%127 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %126
|
||||
%128 = OpLoad %uint %127
|
||||
%129 = OpIAdd %uint %128 %119
|
||||
%130 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %129
|
||||
%131 = OpLoad %uint %130
|
||||
OpReturnValue %131
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndCheck<InstBindlessCheckPass>(
|
||||
defs_before + func_before, defs_after + func_after + new_funcs, true,
|
||||
true, 7u, 23u, true, true, 2u);
|
||||
}
|
||||
|
||||
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
||||
//
|
||||
// Compute shader
|
||||
|
@ -6491,10 +6491,14 @@ OpDecorate %entryPointOutput )" +
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%vtype = )" + type + R"(
|
||||
%v3float = OpTypeVector %float 3
|
||||
%v4float = OpTypeVector %float 4
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
|
||||
%float_0 = OpConstant %float 0
|
||||
%_ptr_Output_vtype = OpTypePointer Output %vtype
|
||||
%entryPointOutput = OpVariable %_ptr_Output_vtype Output
|
||||
%_ptr_Output_type = OpTypePointer Output %)" + type + R"(
|
||||
%entryPointOutput = OpVariable %_ptr_Output_type Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
@ -6504,8 +6508,7 @@ OpFunctionEnd
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 0");
|
||||
std::string spirv = ShaderWithComponentDecoration("uint", "Component 0");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6514,8 +6517,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 1");
|
||||
std::string spirv = ShaderWithComponentDecoration("uint", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6524,8 +6526,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 2");
|
||||
std::string spirv = ShaderWithComponentDecoration("uint", "Component 2");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6534,8 +6535,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 3");
|
||||
std::string spirv = ShaderWithComponentDecoration("uint", "Component 3");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6544,8 +6544,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 4");
|
||||
std::string spirv = ShaderWithComponentDecoration("uint", "Component 4");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
@ -6556,8 +6555,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 3", "Component 1");
|
||||
std::string spirv = ShaderWithComponentDecoration("v3float", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6566,8 +6564,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 0");
|
||||
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 0");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
@ -6576,8 +6573,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 1");
|
||||
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
@ -6588,8 +6584,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 3");
|
||||
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 3");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
@ -6598,6 +6593,28 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
|
||||
"and ending with 6 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationArrayGoodVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 1");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationArrayBadVulkan) {
|
||||
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||
std::string spirv =
|
||||
ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 2");
|
||||
|
||||
CompileSuccessfully(spirv, env);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Sequence of components starting with 2 "
|
||||
"and ending with 4 gets larger than 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
|
2
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp
vendored
2
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp
vendored
@ -257,7 +257,7 @@ int main(int argc, const char** argv) {
|
||||
const std::string dot_spv(".spv");
|
||||
std::string in_facts_file =
|
||||
in_binary_file.substr(0, in_binary_file.length() - dot_spv.length()) +
|
||||
".json";
|
||||
".facts";
|
||||
std::ifstream facts_input(in_facts_file);
|
||||
if (facts_input) {
|
||||
std::string facts_json_string((std::istreambuf_iterator<char>(facts_input)),
|
||||
|
2
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
2
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
@ -28,8 +28,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using ErrorOrInt = std::pair<std::string, int>;
|
||||
|
||||
// Check that the std::system function can actually be used.
|
||||
bool CheckExecuteCommand() {
|
||||
int res = std::system(nullptr);
|
||||
|
Loading…
Reference in New Issue
Block a user