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.
This commit is contained in:
André Perez 2020-09-15 19:36:23 -03:00 committed by GitHub
parent e7c84feda0
commit e8ce4355ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1030 additions and 3 deletions

View File

@ -52,6 +52,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_context.h fuzzer_context.h
fuzzer_pass.h fuzzer_pass.h
fuzzer_pass_add_access_chains.h fuzzer_pass_add_access_chains.h
fuzzer_pass_add_bit_instruction_synonyms.h
fuzzer_pass_add_composite_inserts.h fuzzer_pass_add_composite_inserts.h
fuzzer_pass_add_composite_types.h fuzzer_pass_add_composite_types.h
fuzzer_pass_add_copy_memory.h fuzzer_pass_add_copy_memory.h
@ -124,6 +125,7 @@ if(SPIRV_BUILD_FUZZER)
shrinker.h shrinker.h
transformation.h transformation.h
transformation_access_chain.h transformation_access_chain.h
transformation_add_bit_instruction_synonym.h
transformation_add_constant_boolean.h transformation_add_constant_boolean.h
transformation_add_constant_composite.h transformation_add_constant_composite.h
transformation_add_constant_null.h transformation_add_constant_null.h
@ -217,6 +219,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_context.cpp fuzzer_context.cpp
fuzzer_pass.cpp fuzzer_pass.cpp
fuzzer_pass_add_access_chains.cpp fuzzer_pass_add_access_chains.cpp
fuzzer_pass_add_bit_instruction_synonyms.cpp
fuzzer_pass_add_composite_inserts.cpp fuzzer_pass_add_composite_inserts.cpp
fuzzer_pass_add_composite_types.cpp fuzzer_pass_add_composite_types.cpp
fuzzer_pass_add_copy_memory.cpp fuzzer_pass_add_copy_memory.cpp
@ -288,6 +291,7 @@ if(SPIRV_BUILD_FUZZER)
shrinker.cpp shrinker.cpp
transformation.cpp transformation.cpp
transformation_access_chain.cpp transformation_access_chain.cpp
transformation_add_bit_instruction_synonym.cpp
transformation_add_constant_boolean.cpp transformation_add_constant_boolean.cpp
transformation_add_constant_composite.cpp transformation_add_constant_composite.cpp
transformation_add_constant_null.cpp transformation_add_constant_null.cpp

View File

@ -20,6 +20,7 @@
#include "source/fuzz/fact_manager/fact_manager.h" #include "source/fuzz/fact_manager/fact_manager.h"
#include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/fuzzer_pass_add_access_chains.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_inserts.h"
#include "source/fuzz/fuzzer_pass_add_composite_types.h" #include "source/fuzz/fuzzer_pass_add_composite_types.h"
#include "source/fuzz/fuzzer_pass_add_copy_memory.h" #include "source/fuzz/fuzzer_pass_add_copy_memory.h"
@ -205,6 +206,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
MaybeAddPass<FuzzerPassAddAccessChains>( MaybeAddPass<FuzzerPassAddAccessChains>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddBitInstructionSynonyms>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddCompositeInserts>( MaybeAddPass<FuzzerPassAddCompositeInserts>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);

View File

@ -27,6 +27,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingAccessChain = {5, 50};
const std::pair<uint32_t, uint32_t> kChanceOfAddingAnotherStructField = {20, const std::pair<uint32_t, uint32_t> kChanceOfAddingAnotherStructField = {20,
90}; 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90}; const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingBitInstructionSynonym = {20,
90};
const std::pair<uint32_t, uint32_t> const std::pair<uint32_t, uint32_t>
kChanceOfAddingBothBranchesWhenReplacingOpSelect = {40, 60}; kChanceOfAddingBothBranchesWhenReplacingOpSelect = {40, 60};
const std::pair<uint32_t, uint32_t> kChanceOfAddingCompositeInsert = {20, 50}; const std::pair<uint32_t, uint32_t> kChanceOfAddingCompositeInsert = {20, 50};
@ -172,6 +174,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField); ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField);
chance_of_adding_array_or_struct_type_ = chance_of_adding_array_or_struct_type_ =
ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType); ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType);
chance_of_adding_bit_instruction_synonym_ =
ChooseBetweenMinAndMax(kChanceOfAddingBitInstructionSynonym);
chance_of_adding_both_branches_when_replacing_opselect_ = chance_of_adding_both_branches_when_replacing_opselect_ =
ChooseBetweenMinAndMax(kChanceOfAddingBothBranchesWhenReplacingOpSelect); ChooseBetweenMinAndMax(kChanceOfAddingBothBranchesWhenReplacingOpSelect);
chance_of_adding_composite_insert_ = chance_of_adding_composite_insert_ =

View File

@ -115,6 +115,9 @@ class FuzzerContext {
uint32_t GetChanceOfAddingArrayOrStructType() { uint32_t GetChanceOfAddingArrayOrStructType() {
return chance_of_adding_array_or_struct_type_; return chance_of_adding_array_or_struct_type_;
} }
uint32_t GetChanceOfAddingBitInstructionSynonym() {
return chance_of_adding_bit_instruction_synonym_;
}
uint32_t GetChanceOfAddingBothBranchesWhenReplacingOpSelect() { uint32_t GetChanceOfAddingBothBranchesWhenReplacingOpSelect() {
return chance_of_adding_both_branches_when_replacing_opselect_; 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_access_chain_;
uint32_t chance_of_adding_another_struct_field_; uint32_t chance_of_adding_another_struct_field_;
uint32_t chance_of_adding_array_or_struct_type_; 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_both_branches_when_replacing_opselect_;
uint32_t chance_of_adding_composite_insert_; uint32_t chance_of_adding_composite_insert_;
uint32_t chance_of_adding_copy_memory_; uint32_t chance_of_adding_copy_memory_;

View File

@ -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

View File

@ -0,0 +1,41 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_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_

View File

@ -496,6 +496,7 @@ message Transformation {
TransformationReplaceOpSelectWithConditionalBranch replace_opselect_with_conditional_branch = 74; TransformationReplaceOpSelectWithConditionalBranch replace_opselect_with_conditional_branch = 74;
TransformationDuplicateRegionWithSelection duplicate_region_with_selection = 75; TransformationDuplicateRegionWithSelection duplicate_region_with_selection = 75;
TransformationFlattenConditionalBranch flatten_conditional_branch = 76; TransformationFlattenConditionalBranch flatten_conditional_branch = 76;
TransformationAddBitInstructionSynonym add_bit_instruction_synonym = 77;
// Add additional option using the next available number. // 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 { message TransformationAddConstantBoolean {
// Supports adding the constants true and false to a module, which may be // Supports adding the constants true and false to a module, which may be

View File

@ -18,6 +18,7 @@
#include "source/fuzz/fuzzer_util.h" #include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/transformation_access_chain.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_boolean.h"
#include "source/fuzz/transformation_add_constant_composite.h" #include "source/fuzz/transformation_add_constant_composite.h"
#include "source/fuzz/transformation_add_constant_null.h" #include "source/fuzz/transformation_add_constant_null.h"
@ -105,6 +106,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
switch (message.transformation_case()) { switch (message.transformation_case()) {
case protobufs::Transformation::TransformationCase::kAccessChain: case protobufs::Transformation::TransformationCase::kAccessChain:
return MakeUnique<TransformationAccessChain>(message.access_chain()); return MakeUnique<TransformationAccessChain>(message.access_chain());
case protobufs::Transformation::TransformationCase::
kAddBitInstructionSynonym:
return MakeUnique<TransformationAddBitInstructionSynonym>(
message.add_bit_instruction_synonym());
case protobufs::Transformation::TransformationCase::kAddConstantBoolean: case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
return MakeUnique<TransformationAddConstantBoolean>( return MakeUnique<TransformationAddConstantBoolean>(
message.add_constant_boolean()); message.add_constant_boolean());

View File

@ -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<uint32_t>& fresh_ids) {
message_.set_instruction_result_id(instruction_result_id);
*message_.mutable_fresh_ids() =
google::protobuf::RepeatedField<google::protobuf::uint32>(
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<uint32_t>(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<uint32_t> 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<uint32_t> 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<opt::Instruction>(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<opt::Instruction>(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<opt::Instruction>(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<opt::Instruction>(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

View File

@ -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<uint32_t>& 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_

View File

@ -731,3 +731,20 @@ bool spvOpcodeIsAccessChain(SpvOp opcode) {
return false; 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;
}
}

View File

@ -134,17 +134,20 @@ bool spvOpcodeIsDebug(SpvOp opcode);
// where the order of the operands is irrelevant. // where the order of the operands is irrelevant.
bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode); 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); 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); bool spvOpcodeIsImageSample(SpvOp opcode);
// Returns a vector containing the indices of the memory semantics <id> // Returns a vector containing the indices of the memory semantics <id>
// operands for |opcode|. // operands for |opcode|.
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode); std::vector<uint32_t> 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); bool spvOpcodeIsAccessChain(SpvOp opcode);
// Returns true for opcodes that represent bit instructions.
bool spvOpcodeIsBit(SpvOp opcode);
#endif // SOURCE_OPCODE_H_ #endif // SOURCE_OPCODE_H_

View File

@ -31,6 +31,7 @@ if (${SPIRV_BUILD_FUZZER})
fuzzer_pass_test.cpp fuzzer_pass_test.cpp
replayer_test.cpp replayer_test.cpp
transformation_access_chain_test.cpp transformation_access_chain_test.cpp
transformation_add_bit_instruction_synonym_test.cpp
transformation_add_constant_boolean_test.cpp transformation_add_constant_boolean_test.cpp
transformation_add_constant_composite_test.cpp transformation_add_constant_composite_test.cpp
transformation_add_constant_null_test.cpp transformation_add_constant_null_test.cpp

View File

@ -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