spirv-fuzz: Add swap commutable operands transformation (#3205)
In this PR, the classes that represent the swap commutable operands
transformation and the fuzzer pass were implemented.
Fixes #3205.
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
index 5b2afe4..231ea75 100644
--- a/source/fuzz/CMakeLists.txt
+++ b/source/fuzz/CMakeLists.txt
@@ -63,6 +63,7 @@
fuzzer_pass_outline_functions.h
fuzzer_pass_permute_blocks.h
fuzzer_pass_split_blocks.h
+ fuzzer_pass_swap_commutable_operands.h
fuzzer_util.h
id_use_descriptor.h
instruction_descriptor.h
@@ -112,6 +113,7 @@
transformation_set_selection_control.h
transformation_split_block.h
transformation_store.h
+ transformation_swap_commutable_operands.h
transformation_vector_shuffle.h
uniform_buffer_element_descriptor.h
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
@@ -149,6 +151,7 @@
fuzzer_pass_outline_functions.cpp
fuzzer_pass_permute_blocks.cpp
fuzzer_pass_split_blocks.cpp
+ fuzzer_pass_swap_commutable_operands.cpp
fuzzer_util.cpp
id_use_descriptor.cpp
instruction_descriptor.cpp
@@ -197,6 +200,7 @@
transformation_set_selection_control.cpp
transformation_split_block.cpp
transformation_store.cpp
+ transformation_swap_commutable_operands.cpp
transformation_vector_shuffle.cpp
uniform_buffer_element_descriptor.cpp
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp
index b702025..945bcc5 100644
--- a/source/fuzz/fuzzer.cpp
+++ b/source/fuzz/fuzzer.cpp
@@ -46,6 +46,7 @@
#include "source/fuzz/fuzzer_pass_outline_functions.h"
#include "source/fuzz/fuzzer_pass_permute_blocks.h"
#include "source/fuzz/fuzzer_pass_split_blocks.h"
+#include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/pseudo_random_generator.h"
#include "source/opt/build_module.h"
@@ -280,6 +281,9 @@
MaybeAddPass<FuzzerPassAddNoContractionDecorations>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
transformation_sequence_out);
+ MaybeAddPass<FuzzerPassSwapCommutableOperands>(
+ &final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
+ transformation_sequence_out);
for (auto& pass : final_passes) {
if (!impl_->ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) {
return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule;
diff --git a/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp b/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp
new file mode 100644
index 0000000..4df97c9
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp
@@ -0,0 +1,50 @@
+// 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_swap_commutable_operands.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_swap_commutable_operands.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassSwapCommutableOperands::~FuzzerPassSwapCommutableOperands() = default;
+
+void FuzzerPassSwapCommutableOperands::Apply() {
+ auto context = GetIRContext();
+ // Iterates over the module's instructions and checks whether it is
+ // commutative. In this case, the transformation is probabilistically applied.
+ context->module()->ForEachInst(
+ [this, context](opt::Instruction* instruction) {
+ if (spvOpcodeIsCommutativeBinaryOperator(instruction->opcode()) &&
+ GetFuzzerContext()->ChooseEven()) {
+ auto instructionDescriptor =
+ MakeInstructionDescriptor(context, instruction);
+ auto transformation =
+ TransformationSwapCommutableOperands(instructionDescriptor);
+ ApplyTransformation(transformation);
+ }
+ });
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_swap_commutable_operands.h b/source/fuzz/fuzzer_pass_swap_commutable_operands.h
new file mode 100644
index 0000000..b0206de
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_swap_commutable_operands.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2020 André Perez Maselco
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_SWAP_COMMUTABLE_OPERANDS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_SWAP_COMMUTABLE_OPERANDS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// This fuzzer pass searches for all commutative instructions in the module,
+// probabilistically choosing which of these instructions will have its input
+// operands swapped.
+class FuzzerPassSwapCommutableOperands : public FuzzerPass {
+ public:
+ FuzzerPassSwapCommutableOperands(
+ opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ ~FuzzerPassSwapCommutableOperands();
+
+ void Apply() override;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_PASS_SWAP_COMMUTABLE_OPERANDS_H_
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
index 61c66c2..25f0142 100644
--- a/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -369,6 +369,7 @@
TransformationFunctionCall function_call = 38;
TransformationAccessChain access_chain = 39;
TransformationEquationInstruction equation_instruction = 40;
+ TransformationSwapCommutableOperands swap_commutable_operands = 41;
// Add additional option using the next available number.
}
}
@@ -1068,6 +1069,15 @@
}
+message TransformationSwapCommutableOperands {
+
+ // A transformation that swaps the operands of a commutative instruction.
+
+ // A descriptor for a commutative instruction
+ InstructionDescriptor instruction_descriptor = 1;
+
+}
+
message TransformationVectorShuffle {
// A transformation that adds a vector shuffle instruction.
diff --git a/source/fuzz/transformation.cpp b/source/fuzz/transformation.cpp
index a69da75..fe0d41c 100644
--- a/source/fuzz/transformation.cpp
+++ b/source/fuzz/transformation.cpp
@@ -56,6 +56,7 @@
#include "source/fuzz/transformation_set_selection_control.h"
#include "source/fuzz/transformation_split_block.h"
#include "source/fuzz/transformation_store.h"
+#include "source/fuzz/transformation_swap_commutable_operands.h"
#include "source/fuzz/transformation_vector_shuffle.h"
#include "source/util/make_unique.h"
@@ -170,6 +171,9 @@
return MakeUnique<TransformationSplitBlock>(message.split_block());
case protobufs::Transformation::TransformationCase::kStore:
return MakeUnique<TransformationStore>(message.store());
+ case protobufs::Transformation::TransformationCase::kSwapCommutableOperands:
+ return MakeUnique<TransformationSwapCommutableOperands>(
+ message.swap_commutable_operands());
case protobufs::Transformation::TransformationCase::kVectorShuffle:
return MakeUnique<TransformationVectorShuffle>(message.vector_shuffle());
case protobufs::Transformation::TRANSFORMATION_NOT_SET:
diff --git a/source/fuzz/transformation_swap_commutable_operands.cpp b/source/fuzz/transformation_swap_commutable_operands.cpp
new file mode 100644
index 0000000..49d9de8
--- /dev/null
+++ b/source/fuzz/transformation_swap_commutable_operands.cpp
@@ -0,0 +1,66 @@
+// 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_swap_commutable_operands.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationSwapCommutableOperands::TransformationSwapCommutableOperands(
+ const spvtools::fuzz::protobufs::TransformationSwapCommutableOperands&
+ message)
+ : message_(message) {}
+
+TransformationSwapCommutableOperands::TransformationSwapCommutableOperands(
+ const protobufs::InstructionDescriptor& instruction_descriptor) {
+ *message_.mutable_instruction_descriptor() = instruction_descriptor;
+}
+
+bool TransformationSwapCommutableOperands::IsApplicable(
+ opt::IRContext* context, const spvtools::fuzz::FactManager& /*unused*/
+ ) const {
+ auto instruction =
+ FindInstruction(message_.instruction_descriptor(), context);
+ if (instruction == nullptr) return false;
+
+ SpvOp opcode = static_cast<SpvOp>(
+ message_.instruction_descriptor().target_instruction_opcode());
+ assert(instruction->opcode() == opcode &&
+ "The located instruction must have the same opcode as in the "
+ "descriptor.");
+ return spvOpcodeIsCommutativeBinaryOperator(opcode);
+}
+
+void TransformationSwapCommutableOperands::Apply(
+ opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/
+ ) const {
+ auto instruction =
+ FindInstruction(message_.instruction_descriptor(), context);
+ // By design, the instructions defined to be commutative have exactly two
+ // input parameters.
+ std::swap(instruction->GetInOperand(0), instruction->GetInOperand(1));
+}
+
+protobufs::Transformation TransformationSwapCommutableOperands::ToMessage()
+ const {
+ protobufs::Transformation result;
+ *result.mutable_swap_commutable_operands() = message_;
+ return result;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/transformation_swap_commutable_operands.h b/source/fuzz/transformation_swap_commutable_operands.h
new file mode 100644
index 0000000..061e92d
--- /dev/null
+++ b/source/fuzz/transformation_swap_commutable_operands.h
@@ -0,0 +1,51 @@
+// 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_SWAP_COMMUTABLE_OPERANDS_H_
+#define SOURCE_FUZZ_TRANSFORMATION_SWAP_COMMUTABLE_OPERANDS_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationSwapCommutableOperands : public Transformation {
+ public:
+ explicit TransformationSwapCommutableOperands(
+ const protobufs::TransformationSwapCommutableOperands& message);
+
+ TransformationSwapCommutableOperands(
+ const protobufs::InstructionDescriptor& instruction_descriptor);
+
+ // - |message_.instruction_descriptor| must identify an existing
+ // commutative instruction
+ bool IsApplicable(opt::IRContext* context,
+ const FactManager& fact_manager) const override;
+
+ // Swaps the commutable operands.
+ void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+ protobufs::Transformation ToMessage() const override;
+
+ private:
+ protobufs::TransformationSwapCommutableOperands message_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_TRANSFORMATION_SWAP_COMMUTABLE_OPERANDS_H_
diff --git a/source/opcode.cpp b/source/opcode.cpp
index a837b95..b38b5d4 100644
--- a/source/opcode.cpp
+++ b/source/opcode.cpp
@@ -612,6 +612,39 @@
}
}
+bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpPtrEqual:
+ case SpvOpPtrNotEqual:
+ case SpvOpIAdd:
+ case SpvOpFAdd:
+ case SpvOpIMul:
+ case SpvOpFMul:
+ case SpvOpDot:
+ case SpvOpIAddCarry:
+ case SpvOpUMulExtended:
+ case SpvOpSMulExtended:
+ case SpvOpBitwiseOr:
+ case SpvOpBitwiseXor:
+ case SpvOpBitwiseAnd:
+ case SpvOpOrdered:
+ case SpvOpUnordered:
+ case SpvOpLogicalEqual:
+ case SpvOpLogicalNotEqual:
+ case SpvOpLogicalOr:
+ case SpvOpLogicalAnd:
+ case SpvOpIEqual:
+ case SpvOpINotEqual:
+ case SpvOpFOrdEqual:
+ case SpvOpFUnordEqual:
+ case SpvOpFOrdNotEqual:
+ case SpvOpFUnordNotEqual:
+ return true;
+ default:
+ return false;
+ }
+}
+
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
switch (opcode) {
case SpvOpMemoryBarrier:
diff --git a/source/opcode.h b/source/opcode.h
index f79826f..b4f0271 100644
--- a/source/opcode.h
+++ b/source/opcode.h
@@ -130,6 +130,10 @@
// Returns true if the given opcode is a debug instruction.
bool spvOpcodeIsDebug(SpvOp opcode);
+// Returns true for opcodes that are binary operators,
+// where the order of the operands is irrelevant.
+bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
+
// Returns a vector containing the indices of the memory semantics <id>
// operands for |opcode|.
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);
diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt
index 6ec4c2a..40aa152 100644
--- a/test/fuzz/CMakeLists.txt
+++ b/test/fuzz/CMakeLists.txt
@@ -63,6 +63,7 @@
transformation_set_selection_control_test.cpp
transformation_split_block_test.cpp
transformation_store_test.cpp
+ transformation_swap_commutable_operands_test.cpp
transformation_vector_shuffle_test.cpp
uniform_buffer_element_descriptor_test.cpp)
diff --git a/test/fuzz/transformation_swap_commutable_operands_test.cpp b/test/fuzz/transformation_swap_commutable_operands_test.cpp
new file mode 100644
index 0000000..f0591cf
--- /dev/null
+++ b/test/fuzz/transformation_swap_commutable_operands_test.cpp
@@ -0,0 +1,427 @@
+// 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_swap_commutable_operands.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationSwapCommutableOperandsTest, IsApplicableTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 2
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 1
+ %13 = OpConstant %6 2
+ %14 = OpConstantComposite %9 %12 %13
+ %15 = OpTypePointer Function %6
+ %17 = OpConstant %6 0
+ %29 = OpTypeFloat 32
+ %30 = OpTypeArray %29 %8
+ %31 = OpTypePointer Function %30
+ %33 = OpConstant %29 1
+ %34 = OpConstant %29 2
+ %35 = OpConstantComposite %30 %33 %34
+ %36 = OpTypePointer Function %29
+ %49 = OpTypeVector %29 3
+ %50 = OpTypeArray %49 %8
+ %51 = OpTypePointer Function %50
+ %53 = OpConstant %29 3
+ %54 = OpConstantComposite %49 %33 %34 %53
+ %55 = OpConstant %29 4
+ %56 = OpConstant %29 5
+ %57 = OpConstant %29 6
+ %58 = OpConstantComposite %49 %55 %56 %57
+ %59 = OpConstantComposite %50 %54 %58
+ %61 = OpTypePointer Function %49
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %16 = OpVariable %15 Function
+ %23 = OpVariable %15 Function
+ %32 = OpVariable %31 Function
+ %37 = OpVariable %36 Function
+ %43 = OpVariable %36 Function
+ %52 = OpVariable %51 Function
+ %60 = OpVariable %36 Function
+ OpStore %11 %14
+ %18 = OpAccessChain %15 %11 %17
+ %19 = OpLoad %6 %18
+ %20 = OpAccessChain %15 %11 %12
+ %21 = OpLoad %6 %20
+ %22 = OpIAdd %6 %19 %21
+ OpStore %16 %22
+ %24 = OpAccessChain %15 %11 %17
+ %25 = OpLoad %6 %24
+ %26 = OpAccessChain %15 %11 %12
+ %27 = OpLoad %6 %26
+ %28 = OpIMul %6 %25 %27
+ OpStore %23 %28
+ OpStore %32 %35
+ %38 = OpAccessChain %36 %32 %17
+ %39 = OpLoad %29 %38
+ %40 = OpAccessChain %36 %32 %12
+ %41 = OpLoad %29 %40
+ %42 = OpFAdd %29 %39 %41
+ OpStore %37 %42
+ %44 = OpAccessChain %36 %32 %17
+ %45 = OpLoad %29 %44
+ %46 = OpAccessChain %36 %32 %12
+ %47 = OpLoad %29 %46
+ %48 = OpFMul %29 %45 %47
+ OpStore %43 %48
+ OpStore %52 %59
+ %62 = OpAccessChain %61 %52 %17
+ %63 = OpLoad %49 %62
+ %64 = OpAccessChain %61 %52 %12
+ %65 = OpLoad %49 %64
+ %66 = OpDot %29 %63 %65
+ OpStore %60 %66
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager factManager;
+
+ // Tests existing commutative instructions
+ auto instructionDescriptor = MakeInstructionDescriptor(22, SpvOpIAdd, 0);
+ auto transformation =
+ TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(28, SpvOpIMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(42, SpvOpFAdd, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(48, SpvOpFMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(66, SpvOpDot, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_TRUE(transformation.IsApplicable(context.get(), factManager));
+
+ // Tests existing non-commutative instructions
+ instructionDescriptor = MakeInstructionDescriptor(1, SpvOpExtInstImport, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(5, SpvOpLabel, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(8, SpvOpConstant, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(11, SpvOpVariable, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor =
+ MakeInstructionDescriptor(14, SpvOpConstantComposite, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ // Tests the base instruction id not existing
+ instructionDescriptor = MakeInstructionDescriptor(67, SpvOpIAddCarry, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(68, SpvOpIEqual, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(69, SpvOpINotEqual, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(70, SpvOpFOrdEqual, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(71, SpvOpPtrEqual, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ // Tests there being no instruction with the desired opcode after the base
+ // instruction id
+ instructionDescriptor = MakeInstructionDescriptor(24, SpvOpIAdd, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(38, SpvOpIMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(45, SpvOpFAdd, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(66, SpvOpFMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ // Tests there being an instruction with the desired opcode after the base
+ // instruction id, but the skip count associated with the instruction
+ // descriptor being so high.
+ instructionDescriptor = MakeInstructionDescriptor(11, SpvOpIAdd, 100);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(16, SpvOpIMul, 100);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(23, SpvOpFAdd, 100);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(32, SpvOpFMul, 100);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+
+ instructionDescriptor = MakeInstructionDescriptor(37, SpvOpDot, 100);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ ASSERT_FALSE(transformation.IsApplicable(context.get(), factManager));
+}
+
+TEST(TransformationSwapCommutableOperandsTest, ApplyTest) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 2
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 1
+ %13 = OpConstant %6 2
+ %14 = OpConstantComposite %9 %12 %13
+ %15 = OpTypePointer Function %6
+ %17 = OpConstant %6 0
+ %29 = OpTypeFloat 32
+ %30 = OpTypeArray %29 %8
+ %31 = OpTypePointer Function %30
+ %33 = OpConstant %29 1
+ %34 = OpConstant %29 2
+ %35 = OpConstantComposite %30 %33 %34
+ %36 = OpTypePointer Function %29
+ %49 = OpTypeVector %29 3
+ %50 = OpTypeArray %49 %8
+ %51 = OpTypePointer Function %50
+ %53 = OpConstant %29 3
+ %54 = OpConstantComposite %49 %33 %34 %53
+ %55 = OpConstant %29 4
+ %56 = OpConstant %29 5
+ %57 = OpConstant %29 6
+ %58 = OpConstantComposite %49 %55 %56 %57
+ %59 = OpConstantComposite %50 %54 %58
+ %61 = OpTypePointer Function %49
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %16 = OpVariable %15 Function
+ %23 = OpVariable %15 Function
+ %32 = OpVariable %31 Function
+ %37 = OpVariable %36 Function
+ %43 = OpVariable %36 Function
+ %52 = OpVariable %51 Function
+ %60 = OpVariable %36 Function
+ OpStore %11 %14
+ %18 = OpAccessChain %15 %11 %17
+ %19 = OpLoad %6 %18
+ %20 = OpAccessChain %15 %11 %12
+ %21 = OpLoad %6 %20
+ %22 = OpIAdd %6 %19 %21
+ OpStore %16 %22
+ %24 = OpAccessChain %15 %11 %17
+ %25 = OpLoad %6 %24
+ %26 = OpAccessChain %15 %11 %12
+ %27 = OpLoad %6 %26
+ %28 = OpIMul %6 %25 %27
+ OpStore %23 %28
+ OpStore %32 %35
+ %38 = OpAccessChain %36 %32 %17
+ %39 = OpLoad %29 %38
+ %40 = OpAccessChain %36 %32 %12
+ %41 = OpLoad %29 %40
+ %42 = OpFAdd %29 %39 %41
+ OpStore %37 %42
+ %44 = OpAccessChain %36 %32 %17
+ %45 = OpLoad %29 %44
+ %46 = OpAccessChain %36 %32 %12
+ %47 = OpLoad %29 %46
+ %48 = OpFMul %29 %45 %47
+ OpStore %43 %48
+ OpStore %52 %59
+ %62 = OpAccessChain %61 %52 %17
+ %63 = OpLoad %49 %62
+ %64 = OpAccessChain %61 %52 %12
+ %65 = OpLoad %49 %64
+ %66 = OpDot %29 %63 %65
+ OpStore %60 %66
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ FactManager factManager;
+
+ auto instructionDescriptor = MakeInstructionDescriptor(22, SpvOpIAdd, 0);
+ auto transformation =
+ TransformationSwapCommutableOperands(instructionDescriptor);
+ transformation.Apply(context.get(), &factManager);
+
+ instructionDescriptor = MakeInstructionDescriptor(28, SpvOpIMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ transformation.Apply(context.get(), &factManager);
+
+ instructionDescriptor = MakeInstructionDescriptor(42, SpvOpFAdd, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ transformation.Apply(context.get(), &factManager);
+
+ instructionDescriptor = MakeInstructionDescriptor(48, SpvOpFMul, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ transformation.Apply(context.get(), &factManager);
+
+ instructionDescriptor = MakeInstructionDescriptor(66, SpvOpDot, 0);
+ transformation = TransformationSwapCommutableOperands(instructionDescriptor);
+ transformation.Apply(context.get(), &factManager);
+
+ std::string variantShader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 310
+ OpName %4 "main"
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeInt 32 0
+ %8 = OpConstant %7 2
+ %9 = OpTypeArray %6 %8
+ %10 = OpTypePointer Function %9
+ %12 = OpConstant %6 1
+ %13 = OpConstant %6 2
+ %14 = OpConstantComposite %9 %12 %13
+ %15 = OpTypePointer Function %6
+ %17 = OpConstant %6 0
+ %29 = OpTypeFloat 32
+ %30 = OpTypeArray %29 %8
+ %31 = OpTypePointer Function %30
+ %33 = OpConstant %29 1
+ %34 = OpConstant %29 2
+ %35 = OpConstantComposite %30 %33 %34
+ %36 = OpTypePointer Function %29
+ %49 = OpTypeVector %29 3
+ %50 = OpTypeArray %49 %8
+ %51 = OpTypePointer Function %50
+ %53 = OpConstant %29 3
+ %54 = OpConstantComposite %49 %33 %34 %53
+ %55 = OpConstant %29 4
+ %56 = OpConstant %29 5
+ %57 = OpConstant %29 6
+ %58 = OpConstantComposite %49 %55 %56 %57
+ %59 = OpConstantComposite %50 %54 %58
+ %61 = OpTypePointer Function %49
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %11 = OpVariable %10 Function
+ %16 = OpVariable %15 Function
+ %23 = OpVariable %15 Function
+ %32 = OpVariable %31 Function
+ %37 = OpVariable %36 Function
+ %43 = OpVariable %36 Function
+ %52 = OpVariable %51 Function
+ %60 = OpVariable %36 Function
+ OpStore %11 %14
+ %18 = OpAccessChain %15 %11 %17
+ %19 = OpLoad %6 %18
+ %20 = OpAccessChain %15 %11 %12
+ %21 = OpLoad %6 %20
+ %22 = OpIAdd %6 %21 %19
+ OpStore %16 %22
+ %24 = OpAccessChain %15 %11 %17
+ %25 = OpLoad %6 %24
+ %26 = OpAccessChain %15 %11 %12
+ %27 = OpLoad %6 %26
+ %28 = OpIMul %6 %27 %25
+ OpStore %23 %28
+ OpStore %32 %35
+ %38 = OpAccessChain %36 %32 %17
+ %39 = OpLoad %29 %38
+ %40 = OpAccessChain %36 %32 %12
+ %41 = OpLoad %29 %40
+ %42 = OpFAdd %29 %41 %39
+ OpStore %37 %42
+ %44 = OpAccessChain %36 %32 %17
+ %45 = OpLoad %29 %44
+ %46 = OpAccessChain %36 %32 %12
+ %47 = OpLoad %29 %46
+ %48 = OpFMul %29 %47 %45
+ OpStore %43 %48
+ OpStore %52 %59
+ %62 = OpAccessChain %61 %52 %17
+ %63 = OpLoad %49 %62
+ %64 = OpAccessChain %61 %52 %12
+ %65 = OpLoad %49 %64
+ %66 = OpDot %29 %65 %63
+ OpStore %60 %66
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ ASSERT_TRUE(IsEqual(env, variantShader, context.get()));
+}
+
+} // namespace
+} // namespace fuzz
+} // namespace spvtools
diff --git a/utils/check_copyright.py b/utils/check_copyright.py
index 2d288a1..1e8faf0 100755
--- a/utils/check_copyright.py
+++ b/utils/check_copyright.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+# coding=utf-8
# Copyright (c) 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +32,8 @@
'Google Inc.',
'Google LLC',
'Pierre Moreau',
- 'Samsung Inc']
+ 'Samsung Inc',
+ 'André Perez Maselco']
CURRENT_YEAR='2020'
YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017|2017-2019|2018|2019|2020)'
@@ -167,7 +169,7 @@
has_apache2 = False
line_num = 0
apache_expected_end = 0
- with open(file) as contents:
+ with open(file, encoding='utf-8') as contents:
for line in contents:
line_num += 1
if COPYRIGHT_RE.search(line):