Skip to content

Commit

Permalink
spirv-fuzz: TransformationReplaceAddSubMulWithCarryingExtended (Khron…
Browse files Browse the repository at this point in the history
…osGroup#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 KhronosGroup#3577
  • Loading branch information
Antoni Karpiński authored Aug 6, 2020
1 parent 6d7f34f commit 7b2dd11
Show file tree
Hide file tree
Showing 11 changed files with 1,070 additions and 4 deletions.
4 changes: 4 additions & 0 deletions source/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions source/fuzz/fuzzer_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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_ =
Expand Down
4 changes: 4 additions & 0 deletions source/fuzz/fuzzer_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
}
Expand Down Expand Up @@ -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_;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions source/fuzz/protobufs/spvtoolsfuzz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
Expand Down Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions source/fuzz/transformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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>(
Expand Down Expand Up @@ -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>(
Expand Down
Loading

0 comments on commit 7b2dd11

Please sign in to comment.