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):