From e8ce4355ae1c485864d0fc0f973a6d0a433d9ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Perez?= Date: Tue, 15 Sep 2020 19:36:23 -0300 Subject: [PATCH] spirv-fuzz: Add bit instruction synonym transformation (#3775) This PR implements part of the add bit instruction synonym transformation. For now, the implementation covers the OpBitwiseOr, OpBitwiseXor and OpBitwiseAnd cases. --- source/fuzz/CMakeLists.txt | 4 + source/fuzz/fuzzer.cpp | 4 + source/fuzz/fuzzer_context.cpp | 4 + source/fuzz/fuzzer_context.h | 4 + ...zzer_pass_add_bit_instruction_synonyms.cpp | 84 ++++ ...fuzzer_pass_add_bit_instruction_synonyms.h | 41 ++ source/fuzz/protobufs/spvtoolsfuzz.proto | 28 ++ source/fuzz/transformation.cpp | 5 + ...sformation_add_bit_instruction_synonym.cpp | 228 +++++++++ ...ansformation_add_bit_instruction_synonym.h | 141 ++++++ source/opcode.cpp | 17 + source/opcode.h | 9 +- test/fuzz/CMakeLists.txt | 1 + ...ation_add_bit_instruction_synonym_test.cpp | 463 ++++++++++++++++++ 14 files changed, 1030 insertions(+), 3 deletions(-) create mode 100644 source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp create mode 100644 source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h create mode 100644 source/fuzz/transformation_add_bit_instruction_synonym.cpp create mode 100644 source/fuzz/transformation_add_bit_instruction_synonym.h create mode 100644 test/fuzz/transformation_add_bit_instruction_synonym_test.cpp diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt index ca4b22155..fa5ed0a4e 100644 --- a/source/fuzz/CMakeLists.txt +++ b/source/fuzz/CMakeLists.txt @@ -52,6 +52,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_context.h fuzzer_pass.h fuzzer_pass_add_access_chains.h + fuzzer_pass_add_bit_instruction_synonyms.h fuzzer_pass_add_composite_inserts.h fuzzer_pass_add_composite_types.h fuzzer_pass_add_copy_memory.h @@ -124,6 +125,7 @@ if(SPIRV_BUILD_FUZZER) shrinker.h transformation.h transformation_access_chain.h + transformation_add_bit_instruction_synonym.h transformation_add_constant_boolean.h transformation_add_constant_composite.h transformation_add_constant_null.h @@ -217,6 +219,7 @@ if(SPIRV_BUILD_FUZZER) fuzzer_context.cpp fuzzer_pass.cpp fuzzer_pass_add_access_chains.cpp + fuzzer_pass_add_bit_instruction_synonyms.cpp fuzzer_pass_add_composite_inserts.cpp fuzzer_pass_add_composite_types.cpp fuzzer_pass_add_copy_memory.cpp @@ -288,6 +291,7 @@ if(SPIRV_BUILD_FUZZER) shrinker.cpp transformation.cpp transformation_access_chain.cpp + transformation_add_bit_instruction_synonym.cpp transformation_add_constant_boolean.cpp transformation_add_constant_composite.cpp transformation_add_constant_null.cpp diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp index 5c4cecad6..be530a505 100644 --- a/source/fuzz/fuzzer.cpp +++ b/source/fuzz/fuzzer.cpp @@ -20,6 +20,7 @@ #include "source/fuzz/fact_manager/fact_manager.h" #include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_pass_add_access_chains.h" +#include "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h" #include "source/fuzz/fuzzer_pass_add_composite_inserts.h" #include "source/fuzz/fuzzer_pass_add_composite_types.h" #include "source/fuzz/fuzzer_pass_add_copy_memory.h" @@ -205,6 +206,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run( MaybeAddPass( &passes, ir_context.get(), &transformation_context, &fuzzer_context, transformation_sequence_out); + MaybeAddPass( + &passes, ir_context.get(), &transformation_context, &fuzzer_context, + transformation_sequence_out); MaybeAddPass( &passes, ir_context.get(), &transformation_context, &fuzzer_context, transformation_sequence_out); diff --git a/source/fuzz/fuzzer_context.cpp b/source/fuzz/fuzzer_context.cpp index 1f3baebab..47d4a8b54 100644 --- a/source/fuzz/fuzzer_context.cpp +++ b/source/fuzz/fuzzer_context.cpp @@ -27,6 +27,8 @@ const std::pair kChanceOfAddingAccessChain = {5, 50}; const std::pair kChanceOfAddingAnotherStructField = {20, 90}; const std::pair kChanceOfAddingArrayOrStructType = {20, 90}; +const std::pair kChanceOfAddingBitInstructionSynonym = {20, + 90}; const std::pair kChanceOfAddingBothBranchesWhenReplacingOpSelect = {40, 60}; const std::pair kChanceOfAddingCompositeInsert = {20, 50}; @@ -172,6 +174,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator, ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField); chance_of_adding_array_or_struct_type_ = ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType); + chance_of_adding_bit_instruction_synonym_ = + ChooseBetweenMinAndMax(kChanceOfAddingBitInstructionSynonym); chance_of_adding_both_branches_when_replacing_opselect_ = ChooseBetweenMinAndMax(kChanceOfAddingBothBranchesWhenReplacingOpSelect); chance_of_adding_composite_insert_ = diff --git a/source/fuzz/fuzzer_context.h b/source/fuzz/fuzzer_context.h index 898db1f2e..28bb57555 100644 --- a/source/fuzz/fuzzer_context.h +++ b/source/fuzz/fuzzer_context.h @@ -115,6 +115,9 @@ class FuzzerContext { uint32_t GetChanceOfAddingArrayOrStructType() { return chance_of_adding_array_or_struct_type_; } + uint32_t GetChanceOfAddingBitInstructionSynonym() { + return chance_of_adding_bit_instruction_synonym_; + } uint32_t GetChanceOfAddingBothBranchesWhenReplacingOpSelect() { return chance_of_adding_both_branches_when_replacing_opselect_; } @@ -379,6 +382,7 @@ class FuzzerContext { uint32_t chance_of_adding_access_chain_; uint32_t chance_of_adding_another_struct_field_; uint32_t chance_of_adding_array_or_struct_type_; + uint32_t chance_of_adding_bit_instruction_synonym_; uint32_t chance_of_adding_both_branches_when_replacing_opselect_; uint32_t chance_of_adding_composite_insert_; uint32_t chance_of_adding_copy_memory_; diff --git a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp new file mode 100644 index 000000000..1547810ef --- /dev/null +++ b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2020 André Perez Maselco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_add_bit_instruction_synonym.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddBitInstructionSynonyms::FuzzerPassAddBitInstructionSynonyms( + opt::IRContext* ir_context, TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, transformation_context, fuzzer_context, + transformations) {} + +FuzzerPassAddBitInstructionSynonyms::~FuzzerPassAddBitInstructionSynonyms() = + default; + +void FuzzerPassAddBitInstructionSynonyms::Apply() { + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + for (auto& instruction : block) { + // Randomly decides whether the transformation will be applied. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingBitInstructionSynonym())) { + continue; + } + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3557): + // Right now we only support certain operations. When this issue is + // addressed the following conditional can use the function + // |spvOpcodeIsBit|. + if (instruction.opcode() != SpvOpBitwiseOr && + instruction.opcode() != SpvOpBitwiseXor && + instruction.opcode() != SpvOpBitwiseAnd) { + continue; + } + + // Right now, only integer operands are supported. + if (GetIRContext() + ->get_type_mgr() + ->GetType(instruction.type_id()) + ->AsVector()) { + continue; + } + + // Make sure all bit indexes are defined as 32-bit unsigned integers. + uint32_t width = GetIRContext() + ->get_type_mgr() + ->GetType(instruction.type_id()) + ->AsInteger() + ->width(); + for (uint32_t i = 0; i < width; i++) { + FindOrCreateIntegerConstant({i}, 32, false, false); + } + + // Applies the add bit instruction synonym transformation. + ApplyTransformation(TransformationAddBitInstructionSynonym( + instruction.result_id(), + GetFuzzerContext()->GetFreshIds( + TransformationAddBitInstructionSynonym::GetRequiredFreshIdCount( + GetIRContext(), &instruction)))); + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h new file mode 100644 index 000000000..0194425d8 --- /dev/null +++ b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h @@ -0,0 +1,41 @@ +// Copyright (c) 2020 André Perez Maselco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_BIT_INSTRUCTION_SYNONYMS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_BIT_INSTRUCTION_SYNONYMS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// This fuzzer pass adds synonyms for bit instructions. It iterates over the +// module instructions, checks if they are bit instructions and randomly applies +// the transformation. +class FuzzerPassAddBitInstructionSynonyms : public FuzzerPass { + public: + FuzzerPassAddBitInstructionSynonyms( + opt::IRContext* ir_context, TransformationContext* transformation_context, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddBitInstructionSynonyms(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_BIT_INSTRUCTION_SYNONYMS_H_ diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto index f273bbc27..c6169438a 100644 --- a/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -496,6 +496,7 @@ message Transformation { TransformationReplaceOpSelectWithConditionalBranch replace_opselect_with_conditional_branch = 74; TransformationDuplicateRegionWithSelection duplicate_region_with_selection = 75; TransformationFlattenConditionalBranch flatten_conditional_branch = 76; + TransformationAddBitInstructionSynonym add_bit_instruction_synonym = 77; // Add additional option using the next available number. } } @@ -532,6 +533,33 @@ message TransformationAccessChain { } +message TransformationAddBitInstructionSynonym { + + // A transformation that adds synonyms for bit instructions by evaluating + // each bit with the corresponding operation. There is a SPIR-V code example in the + // header file of the transformation class that can help understand the transformation. + + // This transformation is only applicable if the described instruction has one of the following opcodes. + // Supported: + // OpBitwiseOr + // OpBitwiseXor + // OpBitwiseAnd + // To be supported in the future: + // OpShiftRightLogical + // OpShiftRightArithmetic + // OpShiftLeftLogical + // OpNot + // OpBitReverse + // OpBitCount + + // The bit instruction result id. + uint32 instruction_result_id = 1; + + // The fresh ids required to apply the transformation. + repeated uint32 fresh_ids = 2; + +} + message TransformationAddConstantBoolean { // Supports adding the constants true and false to a module, which may be diff --git a/source/fuzz/transformation.cpp b/source/fuzz/transformation.cpp index bd924f9af..0b253ff5a 100644 --- a/source/fuzz/transformation.cpp +++ b/source/fuzz/transformation.cpp @@ -18,6 +18,7 @@ #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/transformation_access_chain.h" +#include "source/fuzz/transformation_add_bit_instruction_synonym.h" #include "source/fuzz/transformation_add_constant_boolean.h" #include "source/fuzz/transformation_add_constant_composite.h" #include "source/fuzz/transformation_add_constant_null.h" @@ -105,6 +106,10 @@ std::unique_ptr Transformation::FromMessage( switch (message.transformation_case()) { case protobufs::Transformation::TransformationCase::kAccessChain: return MakeUnique(message.access_chain()); + case protobufs::Transformation::TransformationCase:: + kAddBitInstructionSynonym: + return MakeUnique( + message.add_bit_instruction_synonym()); case protobufs::Transformation::TransformationCase::kAddConstantBoolean: return MakeUnique( message.add_constant_boolean()); diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.cpp b/source/fuzz/transformation_add_bit_instruction_synonym.cpp new file mode 100644 index 000000000..ae5d9f15d --- /dev/null +++ b/source/fuzz/transformation_add_bit_instruction_synonym.cpp @@ -0,0 +1,228 @@ +// Copyright (c) 2020 André Perez Maselco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_bit_instruction_synonym.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddBitInstructionSynonym::TransformationAddBitInstructionSynonym( + const spvtools::fuzz::protobufs::TransformationAddBitInstructionSynonym& + message) + : message_(message) {} + +TransformationAddBitInstructionSynonym::TransformationAddBitInstructionSynonym( + const uint32_t instruction_result_id, + const std::vector& fresh_ids) { + message_.set_instruction_result_id(instruction_result_id); + *message_.mutable_fresh_ids() = + google::protobuf::RepeatedField( + fresh_ids.begin(), fresh_ids.end()); +} + +bool TransformationAddBitInstructionSynonym::IsApplicable( + opt::IRContext* ir_context, + const TransformationContext& transformation_context) const { + auto instruction = + ir_context->get_def_use_mgr()->GetDef(message_.instruction_result_id()); + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3557): + // Right now we only support certain operations. When this issue is addressed + // the following conditional can use the function |spvOpcodeIsBit|. + // |instruction| must be defined and must be a supported bit instruction. + if (!instruction || (instruction->opcode() != SpvOpBitwiseOr && + instruction->opcode() != SpvOpBitwiseXor && + instruction->opcode() != SpvOpBitwiseAnd)) { + return false; + } + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3792): + // Right now, only integer operands are supported. + if (ir_context->get_type_mgr()->GetType(instruction->type_id())->AsVector()) { + return false; + } + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3791): + // This condition could be relaxed if the index exists as another integer + // type. + // All bit indexes must be defined as 32-bit unsigned integers. + uint32_t width = ir_context->get_type_mgr() + ->GetType(instruction->type_id()) + ->AsInteger() + ->width(); + for (uint32_t i = 0; i < width; i++) { + if (!fuzzerutil::MaybeGetIntegerConstant(ir_context, transformation_context, + {i}, 32, false, false)) { + return false; + } + } + + // |message_.fresh_ids.size| must have the exact number of fresh ids required + // to apply the transformation. + if (static_cast(message_.fresh_ids().size()) != + GetRequiredFreshIdCount(ir_context, instruction)) { + return false; + } + + // All ids in |message_.fresh_ids| must be fresh. + for (uint32_t fresh_id : message_.fresh_ids()) { + if (!fuzzerutil::IsFreshId(ir_context, fresh_id)) { + return false; + } + } + + return true; +} + +void TransformationAddBitInstructionSynonym::Apply( + opt::IRContext* ir_context, + TransformationContext* transformation_context) const { + auto bit_instruction = + ir_context->get_def_use_mgr()->GetDef(message_.instruction_result_id()); + + switch (bit_instruction->opcode()) { + case SpvOpBitwiseOr: + case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: + AddBitwiseSynonym(ir_context, transformation_context, bit_instruction); + break; + default: + assert(false && "Should be unreachable."); + break; + } + + ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); +} + +protobufs::Transformation TransformationAddBitInstructionSynonym::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_add_bit_instruction_synonym() = message_; + return result; +} + +uint32_t TransformationAddBitInstructionSynonym::GetRequiredFreshIdCount( + opt::IRContext* ir_context, opt::Instruction* bit_instruction) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3557): + // Right now, only certain operations are supported. + switch (bit_instruction->opcode()) { + case SpvOpBitwiseOr: + case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: + return 4 * ir_context->get_type_mgr() + ->GetType(bit_instruction->type_id()) + ->AsInteger() + ->width() - + 1; + default: + assert(false && "Unsupported bit instruction."); + return 0; + } +} + +void TransformationAddBitInstructionSynonym::AddBitwiseSynonym( + opt::IRContext* ir_context, TransformationContext* transformation_context, + opt::Instruction* bit_instruction) const { + // Fresh id iterator. + auto fresh_id = message_.fresh_ids().begin(); + + // |width| is the bit width of operands (8, 16, 32 or 64). + const uint32_t width = ir_context->get_type_mgr() + ->GetType(bit_instruction->type_id()) + ->AsInteger() + ->width(); + + // |count| is the number of bits to be extracted and inserted at a time. + const uint32_t count = fuzzerutil::MaybeGetIntegerConstant( + ir_context, *transformation_context, {1}, 32, false, false); + + // |bitwise_ids| is the collection of OpBiwise* instructions that evaluate a + // pair of extracted bits. Those ids will be used to insert the result bits. + std::vector bitwise_ids(width); + + for (uint32_t i = 0; i < width; i++) { + // |offset| is the current bit index. + uint32_t offset = fuzzerutil::MaybeGetIntegerConstant( + ir_context, *transformation_context, {i}, 32, false, false); + + // |bit_extract_ids| are the two extracted bits from the operands. + std::vector bit_extract_ids; + + // Extracts the i-th bit from operands. + for (auto operand = bit_instruction->begin() + 2; + operand != bit_instruction->end(); operand++) { + auto bit_extract = + opt::Instruction(ir_context, SpvOpBitFieldUExtract, + bit_instruction->type_id(), *fresh_id++, + {{SPV_OPERAND_TYPE_ID, operand->words}, + {SPV_OPERAND_TYPE_ID, {offset}}, + {SPV_OPERAND_TYPE_ID, {count}}}); + bit_instruction->InsertBefore(MakeUnique(bit_extract)); + fuzzerutil::UpdateModuleIdBound(ir_context, bit_extract.result_id()); + bit_extract_ids.push_back(bit_extract.result_id()); + } + + // Applies |bit_instruction| to the pair of extracted bits. + auto bitwise = + opt::Instruction(ir_context, bit_instruction->opcode(), + bit_instruction->type_id(), *fresh_id++, + {{SPV_OPERAND_TYPE_ID, {bit_extract_ids[0]}}, + {SPV_OPERAND_TYPE_ID, {bit_extract_ids[1]}}}); + bit_instruction->InsertBefore(MakeUnique(bitwise)); + fuzzerutil::UpdateModuleIdBound(ir_context, bitwise.result_id()); + bitwise_ids[i] = bitwise.result_id(); + } + + // The first two ids in |bitwise_ids| are used to insert the first two bits of + // the result. + uint32_t offset = fuzzerutil::MaybeGetIntegerConstant( + ir_context, *transformation_context, {1}, 32, false, false); + auto bit_insert = opt::Instruction(ir_context, SpvOpBitFieldInsert, + bit_instruction->type_id(), *fresh_id++, + {{SPV_OPERAND_TYPE_ID, {bitwise_ids[0]}}, + {SPV_OPERAND_TYPE_ID, {bitwise_ids[1]}}, + {SPV_OPERAND_TYPE_ID, {offset}}, + {SPV_OPERAND_TYPE_ID, {count}}}); + bit_instruction->InsertBefore(MakeUnique(bit_insert)); + fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id()); + + // Inserts the remaining bits. + for (uint32_t i = 2; i < width; i++) { + offset = fuzzerutil::MaybeGetIntegerConstant( + ir_context, *transformation_context, {i}, 32, false, false); + bit_insert = + opt::Instruction(ir_context, SpvOpBitFieldInsert, + bit_instruction->type_id(), *fresh_id++, + {{SPV_OPERAND_TYPE_ID, {bit_insert.result_id()}}, + {SPV_OPERAND_TYPE_ID, {bitwise_ids[i]}}, + {SPV_OPERAND_TYPE_ID, {offset}}, + {SPV_OPERAND_TYPE_ID, {count}}}); + bit_instruction->InsertBefore(MakeUnique(bit_insert)); + fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id()); + } + + ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + + // Adds the fact that the last |bit_insert| instruction is synonymous of + // |bit_instruction|. + transformation_context->GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(bit_insert.result_id(), {}), + MakeDataDescriptor(bit_instruction->result_id(), {}), ir_context); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.h b/source/fuzz/transformation_add_bit_instruction_synonym.h new file mode 100644 index 000000000..1baf959a3 --- /dev/null +++ b/source/fuzz/transformation_add_bit_instruction_synonym.h @@ -0,0 +1,141 @@ +// Copyright (c) 2020 André Perez Maselco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_BIT_INSTRUCTION_SYNONYM_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_BIT_INSTRUCTION_SYNONYM_H_ + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/fuzz/transformation_context.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// clang-format off +// SPIR-V code to help understand the transformation. +// +// ---------------------------------------------------------------------------------------------------------------- +// | Reference shader | Variant shader | +// ---------------------------------------------------------------------------------------------------------------- +// | OpCapability Shader | OpCapability Shader | +// | OpCapability Int8 | OpCapability Int8 | +// | %1 = OpExtInstImport "GLSL.std.450" | %1 = OpExtInstImport "GLSL.std.450" | +// | OpMemoryModel Logical GLSL450 | OpMemoryModel Logical GLSL450 | +// | OpEntryPoint Vertex %7 "main" | OpEntryPoint Vertex %7 "main" | +// | | | +// | ; Types | ; Types | +// | %2 = OpTypeInt 8 0 | %2 = OpTypeInt 8 0 | +// | %3 = OpTypeVoid | %3 = OpTypeVoid | +// | %4 = OpTypeFunction %3 | %4 = OpTypeFunction %3 | +// | | | +// | ; Constants | ; Constants | +// | %5 = OpConstant %2 0 | %5 = OpConstant %2 0 | +// | %6 = OpConstant %2 1 | %6 = OpConstant %2 1 | +// | | %10 = OpConstant %2 2 | +// | ; main function | %11 = OpConstant %2 3 | +// | %7 = OpFunction %3 None %4 | %12 = OpConstant %2 4 | +// | %8 = OpLabel | %13 = OpConstant %2 5 | +// | %9 = OpBitwiseOr %2 %5 %6 ; bit instruction | %14 = OpConstant %2 6 | +// | OpReturn | %15 = OpConstant %2 7 | +// | OpFunctionEnd | | +// | | ; main function | +// | | %7 = OpFunction %3 None %4 | +// | | %8 = OpLabel | +// | | | +// | | %16 = OpBitFieldUExtract %2 %5 %5 %6 ; extracts bit 0 from %5 | +// | | %17 = OpBitFieldUExtract %2 %6 %5 %6 ; extracts bit 0 from %6 | +// | | %18 = OpBitwiseOr %2 %16 %17 | +// | | | +// | | %19 = OpBitFieldUExtract %2 %5 %6 %6 ; extracts bit 1 from %5 | +// | | %20 = OpBitFieldUExtract %2 %6 %6 %6 ; extracts bit 1 from %6 | +// | | %21 = OpBitwiseOr %2 %19 %20 | +// | | | +// | | %22 = OpBitFieldUExtract %2 %5 %10 %6 ; extracts bit 2 from %5 | +// | | %23 = OpBitFieldUExtract %2 %6 %10 %6 ; extracts bit 2 from %6 | +// | | %24 = OpBitwiseOr %2 %22 %23 | +// | | | +// | | %25 = OpBitFieldUExtract %2 %5 %11 %6 ; extracts bit 3 from %5 | +// | | %26 = OpBitFieldUExtract %2 %6 %11 %6 ; extracts bit 3 from %6 | +// | | %27 = OpBitwiseOr %2 %25 %26 | +// | | | +// | | %28 = OpBitFieldUExtract %2 %5 %12 %6 ; extracts bit 4 from %5 | +// | | %29 = OpBitFieldUExtract %2 %6 %12 %6 ; extracts bit 4 from %6 | +// | | %30 = OpBitwiseOr %2 %28 %29 | +// | | | +// | | %31 = OpBitFieldUExtract %2 %5 %13 %6 ; extracts bit 5 from %5 | +// | | %32 = OpBitFieldUExtract %2 %6 %13 %6 ; extracts bit 5 from %6 | +// | | %33 = OpBitwiseOr %2 %31 %32 | +// | | | +// | | %34 = OpBitFieldUExtract %2 %5 %14 %6 ; extracts bit 6 from %5 | +// | | %35 = OpBitFieldUExtract %2 %6 %14 %6 ; extracts bit 6 from %6 | +// | | %36 = OpBitwiseOr %2 %34 %35 | +// | | | +// | | %37 = OpBitFieldUExtract %2 %5 %15 %6 ; extracts bit 7 from %5 | +// | | %38 = OpBitFieldUExtract %2 %6 %15 %6 ; extracts bit 7 from %6 | +// | | %39 = OpBitwiseOr %2 %37 %38 | +// | | | +// | | %40 = OpBitFieldInsert %2 %18 %21 %6 %6 ; inserts bit 1 | +// | | %41 = OpBitFieldInsert %2 %40 %24 %10 %6 ; inserts bit 2 | +// | | %42 = OpBitFieldInsert %2 %41 %27 %11 %6 ; inserts bit 3 | +// | | %43 = OpBitFieldInsert %2 %42 %30 %12 %6 ; inserts bit 4 | +// | | %44 = OpBitFieldInsert %2 %43 %33 %13 %6 ; inserts bit 5 | +// | | %45 = OpBitFieldInsert %2 %44 %36 %14 %6 ; inserts bit 6 | +// | | %46 = OpBitFieldInsert %2 %45 %39 %15 %6 ; inserts bit 7 | +// | | %9 = OpBitwiseOr %2 %5 %6 ; bit instruction | +// | | OpReturn | +// | | OpFunctionEnd | +// ---------------------------------------------------------------------------------------------------------------- +// +// After the transformation, %9 and %46 will be synonymous. +// clang-format on +class TransformationAddBitInstructionSynonym : public Transformation { + public: + explicit TransformationAddBitInstructionSynonym( + const protobufs::TransformationAddBitInstructionSynonym& message); + + TransformationAddBitInstructionSynonym( + const uint32_t instruction_result_id, + const std::vector& fresh_ids); + + // - |message_.instruction_result_id| must be a bit instruction. + // - |message_.fresh_ids| must be fresh ids needed to apply the + // transformation. + bool IsApplicable( + opt::IRContext* ir_context, + const TransformationContext& transformation_context) const override; + + // Adds a bit instruction synonym. + void Apply(opt::IRContext* ir_context, + TransformationContext* transformation_context) const override; + + protobufs::Transformation ToMessage() const override; + + // Returns the number of fresh ids required to apply the transformation. + static uint32_t GetRequiredFreshIdCount(opt::IRContext* ir_context, + opt::Instruction* bit_instruction); + + private: + protobufs::TransformationAddBitInstructionSynonym message_; + + // Adds an OpBitwise* synonym. + void AddBitwiseSynonym(opt::IRContext* ir_context, + TransformationContext* transformation_context, + opt::Instruction* bitwise_instruction) const; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_BIT_INSTRUCTION_SYNONYM_H_ diff --git a/source/opcode.cpp b/source/opcode.cpp index c41e41d6c..8305bcf0a 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -731,3 +731,20 @@ bool spvOpcodeIsAccessChain(SpvOp opcode) { return false; } } + +bool spvOpcodeIsBit(SpvOp opcode) { + switch (opcode) { + case SpvOpShiftRightLogical: + case SpvOpShiftRightArithmetic: + case SpvOpShiftLeftLogical: + case SpvOpBitwiseOr: + case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: + case SpvOpNot: + case SpvOpBitReverse: + case SpvOpBitCount: + return true; + default: + return false; + } +} diff --git a/source/opcode.h b/source/opcode.h index d79909d26..3702cb35f 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -134,17 +134,20 @@ bool spvOpcodeIsDebug(SpvOp opcode); // where the order of the operands is irrelevant. bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode); -// Returns true for opcodes that represents linear algebra instructions. +// Returns true for opcodes that represent linear algebra instructions. bool spvOpcodeIsLinearAlgebra(SpvOp opcode); -// Returns true for opcodes that represents an image sample instruction. +// Returns true for opcodes that represent image sample instructions. bool spvOpcodeIsImageSample(SpvOp opcode); // Returns a vector containing the indices of the memory semantics // operands for |opcode|. std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode); -// Returns true for opcodes that represents access chain instructions. +// Returns true for opcodes that represent access chain instructions. bool spvOpcodeIsAccessChain(SpvOp opcode); +// Returns true for opcodes that represent bit instructions. +bool spvOpcodeIsBit(SpvOp opcode); + #endif // SOURCE_OPCODE_H_ diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt index 5bdb42ce7..66299f77a 100644 --- a/test/fuzz/CMakeLists.txt +++ b/test/fuzz/CMakeLists.txt @@ -31,6 +31,7 @@ if (${SPIRV_BUILD_FUZZER}) fuzzer_pass_test.cpp replayer_test.cpp transformation_access_chain_test.cpp + transformation_add_bit_instruction_synonym_test.cpp transformation_add_constant_boolean_test.cpp transformation_add_constant_composite_test.cpp transformation_add_constant_null_test.cpp diff --git a/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp new file mode 100644 index 000000000..642a12204 --- /dev/null +++ b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp @@ -0,0 +1,463 @@ +// Copyright (c) 2020 André Perez Maselco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_bit_instruction_synonym.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddBitInstructionSynonymTest, IsApplicable) { + std::string reference_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %37 "main" + +; Types + %2 = OpTypeInt 32 0 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + +; Constants + %5 = OpConstant %2 0 + %6 = OpConstant %2 1 + %7 = OpConstant %2 2 + %8 = OpConstant %2 3 + %9 = OpConstant %2 4 + %10 = OpConstant %2 5 + %11 = OpConstant %2 6 + %12 = OpConstant %2 7 + %13 = OpConstant %2 8 + %14 = OpConstant %2 9 + %15 = OpConstant %2 10 + %16 = OpConstant %2 11 + %17 = OpConstant %2 12 + %18 = OpConstant %2 13 + %19 = OpConstant %2 14 + %20 = OpConstant %2 15 + %21 = OpConstant %2 16 + %22 = OpConstant %2 17 + %23 = OpConstant %2 18 + %24 = OpConstant %2 19 + %25 = OpConstant %2 20 + %26 = OpConstant %2 21 + %27 = OpConstant %2 22 + %28 = OpConstant %2 23 + %29 = OpConstant %2 24 + %30 = OpConstant %2 25 + %31 = OpConstant %2 26 + %32 = OpConstant %2 27 + %33 = OpConstant %2 28 + %34 = OpConstant %2 29 + %35 = OpConstant %2 30 + %36 = OpConstant %2 31 + +; main function + %37 = OpFunction %3 None %4 + %38 = OpLabel + %39 = OpBitwiseOr %2 %5 %6 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, reference_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + spvtools::ValidatorOptions validator_options; + TransformationContext transformation_context(&fact_manager, + validator_options); + + // Tests undefined bit instruction. + auto transformation = TransformationAddBitInstructionSynonym( + 40, {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167}); + ASSERT_FALSE( + transformation.IsApplicable(context.get(), transformation_context)); + + // Tests false bit instruction. + transformation = TransformationAddBitInstructionSynonym( + 38, {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166}); + ASSERT_FALSE( + transformation.IsApplicable(context.get(), transformation_context)); + + // Tests the number of fresh ids being different than the necessary. + transformation = TransformationAddBitInstructionSynonym( + 39, + {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165}); + ASSERT_FALSE( + transformation.IsApplicable(context.get(), transformation_context)); + + // Tests non-fresh ids. + transformation = TransformationAddBitInstructionSynonym( + 39, {38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165}); + ASSERT_FALSE( + transformation.IsApplicable(context.get(), transformation_context)); + + // Tests applicable transformation. + transformation = TransformationAddBitInstructionSynonym( + 39, {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166}); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); +} + +TEST(TransformationAddBitInstructionSynonymTest, AddBitwiseSynonym) { + std::string reference_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %37 "main" + +; Types + %2 = OpTypeInt 32 0 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + +; Constants + %5 = OpConstant %2 0 + %6 = OpConstant %2 1 + %7 = OpConstant %2 2 + %8 = OpConstant %2 3 + %9 = OpConstant %2 4 + %10 = OpConstant %2 5 + %11 = OpConstant %2 6 + %12 = OpConstant %2 7 + %13 = OpConstant %2 8 + %14 = OpConstant %2 9 + %15 = OpConstant %2 10 + %16 = OpConstant %2 11 + %17 = OpConstant %2 12 + %18 = OpConstant %2 13 + %19 = OpConstant %2 14 + %20 = OpConstant %2 15 + %21 = OpConstant %2 16 + %22 = OpConstant %2 17 + %23 = OpConstant %2 18 + %24 = OpConstant %2 19 + %25 = OpConstant %2 20 + %26 = OpConstant %2 21 + %27 = OpConstant %2 22 + %28 = OpConstant %2 23 + %29 = OpConstant %2 24 + %30 = OpConstant %2 25 + %31 = OpConstant %2 26 + %32 = OpConstant %2 27 + %33 = OpConstant %2 28 + %34 = OpConstant %2 29 + %35 = OpConstant %2 30 + %36 = OpConstant %2 31 + +; main function + %37 = OpFunction %3 None %4 + %38 = OpLabel + %39 = OpBitwiseOr %2 %5 %6 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, reference_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + spvtools::ValidatorOptions validator_options; + TransformationContext transformation_context(&fact_manager, + validator_options); + + auto transformation = TransformationAddBitInstructionSynonym( + 39, {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166}); + transformation.Apply(context.get(), &transformation_context); + + std::string variant_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %37 "main" + +; Types + %2 = OpTypeInt 32 0 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + +; Constants + %5 = OpConstant %2 0 + %6 = OpConstant %2 1 + %7 = OpConstant %2 2 + %8 = OpConstant %2 3 + %9 = OpConstant %2 4 + %10 = OpConstant %2 5 + %11 = OpConstant %2 6 + %12 = OpConstant %2 7 + %13 = OpConstant %2 8 + %14 = OpConstant %2 9 + %15 = OpConstant %2 10 + %16 = OpConstant %2 11 + %17 = OpConstant %2 12 + %18 = OpConstant %2 13 + %19 = OpConstant %2 14 + %20 = OpConstant %2 15 + %21 = OpConstant %2 16 + %22 = OpConstant %2 17 + %23 = OpConstant %2 18 + %24 = OpConstant %2 19 + %25 = OpConstant %2 20 + %26 = OpConstant %2 21 + %27 = OpConstant %2 22 + %28 = OpConstant %2 23 + %29 = OpConstant %2 24 + %30 = OpConstant %2 25 + %31 = OpConstant %2 26 + %32 = OpConstant %2 27 + %33 = OpConstant %2 28 + %34 = OpConstant %2 29 + %35 = OpConstant %2 30 + %36 = OpConstant %2 31 + +; main function + %37 = OpFunction %3 None %4 + %38 = OpLabel + + %40 = OpBitFieldUExtract %2 %5 %5 %6 ; extracts bit 0 from %5 + %41 = OpBitFieldUExtract %2 %6 %5 %6 ; extracts bit 0 from %6 + %42 = OpBitwiseOr %2 %40 %41 + + %43 = OpBitFieldUExtract %2 %5 %6 %6 ; extracts bit 1 from %5 + %44 = OpBitFieldUExtract %2 %6 %6 %6 ; extracts bit 1 from %6 + %45 = OpBitwiseOr %2 %43 %44 + + %46 = OpBitFieldUExtract %2 %5 %7 %6 ; extracts bit 2 from %5 + %47 = OpBitFieldUExtract %2 %6 %7 %6 ; extracts bit 2 from %6 + %48 = OpBitwiseOr %2 %46 %47 + + %49 = OpBitFieldUExtract %2 %5 %8 %6 ; extracts bit 3 from %5 + %50 = OpBitFieldUExtract %2 %6 %8 %6 ; extracts bit 3 from %6 + %51 = OpBitwiseOr %2 %49 %50 + + %52 = OpBitFieldUExtract %2 %5 %9 %6 ; extracts bit 4 from %5 + %53 = OpBitFieldUExtract %2 %6 %9 %6 ; extracts bit 4 from %6 + %54 = OpBitwiseOr %2 %52 %53 + + %55 = OpBitFieldUExtract %2 %5 %10 %6 ; extracts bit 5 from %5 + %56 = OpBitFieldUExtract %2 %6 %10 %6 ; extracts bit 5 from %6 + %57 = OpBitwiseOr %2 %55 %56 + + %58 = OpBitFieldUExtract %2 %5 %11 %6 ; extracts bit 6 from %5 + %59 = OpBitFieldUExtract %2 %6 %11 %6 ; extracts bit 6 from %6 + %60 = OpBitwiseOr %2 %58 %59 + + %61 = OpBitFieldUExtract %2 %5 %12 %6 ; extracts bit 7 from %5 + %62 = OpBitFieldUExtract %2 %6 %12 %6 ; extracts bit 7 from %6 + %63 = OpBitwiseOr %2 %61 %62 + + %64 = OpBitFieldUExtract %2 %5 %13 %6 ; extracts bit 8 from %5 + %65 = OpBitFieldUExtract %2 %6 %13 %6 ; extracts bit 8 from %6 + %66 = OpBitwiseOr %2 %64 %65 + + %67 = OpBitFieldUExtract %2 %5 %14 %6 ; extracts bit 9 from %5 + %68 = OpBitFieldUExtract %2 %6 %14 %6 ; extracts bit 9 from %6 + %69 = OpBitwiseOr %2 %67 %68 + + %70 = OpBitFieldUExtract %2 %5 %15 %6 ; extracts bit 10 from %5 + %71 = OpBitFieldUExtract %2 %6 %15 %6 ; extracts bit 10 from %6 + %72 = OpBitwiseOr %2 %70 %71 + + %73 = OpBitFieldUExtract %2 %5 %16 %6 ; extracts bit 11 from %5 + %74 = OpBitFieldUExtract %2 %6 %16 %6 ; extracts bit 11 from %6 + %75 = OpBitwiseOr %2 %73 %74 + + %76 = OpBitFieldUExtract %2 %5 %17 %6 ; extracts bit 12 from %5 + %77 = OpBitFieldUExtract %2 %6 %17 %6 ; extracts bit 12 from %6 + %78 = OpBitwiseOr %2 %76 %77 + + %79 = OpBitFieldUExtract %2 %5 %18 %6 ; extracts bit 13 from %5 + %80 = OpBitFieldUExtract %2 %6 %18 %6 ; extracts bit 13 from %6 + %81 = OpBitwiseOr %2 %79 %80 + + %82 = OpBitFieldUExtract %2 %5 %19 %6 ; extracts bit 14 from %5 + %83 = OpBitFieldUExtract %2 %6 %19 %6 ; extracts bit 14 from %6 + %84 = OpBitwiseOr %2 %82 %83 + + %85 = OpBitFieldUExtract %2 %5 %20 %6 ; extracts bit 15 from %5 + %86 = OpBitFieldUExtract %2 %6 %20 %6 ; extracts bit 15 from %6 + %87 = OpBitwiseOr %2 %85 %86 + + %88 = OpBitFieldUExtract %2 %5 %21 %6 ; extracts bit 16 from %5 + %89 = OpBitFieldUExtract %2 %6 %21 %6 ; extracts bit 16 from %6 + %90 = OpBitwiseOr %2 %88 %89 + + %91 = OpBitFieldUExtract %2 %5 %22 %6 ; extracts bit 17 from %5 + %92 = OpBitFieldUExtract %2 %6 %22 %6 ; extracts bit 17 from %6 + %93 = OpBitwiseOr %2 %91 %92 + + %94 = OpBitFieldUExtract %2 %5 %23 %6 ; extracts bit 18 from %5 + %95 = OpBitFieldUExtract %2 %6 %23 %6 ; extracts bit 18 from %6 + %96 = OpBitwiseOr %2 %94 %95 + + %97 = OpBitFieldUExtract %2 %5 %24 %6 ; extracts bit 19 from %5 + %98 = OpBitFieldUExtract %2 %6 %24 %6 ; extracts bit 19 from %6 + %99 = OpBitwiseOr %2 %97 %98 + + %100 = OpBitFieldUExtract %2 %5 %25 %6 ; extracts bit 20 from %5 + %101 = OpBitFieldUExtract %2 %6 %25 %6 ; extracts bit 20 from %6 + %102 = OpBitwiseOr %2 %100 %101 + + %103 = OpBitFieldUExtract %2 %5 %26 %6 ; extracts bit 21 from %5 + %104 = OpBitFieldUExtract %2 %6 %26 %6 ; extracts bit 21 from %6 + %105 = OpBitwiseOr %2 %103 %104 + + %106 = OpBitFieldUExtract %2 %5 %27 %6 ; extracts bit 22 from %5 + %107 = OpBitFieldUExtract %2 %6 %27 %6 ; extracts bit 22 from %6 + %108 = OpBitwiseOr %2 %106 %107 + + %109 = OpBitFieldUExtract %2 %5 %28 %6 ; extracts bit 23 from %5 + %110 = OpBitFieldUExtract %2 %6 %28 %6 ; extracts bit 23 from %6 + %111 = OpBitwiseOr %2 %109 %110 + + %112 = OpBitFieldUExtract %2 %5 %29 %6 ; extracts bit 24 from %5 + %113 = OpBitFieldUExtract %2 %6 %29 %6 ; extracts bit 24 from %6 + %114 = OpBitwiseOr %2 %112 %113 + + %115 = OpBitFieldUExtract %2 %5 %30 %6 ; extracts bit 25 from %5 + %116 = OpBitFieldUExtract %2 %6 %30 %6 ; extracts bit 25 from %6 + %117 = OpBitwiseOr %2 %115 %116 + + %118 = OpBitFieldUExtract %2 %5 %31 %6 ; extracts bit 26 from %5 + %119 = OpBitFieldUExtract %2 %6 %31 %6 ; extracts bit 26 from %6 + %120 = OpBitwiseOr %2 %118 %119 + + %121 = OpBitFieldUExtract %2 %5 %32 %6 ; extracts bit 27 from %5 + %122 = OpBitFieldUExtract %2 %6 %32 %6 ; extracts bit 27 from %6 + %123 = OpBitwiseOr %2 %121 %122 + + %124 = OpBitFieldUExtract %2 %5 %33 %6 ; extracts bit 28 from %5 + %125 = OpBitFieldUExtract %2 %6 %33 %6 ; extracts bit 28 from %6 + %126 = OpBitwiseOr %2 %124 %125 + + %127 = OpBitFieldUExtract %2 %5 %34 %6 ; extracts bit 29 from %5 + %128 = OpBitFieldUExtract %2 %6 %34 %6 ; extracts bit 29 from %6 + %129 = OpBitwiseOr %2 %127 %128 + + %130 = OpBitFieldUExtract %2 %5 %35 %6 ; extracts bit 30 from %5 + %131 = OpBitFieldUExtract %2 %6 %35 %6 ; extracts bit 30 from %6 + %132 = OpBitwiseOr %2 %130 %131 + + %133 = OpBitFieldUExtract %2 %5 %36 %6 ; extracts bit 31 from %5 + %134 = OpBitFieldUExtract %2 %6 %36 %6 ; extracts bit 31 from %6 + %135 = OpBitwiseOr %2 %133 %134 + + %136 = OpBitFieldInsert %2 %42 %45 %6 %6 ; inserts bit 1 + %137 = OpBitFieldInsert %2 %136 %48 %7 %6 ; inserts bit 2 + %138 = OpBitFieldInsert %2 %137 %51 %8 %6 ; inserts bit 3 + %139 = OpBitFieldInsert %2 %138 %54 %9 %6 ; inserts bit 4 + %140 = OpBitFieldInsert %2 %139 %57 %10 %6 ; inserts bit 5 + %141 = OpBitFieldInsert %2 %140 %60 %11 %6 ; inserts bit 6 + %142 = OpBitFieldInsert %2 %141 %63 %12 %6 ; inserts bit 7 + %143 = OpBitFieldInsert %2 %142 %66 %13 %6 ; inserts bit 8 + %144 = OpBitFieldInsert %2 %143 %69 %14 %6 ; inserts bit 9 + %145 = OpBitFieldInsert %2 %144 %72 %15 %6 ; inserts bit 10 + %146 = OpBitFieldInsert %2 %145 %75 %16 %6 ; inserts bit 11 + %147 = OpBitFieldInsert %2 %146 %78 %17 %6 ; inserts bit 12 + %148 = OpBitFieldInsert %2 %147 %81 %18 %6 ; inserts bit 13 + %149 = OpBitFieldInsert %2 %148 %84 %19 %6 ; inserts bit 14 + %150 = OpBitFieldInsert %2 %149 %87 %20 %6 ; inserts bit 15 + %151 = OpBitFieldInsert %2 %150 %90 %21 %6 ; inserts bit 16 + %152 = OpBitFieldInsert %2 %151 %93 %22 %6 ; inserts bit 17 + %153 = OpBitFieldInsert %2 %152 %96 %23 %6 ; inserts bit 18 + %154 = OpBitFieldInsert %2 %153 %99 %24 %6 ; inserts bit 19 + %155 = OpBitFieldInsert %2 %154 %102 %25 %6 ; inserts bit 20 + %156 = OpBitFieldInsert %2 %155 %105 %26 %6 ; inserts bit 21 + %157 = OpBitFieldInsert %2 %156 %108 %27 %6 ; inserts bit 22 + %158 = OpBitFieldInsert %2 %157 %111 %28 %6 ; inserts bit 23 + %159 = OpBitFieldInsert %2 %158 %114 %29 %6 ; inserts bit 24 + %160 = OpBitFieldInsert %2 %159 %117 %30 %6 ; inserts bit 25 + %161 = OpBitFieldInsert %2 %160 %120 %31 %6 ; inserts bit 26 + %162 = OpBitFieldInsert %2 %161 %123 %32 %6 ; inserts bit 27 + %163 = OpBitFieldInsert %2 %162 %126 %33 %6 ; inserts bit 28 + %164 = OpBitFieldInsert %2 %163 %129 %34 %6 ; inserts bit 29 + %165 = OpBitFieldInsert %2 %164 %132 %35 %6 ; inserts bit 30 + %166 = OpBitFieldInsert %2 %165 %135 %36 %6 ; inserts bit 31 + %39 = OpBitwiseOr %2 %5 %6 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(IsEqual(env, variant_shader, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(166, {}), + MakeDataDescriptor(39, {}))); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools