spirv-fuzz: TransformationReplaceAddSubMulWithCarryingExtended (#3598)
Replaces OpIAdd with OpIAddCarry, OpISub with OpISubBorrow, OpIMul with OpUMulExtended or OpSMulExtended and stores the result into a fresh_id representing a structure. Extracts the first element of the result into the original result_id. This value is the same as the result of the original instruction. Fixes #3577
This commit is contained in:
Родитель
6d7f34fbfe
Коммит
7b2dd11dda
|
@ -76,6 +76,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
fuzzer_pass_permute_instructions.h
|
||||
fuzzer_pass_permute_phi_operands.h
|
||||
fuzzer_pass_push_ids_through_variables.h
|
||||
fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h
|
||||
fuzzer_pass_replace_copy_memories_with_loads_stores.h
|
||||
fuzzer_pass_replace_copy_objects_with_stores_loads.h
|
||||
fuzzer_pass_replace_linear_algebra_instructions.h
|
||||
|
@ -143,6 +144,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
transformation_permute_phi_operands.h
|
||||
transformation_push_id_through_variable.h
|
||||
transformation_record_synonymous_constants.h
|
||||
transformation_replace_add_sub_mul_with_carrying_extended.h
|
||||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
transformation_replace_constant_with_uniform.h
|
||||
transformation_replace_copy_memory_with_load_store.h
|
||||
|
@ -211,6 +213,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
fuzzer_pass_permute_instructions.cpp
|
||||
fuzzer_pass_permute_phi_operands.cpp
|
||||
fuzzer_pass_push_ids_through_variables.cpp
|
||||
fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp
|
||||
fuzzer_pass_replace_copy_memories_with_loads_stores.cpp
|
||||
fuzzer_pass_replace_copy_objects_with_stores_loads.cpp
|
||||
fuzzer_pass_replace_linear_algebra_instructions.cpp
|
||||
|
@ -277,6 +280,7 @@ if(SPIRV_BUILD_FUZZER)
|
|||
transformation_permute_phi_operands.cpp
|
||||
transformation_push_id_through_variable.cpp
|
||||
transformation_record_synonymous_constants.cpp
|
||||
transformation_replace_add_sub_mul_with_carrying_extended.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
transformation_replace_constant_with_uniform.cpp
|
||||
transformation_replace_copy_memory_with_load_store.cpp
|
||||
|
|
|
@ -82,6 +82,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfPermutingInstructions = {20, 70};
|
|||
const std::pair<uint32_t, uint32_t> kChanceOfPermutingParameters = {30, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfPermutingPhiOperands = {30, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfPushingIdThroughVariable = {5, 50};
|
||||
const std::pair<uint32_t, uint32_t>
|
||||
kChanceOfReplacingAddSubMulWithCarryingExtended = {20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingCopyMemoryWithLoadStore =
|
||||
{20, 90};
|
||||
const std::pair<uint32_t, uint32_t> kChanceOfReplacingCopyObjectWithStoreLoad =
|
||||
|
@ -227,6 +229,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
|
|||
ChooseBetweenMinAndMax(kChanceOfPermutingPhiOperands);
|
||||
chance_of_pushing_id_through_variable_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfPushingIdThroughVariable);
|
||||
chance_of_replacing_add_sub_mul_with_carrying_extended_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfReplacingAddSubMulWithCarryingExtended);
|
||||
chance_of_replacing_copy_memory_with_load_store_ =
|
||||
ChooseBetweenMinAndMax(kChanceOfReplacingCopyMemoryWithLoadStore);
|
||||
chance_of_replacing_copyobject_with_store_load_ =
|
||||
|
|
|
@ -221,6 +221,9 @@ class FuzzerContext {
|
|||
uint32_t GetChanceOfPushingIdThroughVariable() {
|
||||
return chance_of_pushing_id_through_variable_;
|
||||
}
|
||||
uint32_t GetChanceOfReplacingAddSubMulWithCarryingExtended() {
|
||||
return chance_of_replacing_add_sub_mul_with_carrying_extended_;
|
||||
}
|
||||
uint32_t GetChanceOfReplacingCopyMemoryWithLoadStore() {
|
||||
return chance_of_replacing_copy_memory_with_load_store_;
|
||||
}
|
||||
|
@ -375,6 +378,7 @@ class FuzzerContext {
|
|||
uint32_t chance_of_permuting_parameters_;
|
||||
uint32_t chance_of_permuting_phi_operands_;
|
||||
uint32_t chance_of_pushing_id_through_variable_;
|
||||
uint32_t chance_of_replacing_add_sub_mul_with_carrying_extended_;
|
||||
uint32_t chance_of_replacing_copy_memory_with_load_store_;
|
||||
uint32_t chance_of_replacing_copyobject_with_store_load_;
|
||||
uint32_t chance_of_replacing_id_with_synonym_;
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
namespace {
|
||||
const uint32_t kArithmeticInstructionIndexLeftInOperand = 0;
|
||||
} // namespace
|
||||
|
||||
FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::
|
||||
FuzzerPassReplaceAddsSubsMulsWithCarryingExtended(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations)
|
||||
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
|
||||
transformations) {}
|
||||
|
||||
FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::
|
||||
~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() = default;
|
||||
|
||||
void FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::Apply() {
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
for (auto& block : function) {
|
||||
for (auto& instruction : block) {
|
||||
// Randomly decide whether to apply the transformation.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()
|
||||
->GetChanceOfReplacingAddSubMulWithCarryingExtended())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the transformation can be applied to this instruction.
|
||||
if (!TransformationReplaceAddSubMulWithCarryingExtended::
|
||||
IsInstructionSuitable(GetIRContext(), instruction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the operand type id. We know that both operands have the same
|
||||
// type.
|
||||
uint32_t operand_type_id =
|
||||
GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(instruction.GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexLeftInOperand))
|
||||
->type_id();
|
||||
|
||||
// Ensure the required struct type exists. The struct type is based on
|
||||
// the operand type.
|
||||
FindOrCreateStructType({operand_type_id, operand_type_id});
|
||||
|
||||
ApplyTransformation(TransformationReplaceAddSubMulWithCarryingExtended(
|
||||
GetFuzzerContext()->GetFreshId(), instruction.result_id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H
|
||||
#define SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// A fuzzer pass that replaces instructions OpIAdd, OpISub, OpIMul with pairs of
|
||||
// instructions. The first one (OpIAddCarry, OpISubBorrow, OpUMulExtended,
|
||||
// OpSMulExtended) computes the result into a struct. The second one extracts
|
||||
// the appropriate component from the struct to yield the original result.
|
||||
class FuzzerPassReplaceAddsSubsMulsWithCarryingExtended : public FuzzerPass {
|
||||
public:
|
||||
FuzzerPassReplaceAddsSubsMulsWithCarryingExtended(
|
||||
opt::IRContext* ir_context, TransformationContext* transformation_context,
|
||||
FuzzerContext* fuzzer_context,
|
||||
protobufs::TransformationSequence* transformations);
|
||||
|
||||
~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() override;
|
||||
|
||||
void Apply() override;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SPIRV_TOOLS_FUZZER_PASS_REPLACE_ADDS_SUBS_MULS_WITH_CARRYING_EXTENDED_H
|
|
@ -410,6 +410,7 @@ message Transformation {
|
|||
TransformationAddLoopPreheader add_loop_preheader = 63;
|
||||
TransformationMoveInstructionDown move_instruction_down = 64;
|
||||
TransformationMakeVectorOperationDynamic make_vector_operation_dynamic = 65;
|
||||
TransformationReplaceAddSubMulWithCarryingExtended replace_add_sub_mul_with_carrying_extended = 66;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
|
@ -1285,6 +1286,24 @@ message TransformationRecordSynonymousConstants {
|
|||
|
||||
}
|
||||
|
||||
message TransformationReplaceAddSubMulWithCarryingExtended {
|
||||
|
||||
// Replaces OpIAdd with OpIAddCarry, OpISub with OpISubBorrow, OpIMul
|
||||
// with OpUMulExtended or OpSMulExtended (depending on the signedness
|
||||
// of the operands) and stores the result into a |struct_fresh_id|.
|
||||
// In the original instruction the result type id and the type ids of
|
||||
// the operands must be the same. Then the transformation extracts
|
||||
// the first element of the result into the original |result_id|.
|
||||
// This value is the same as the result of the original instruction.
|
||||
|
||||
// The fresh id of the intermediate result.
|
||||
uint32 struct_fresh_id = 1;
|
||||
|
||||
// The result id of the original instruction.
|
||||
uint32 result_id = 2;
|
||||
|
||||
}
|
||||
|
||||
message TransformationReplaceParameterWithGlobal {
|
||||
|
||||
// Removes parameter with result id |parameter_id| from its function
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "source/fuzz/transformation_permute_phi_operands.h"
|
||||
#include "source/fuzz/transformation_push_id_through_variable.h"
|
||||
#include "source/fuzz/transformation_record_synonymous_constants.h"
|
||||
#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/fuzz/transformation_replace_copy_memory_with_load_store.h"
|
||||
|
@ -221,9 +222,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
|||
return MakeUnique<TransformationRecordSynonymousConstants>(
|
||||
message.record_synonymous_constants());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceParameterWithGlobal:
|
||||
return MakeUnique<TransformationReplaceParameterWithGlobal>(
|
||||
message.replace_parameter_with_global());
|
||||
kReplaceAddSubMulWithCarryingExtended:
|
||||
return MakeUnique<TransformationReplaceAddSubMulWithCarryingExtended>(
|
||||
message.replace_add_sub_mul_with_carrying_extended());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceBooleanConstantWithConstantBinary:
|
||||
return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(
|
||||
|
@ -251,6 +252,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
|||
kReplaceLoadStoreWithCopyMemory:
|
||||
return MakeUnique<TransformationReplaceLoadStoreWithCopyMemory>(
|
||||
message.replace_load_store_with_copy_memory());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceParameterWithGlobal:
|
||||
return MakeUnique<TransformationReplaceParameterWithGlobal>(
|
||||
message.replace_parameter_with_global());
|
||||
case protobufs::Transformation::TransformationCase::
|
||||
kReplaceParamsWithStruct:
|
||||
return MakeUnique<TransformationReplaceParamsWithStruct>(
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
namespace {
|
||||
const uint32_t kOpCompositeExtractIndexLowOrderBits = 0;
|
||||
const uint32_t kArithmeticInstructionIndexLeftInOperand = 0;
|
||||
const uint32_t kArithmeticInstructionIndexRightInOperand = 1;
|
||||
} // namespace
|
||||
|
||||
TransformationReplaceAddSubMulWithCarryingExtended::
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(
|
||||
const spvtools::fuzz::protobufs::
|
||||
TransformationReplaceAddSubMulWithCarryingExtended& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationReplaceAddSubMulWithCarryingExtended::
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(uint32_t struct_fresh_id,
|
||||
uint32_t result_id) {
|
||||
message_.set_struct_fresh_id(struct_fresh_id);
|
||||
message_.set_result_id(result_id);
|
||||
}
|
||||
|
||||
bool TransformationReplaceAddSubMulWithCarryingExtended::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
// |message_.struct_fresh_id| must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.struct_fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |message_.result_id| must refer to a suitable OpIAdd, OpISub or OpIMul
|
||||
// instruction. The instruction must be defined.
|
||||
auto instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.result_id());
|
||||
if (instruction == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!TransformationReplaceAddSubMulWithCarryingExtended::
|
||||
IsInstructionSuitable(ir_context, *instruction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The struct type for holding the intermediate result must exist in the
|
||||
// module. The struct type is based on the operand type.
|
||||
uint32_t operand_type_id = ir_context->get_def_use_mgr()
|
||||
->GetDef(instruction->GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexLeftInOperand))
|
||||
->type_id();
|
||||
|
||||
uint32_t struct_type_id = fuzzerutil::MaybeGetStructType(
|
||||
ir_context, {operand_type_id, operand_type_id});
|
||||
if (struct_type_id == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransformationReplaceAddSubMulWithCarryingExtended::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
// |message_.struct_fresh_id| must be fresh.
|
||||
assert(fuzzerutil::IsFreshId(ir_context, message_.struct_fresh_id()) &&
|
||||
"|message_.struct_fresh_id| must be fresh");
|
||||
|
||||
// Get the signedness of an operand if it is an int or the signedness of a
|
||||
// component if it is a vector.
|
||||
auto type_id =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.result_id())->type_id();
|
||||
auto type = ir_context->get_type_mgr()->GetType(type_id);
|
||||
bool operand_is_signed;
|
||||
if (type->kind() == opt::analysis::Type::kVector) {
|
||||
auto operand_type = type->AsVector()->element_type();
|
||||
operand_is_signed = operand_type->AsInteger()->IsSigned();
|
||||
} else {
|
||||
operand_is_signed = type->AsInteger()->IsSigned();
|
||||
}
|
||||
|
||||
auto original_instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.result_id());
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.struct_fresh_id());
|
||||
|
||||
// Determine the opcode of the new instruction that computes the result into a
|
||||
// struct.
|
||||
SpvOp new_instruction_opcode;
|
||||
|
||||
switch (original_instruction->opcode()) {
|
||||
case SpvOpIAdd:
|
||||
new_instruction_opcode = SpvOpIAddCarry;
|
||||
break;
|
||||
case SpvOpISub:
|
||||
new_instruction_opcode = SpvOpISubBorrow;
|
||||
break;
|
||||
case SpvOpIMul:
|
||||
if (!operand_is_signed) {
|
||||
new_instruction_opcode = SpvOpUMulExtended;
|
||||
} else {
|
||||
new_instruction_opcode = SpvOpSMulExtended;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false && "The instruction has an unsupported opcode.");
|
||||
return;
|
||||
}
|
||||
// Get the type of struct type id holding the intermediate result based on the
|
||||
// operand type.
|
||||
uint32_t operand_type_id =
|
||||
ir_context->get_def_use_mgr()
|
||||
->GetDef(original_instruction->GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexLeftInOperand))
|
||||
->type_id();
|
||||
|
||||
uint32_t struct_type_id = fuzzerutil::MaybeGetStructType(
|
||||
ir_context, {operand_type_id, operand_type_id});
|
||||
// Avoid unused variables in release mode.
|
||||
(void)struct_type_id;
|
||||
assert(struct_type_id && "The struct type must exist in the module.");
|
||||
|
||||
// Insert the new instruction that computes the result into a struct before
|
||||
// the |original_instruction|.
|
||||
original_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, new_instruction_opcode, struct_type_id,
|
||||
message_.struct_fresh_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID,
|
||||
{original_instruction->GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexLeftInOperand)}},
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{original_instruction->GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexRightInOperand)}}})));
|
||||
|
||||
// Insert the OpCompositeExtract after the added instruction. This instruction
|
||||
// takes the first component of the struct which represents low-order bits of
|
||||
// the operation. This is the original result.
|
||||
original_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCompositeExtract, original_instruction->type_id(),
|
||||
message_.result_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {message_.struct_fresh_id()}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||
{kOpCompositeExtractIndexLowOrderBits}}})));
|
||||
|
||||
// Remove the original instruction.
|
||||
ir_context->KillInst(original_instruction);
|
||||
|
||||
// We have modified the module so most analyzes are now invalid.
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
}
|
||||
|
||||
bool TransformationReplaceAddSubMulWithCarryingExtended::IsInstructionSuitable(
|
||||
opt::IRContext* ir_context, const opt::Instruction& instruction) {
|
||||
auto instruction_opcode = instruction.opcode();
|
||||
|
||||
// Only instructions OpIAdd, OpISub, OpIMul are supported.
|
||||
switch (instruction_opcode) {
|
||||
case SpvOpIAdd:
|
||||
case SpvOpISub:
|
||||
case SpvOpIMul:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
uint32_t operand_1_type_id =
|
||||
ir_context->get_def_use_mgr()
|
||||
->GetDef(instruction.GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexLeftInOperand))
|
||||
->type_id();
|
||||
|
||||
uint32_t operand_2_type_id =
|
||||
ir_context->get_def_use_mgr()
|
||||
->GetDef(instruction.GetSingleWordInOperand(
|
||||
kArithmeticInstructionIndexRightInOperand))
|
||||
->type_id();
|
||||
|
||||
uint32_t result_type_id = instruction.type_id();
|
||||
|
||||
// Both type ids of the operands and the result type ids must be equal.
|
||||
if (operand_1_type_id != operand_2_type_id) {
|
||||
return false;
|
||||
}
|
||||
if (operand_2_type_id != result_type_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// In case of OpIAdd and OpISub, the type must be unsigned.
|
||||
auto type = ir_context->get_type_mgr()->GetType(instruction.type_id());
|
||||
|
||||
switch (instruction_opcode) {
|
||||
case SpvOpIAdd:
|
||||
case SpvOpISub: {
|
||||
// In case of OpIAdd and OpISub if the operand is a vector, the component
|
||||
// type must be unsigned. Otherwise (if the operand is an int), the
|
||||
// operand must be unsigned.
|
||||
bool operand_is_signed =
|
||||
type->AsVector()
|
||||
? type->AsVector()->element_type()->AsInteger()->IsSigned()
|
||||
: type->AsInteger()->IsSigned();
|
||||
if (operand_is_signed) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protobufs::Transformation
|
||||
TransformationReplaceAddSubMulWithCarryingExtended::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_replace_add_sub_mul_with_carrying_extended() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_H
|
||||
#define SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_H
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationReplaceAddSubMulWithCarryingExtended
|
||||
: public Transformation {
|
||||
public:
|
||||
explicit TransformationReplaceAddSubMulWithCarryingExtended(
|
||||
const protobufs::TransformationReplaceAddSubMulWithCarryingExtended&
|
||||
message);
|
||||
|
||||
explicit TransformationReplaceAddSubMulWithCarryingExtended(
|
||||
uint32_t struct_fresh_id, uint32_t result_id);
|
||||
|
||||
// - |message_.struct_fresh_id| must be fresh.
|
||||
// - |message_.result_id| must refer to an OpIAdd or OpISub or OpIMul
|
||||
// instruction. In this instruction the result type id and the type ids of
|
||||
// the operands must be the same.
|
||||
// - The type of struct holding the intermediate result must exists in the
|
||||
// module.
|
||||
// - For OpIAdd, OpISub both operands must be unsigned.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
||||
// A transformation that replaces instructions OpIAdd, OpISub, OpIMul with
|
||||
// pairs of instructions. The first one (OpIAddCarry, OpISubBorrow,
|
||||
// OpUMulExtended, OpSMulExtended) computes the result into a struct. The
|
||||
// second one extracts the appropriate component from the struct to yield the
|
||||
// original result.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
// Checks if an OpIAdd, OpISub or OpIMul instruction can be used by the
|
||||
// transformation.
|
||||
bool static IsInstructionSuitable(opt::IRContext* ir_context,
|
||||
const opt::Instruction& instruction);
|
||||
|
||||
private:
|
||||
protobufs::TransformationReplaceAddSubMulWithCarryingExtended message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SPIRV_TOOLS_TRANSFORMATION_REPLACE_ADD_SUB_MUL_WITH_CARRYING_EXTENDED_H
|
|
@ -70,7 +70,7 @@ if (${SPIRV_BUILD_FUZZER})
|
|||
transformation_permute_function_parameters_test.cpp
|
||||
transformation_permute_phi_operands_test.cpp
|
||||
transformation_push_id_through_variable_test.cpp
|
||||
transformation_replace_parameter_with_global_test.cpp
|
||||
transformation_replace_add_sub_mul_with_carrying_extended_test.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
transformation_replace_copy_object_with_store_load_test.cpp
|
||||
transformation_replace_constant_with_uniform_test.cpp
|
||||
|
@ -78,6 +78,7 @@ if (${SPIRV_BUILD_FUZZER})
|
|||
transformation_replace_id_with_synonym_test.cpp
|
||||
transformation_replace_linear_algebra_instruction_test.cpp
|
||||
transformation_replace_load_store_with_copy_memory_test.cpp
|
||||
transformation_replace_parameter_with_global_test.cpp
|
||||
transformation_replace_params_with_struct_test.cpp
|
||||
transformation_set_function_control_test.cpp
|
||||
transformation_set_loop_control_test.cpp
|
||||
|
|
|
@ -0,0 +1,610 @@
|
|||
// Copyright (c) 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationReplaceAddSubMulWithCarryingExtendedTest,
|
||||
NotApplicableBasicChecks) {
|
||||
// First conditions in IsApplicable() are checked.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i1"
|
||||
OpName %10 "i2"
|
||||
OpName %12 "i3"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%12 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%13 = OpLoad %6 %10
|
||||
%14 = OpLoad %6 %8
|
||||
%15 = OpSDiv %6 %13 %14
|
||||
OpStore %12 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
|
||||
// Bad: |struct_fresh_id| must be fresh.
|
||||
auto transformation_bad_1 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(14, 15);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_1.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to an instruction OpSDiv.
|
||||
auto transformation_bad_2 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(20, 15);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_2.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to an nonexistent instruction.
|
||||
auto transformation_bad_3 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(20, 21);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_3.IsApplicable(context.get(), transformation_context));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceAddSubMulWithCarryingExtendedTest,
|
||||
NotApplicableDifferingSignedTypes) {
|
||||
// Operand types and result types do not match. Not applicable to an operation
|
||||
// on vectors with signed integers and operation on signed integers.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i1"
|
||||
OpName %10 "i2"
|
||||
OpName %16 "v1"
|
||||
OpName %20 "v2"
|
||||
OpName %25 "v3"
|
||||
OpName %31 "u1"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%14 = OpTypeVector %6 3
|
||||
%15 = OpTypePointer Function %14
|
||||
%17 = OpConstant %6 0
|
||||
%18 = OpConstant %6 2
|
||||
%19 = OpConstantComposite %14 %17 %9 %18
|
||||
%21 = OpConstant %6 3
|
||||
%22 = OpConstant %6 4
|
||||
%23 = OpConstant %6 5
|
||||
%24 = OpConstantComposite %14 %21 %22 %23
|
||||
%29 = OpTypeInt 32 0
|
||||
%30 = OpTypePointer Function %29
|
||||
%32 = OpConstant %29 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%16 = OpVariable %15 Function
|
||||
%20 = OpVariable %15 Function
|
||||
%25 = OpVariable %15 Function
|
||||
%31 = OpVariable %30 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
%12 = OpLoad %6 %8
|
||||
%13 = OpISub %6 %11 %12
|
||||
OpStore %10 %13
|
||||
OpStore %16 %19
|
||||
OpStore %20 %24
|
||||
%26 = OpLoad %14 %16
|
||||
%27 = OpLoad %14 %20
|
||||
%28 = OpIAdd %14 %26 %27
|
||||
OpStore %25 %28
|
||||
OpStore %31 %32
|
||||
%40 = OpIMul %6 %32 %18
|
||||
%41 = OpIAdd %6 %32 %32
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
|
||||
// Bad: The transformation cannot be applied to an instruction OpIMul that has
|
||||
// different signedness of the types of operands.
|
||||
auto transformation_bad_1 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 40);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_1.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to an instruction OpIAdd that has
|
||||
// different signedness of the result type than the signedness of the types of
|
||||
// the operands.
|
||||
auto transformation_bad_2 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 41);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_2.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to the instruction OpIAdd of two
|
||||
// vectors that have signed components.
|
||||
auto transformation_bad_3 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 28);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_3.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to the instruction OpISub of two
|
||||
// signed integers
|
||||
auto transformation_bad_4 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 13);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_4.IsApplicable(context.get(), transformation_context));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceAddSubMulWithCarryingExtendedTest,
|
||||
NotApplicableMissingStructTypes) {
|
||||
// In all cases the required struct types are missing.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "u1"
|
||||
OpName %10 "u2"
|
||||
OpName %12 "u3"
|
||||
OpName %24 "i1"
|
||||
OpName %26 "i2"
|
||||
OpName %28 "i3"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 0
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%22 = OpTypeInt 32 1
|
||||
%23 = OpTypePointer Function %22
|
||||
%25 = OpConstant %22 1
|
||||
%27 = OpConstant %22 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%12 = OpVariable %7 Function
|
||||
%24 = OpVariable %23 Function
|
||||
%26 = OpVariable %23 Function
|
||||
%28 = OpVariable %23 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%13 = OpLoad %6 %8
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %13 %14
|
||||
OpStore %12 %15
|
||||
%16 = OpLoad %6 %8
|
||||
%17 = OpLoad %6 %10
|
||||
%18 = OpISub %6 %16 %17
|
||||
OpStore %12 %18
|
||||
%19 = OpLoad %6 %8
|
||||
%20 = OpLoad %6 %10
|
||||
%21 = OpIMul %6 %19 %20
|
||||
OpStore %12 %21
|
||||
OpStore %24 %25
|
||||
OpStore %26 %27
|
||||
%29 = OpLoad %22 %24
|
||||
%30 = OpLoad %22 %26
|
||||
%31 = OpIMul %22 %29 %30
|
||||
OpStore %28 %31
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
|
||||
auto transformation_bad_1 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 15);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_1.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
auto transformation_bad_2 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 18);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_2.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to the instruction OpIAdd of two
|
||||
// vectors that have signed components.
|
||||
auto transformation_bad_3 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 21);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_3.IsApplicable(context.get(), transformation_context));
|
||||
|
||||
// Bad: The transformation cannot be applied to the instruction OpISub of two
|
||||
// signed integers
|
||||
auto transformation_bad_4 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(50, 31);
|
||||
ASSERT_FALSE(
|
||||
transformation_bad_4.IsApplicable(context.get(), transformation_context));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceAddSubMulWithCarryingExtendedTest,
|
||||
ApplicableScenarios) {
|
||||
// In this test all of the transformations can be applied. The required struct
|
||||
// types are provided.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "u1"
|
||||
OpName %10 "u2"
|
||||
OpName %12 "u3"
|
||||
OpName %24 "i1"
|
||||
OpName %26 "i2"
|
||||
OpName %28 "i3"
|
||||
OpName %34 "uv1"
|
||||
OpName %36 "uv2"
|
||||
OpName %39 "uv3"
|
||||
OpName %51 "v1"
|
||||
OpName %53 "v2"
|
||||
OpName %56 "v3"
|
||||
OpName %60 "pair_uint"
|
||||
OpMemberName %60 0 "u_1"
|
||||
OpMemberName %60 1 "u_2"
|
||||
OpName %62 "p_uint"
|
||||
OpName %63 "pair_uvec2"
|
||||
OpMemberName %63 0 "uv_1"
|
||||
OpMemberName %63 1 "uv_2"
|
||||
OpName %65 "p_uvec2"
|
||||
OpName %66 "pair_ivec2"
|
||||
OpMemberName %66 0 "v_1"
|
||||
OpMemberName %66 1 "v_2"
|
||||
OpName %68 "p_ivec2"
|
||||
OpName %69 "pair_int"
|
||||
OpMemberName %69 0 "i_1"
|
||||
OpMemberName %69 1 "i_2"
|
||||
OpName %71 "p_int"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 0
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%22 = OpTypeInt 32 1
|
||||
%23 = OpTypePointer Function %22
|
||||
%25 = OpConstant %22 1
|
||||
%27 = OpConstant %22 2
|
||||
%32 = OpTypeVector %6 2
|
||||
%33 = OpTypePointer Function %32
|
||||
%35 = OpConstantComposite %32 %9 %11
|
||||
%37 = OpConstant %6 3
|
||||
%38 = OpConstantComposite %32 %11 %37
|
||||
%49 = OpTypeVector %22 2
|
||||
%50 = OpTypePointer Function %49
|
||||
%52 = OpConstantComposite %49 %25 %27
|
||||
%54 = OpConstant %22 3
|
||||
%55 = OpConstantComposite %49 %27 %54
|
||||
%60 = OpTypeStruct %6 %6
|
||||
%61 = OpTypePointer Private %60
|
||||
%62 = OpVariable %61 Private
|
||||
%63 = OpTypeStruct %32 %32
|
||||
%64 = OpTypePointer Private %63
|
||||
%65 = OpVariable %64 Private
|
||||
%66 = OpTypeStruct %49 %49
|
||||
%67 = OpTypePointer Private %66
|
||||
%68 = OpVariable %67 Private
|
||||
%69 = OpTypeStruct %22 %22
|
||||
%70 = OpTypePointer Private %69
|
||||
%71 = OpVariable %70 Private
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%12 = OpVariable %7 Function
|
||||
%24 = OpVariable %23 Function
|
||||
%26 = OpVariable %23 Function
|
||||
%28 = OpVariable %23 Function
|
||||
%34 = OpVariable %33 Function
|
||||
%36 = OpVariable %33 Function
|
||||
%39 = OpVariable %33 Function
|
||||
%51 = OpVariable %50 Function
|
||||
%53 = OpVariable %50 Function
|
||||
%56 = OpVariable %50 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%13 = OpLoad %6 %8
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %13 %14
|
||||
OpStore %12 %15
|
||||
%16 = OpLoad %6 %8
|
||||
%17 = OpLoad %6 %10
|
||||
%18 = OpISub %6 %16 %17
|
||||
OpStore %12 %18
|
||||
%19 = OpLoad %6 %8
|
||||
%20 = OpLoad %6 %10
|
||||
%21 = OpIMul %6 %19 %20
|
||||
OpStore %12 %21
|
||||
OpStore %24 %25
|
||||
OpStore %26 %27
|
||||
%29 = OpLoad %22 %24
|
||||
%30 = OpLoad %22 %26
|
||||
%31 = OpIMul %22 %29 %30
|
||||
OpStore %28 %31
|
||||
OpStore %34 %35
|
||||
OpStore %36 %38
|
||||
%40 = OpLoad %32 %34
|
||||
%41 = OpLoad %32 %36
|
||||
%42 = OpIAdd %32 %40 %41
|
||||
OpStore %39 %42
|
||||
%43 = OpLoad %32 %34
|
||||
%44 = OpLoad %32 %36
|
||||
%45 = OpISub %32 %43 %44
|
||||
OpStore %39 %45
|
||||
%46 = OpLoad %32 %34
|
||||
%47 = OpLoad %32 %36
|
||||
%48 = OpIMul %32 %46 %47
|
||||
OpStore %39 %48
|
||||
OpStore %51 %52
|
||||
OpStore %53 %55
|
||||
%57 = OpLoad %49 %51
|
||||
%58 = OpLoad %49 %53
|
||||
%59 = OpIMul %49 %57 %58
|
||||
OpStore %56 %59
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
|
||||
auto transformation_good_1 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(80, 15);
|
||||
ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_1.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_2 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(81, 18);
|
||||
ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_2.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_3 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(82, 21);
|
||||
ASSERT_TRUE(transformation_good_3.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_3.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_4 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(83, 31);
|
||||
ASSERT_TRUE(transformation_good_4.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_4.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_5 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(84, 42);
|
||||
ASSERT_TRUE(transformation_good_5.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_5.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_6 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(85, 45);
|
||||
ASSERT_TRUE(transformation_good_6.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_6.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_7 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(86, 48);
|
||||
ASSERT_TRUE(transformation_good_7.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_7.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
auto transformation_good_8 =
|
||||
TransformationReplaceAddSubMulWithCarryingExtended(87, 59);
|
||||
ASSERT_TRUE(transformation_good_8.IsApplicable(context.get(),
|
||||
transformation_context));
|
||||
transformation_good_8.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "u1"
|
||||
OpName %10 "u2"
|
||||
OpName %12 "u3"
|
||||
OpName %24 "i1"
|
||||
OpName %26 "i2"
|
||||
OpName %28 "i3"
|
||||
OpName %34 "uv1"
|
||||
OpName %36 "uv2"
|
||||
OpName %39 "uv3"
|
||||
OpName %51 "v1"
|
||||
OpName %53 "v2"
|
||||
OpName %56 "v3"
|
||||
OpName %60 "pair_uint"
|
||||
OpMemberName %60 0 "u_1"
|
||||
OpMemberName %60 1 "u_2"
|
||||
OpName %62 "p_uint"
|
||||
OpName %63 "pair_uvec2"
|
||||
OpMemberName %63 0 "uv_1"
|
||||
OpMemberName %63 1 "uv_2"
|
||||
OpName %65 "p_uvec2"
|
||||
OpName %66 "pair_ivec2"
|
||||
OpMemberName %66 0 "v_1"
|
||||
OpMemberName %66 1 "v_2"
|
||||
OpName %68 "p_ivec2"
|
||||
OpName %69 "pair_int"
|
||||
OpMemberName %69 0 "i_1"
|
||||
OpMemberName %69 1 "i_2"
|
||||
OpName %71 "p_int"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 0
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%22 = OpTypeInt 32 1
|
||||
%23 = OpTypePointer Function %22
|
||||
%25 = OpConstant %22 1
|
||||
%27 = OpConstant %22 2
|
||||
%32 = OpTypeVector %6 2
|
||||
%33 = OpTypePointer Function %32
|
||||
%35 = OpConstantComposite %32 %9 %11
|
||||
%37 = OpConstant %6 3
|
||||
%38 = OpConstantComposite %32 %11 %37
|
||||
%49 = OpTypeVector %22 2
|
||||
%50 = OpTypePointer Function %49
|
||||
%52 = OpConstantComposite %49 %25 %27
|
||||
%54 = OpConstant %22 3
|
||||
%55 = OpConstantComposite %49 %27 %54
|
||||
%60 = OpTypeStruct %6 %6
|
||||
%61 = OpTypePointer Private %60
|
||||
%62 = OpVariable %61 Private
|
||||
%63 = OpTypeStruct %32 %32
|
||||
%64 = OpTypePointer Private %63
|
||||
%65 = OpVariable %64 Private
|
||||
%66 = OpTypeStruct %49 %49
|
||||
%67 = OpTypePointer Private %66
|
||||
%68 = OpVariable %67 Private
|
||||
%69 = OpTypeStruct %22 %22
|
||||
%70 = OpTypePointer Private %69
|
||||
%71 = OpVariable %70 Private
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%12 = OpVariable %7 Function
|
||||
%24 = OpVariable %23 Function
|
||||
%26 = OpVariable %23 Function
|
||||
%28 = OpVariable %23 Function
|
||||
%34 = OpVariable %33 Function
|
||||
%36 = OpVariable %33 Function
|
||||
%39 = OpVariable %33 Function
|
||||
%51 = OpVariable %50 Function
|
||||
%53 = OpVariable %50 Function
|
||||
%56 = OpVariable %50 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%13 = OpLoad %6 %8
|
||||
%14 = OpLoad %6 %10
|
||||
%80 = OpIAddCarry %60 %13 %14
|
||||
%15 = OpCompositeExtract %6 %80 0
|
||||
OpStore %12 %15
|
||||
%16 = OpLoad %6 %8
|
||||
%17 = OpLoad %6 %10
|
||||
%81 = OpISubBorrow %60 %16 %17
|
||||
%18 = OpCompositeExtract %6 %81 0
|
||||
OpStore %12 %18
|
||||
%19 = OpLoad %6 %8
|
||||
%20 = OpLoad %6 %10
|
||||
%82 = OpUMulExtended %60 %19 %20
|
||||
%21 = OpCompositeExtract %6 %82 0
|
||||
OpStore %12 %21
|
||||
OpStore %24 %25
|
||||
OpStore %26 %27
|
||||
%29 = OpLoad %22 %24
|
||||
%30 = OpLoad %22 %26
|
||||
%83 = OpSMulExtended %69 %29 %30
|
||||
%31 = OpCompositeExtract %22 %83 0
|
||||
OpStore %28 %31
|
||||
OpStore %34 %35
|
||||
OpStore %36 %38
|
||||
%40 = OpLoad %32 %34
|
||||
%41 = OpLoad %32 %36
|
||||
%84 = OpIAddCarry %63 %40 %41
|
||||
%42 = OpCompositeExtract %32 %84 0
|
||||
OpStore %39 %42
|
||||
%43 = OpLoad %32 %34
|
||||
%44 = OpLoad %32 %36
|
||||
%85 = OpISubBorrow %63 %43 %44
|
||||
%45 = OpCompositeExtract %32 %85 0
|
||||
OpStore %39 %45
|
||||
%46 = OpLoad %32 %34
|
||||
%47 = OpLoad %32 %36
|
||||
%86 = OpUMulExtended %63 %46 %47
|
||||
%48 = OpCompositeExtract %32 %86 0
|
||||
OpStore %39 %48
|
||||
OpStore %51 %52
|
||||
OpStore %53 %55
|
||||
%57 = OpLoad %49 %51
|
||||
%58 = OpLoad %49 %53
|
||||
%87 = OpSMulExtended %66 %57 %58
|
||||
%59 = OpCompositeExtract %49 %87 0
|
||||
OpStore %56 %59
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Загрузка…
Ссылка в новой задаче