spirv-fuzz: Support OpNot bit instruction case (#3841)

This PR implements the OpNot instruction for the
add bit instruction synonym transformation. In addition,
some code improvements have been made.
diff --git a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp
index 1547810..bd2dd3d 100644
--- a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp
@@ -47,7 +47,8 @@
         //  |spvOpcodeIsBit|.
         if (instruction.opcode() != SpvOpBitwiseOr &&
             instruction.opcode() != SpvOpBitwiseXor &&
-            instruction.opcode() != SpvOpBitwiseAnd) {
+            instruction.opcode() != SpvOpBitwiseAnd &&
+            instruction.opcode() != SpvOpNot) {
           continue;
         }
 
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
index 0c2d2a9..731074f 100644
--- a/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -545,11 +545,11 @@
   //   OpBitwiseOr
   //   OpBitwiseXor
   //   OpBitwiseAnd
+  //   OpNot
   // To be supported in the future:
   //   OpShiftRightLogical
   //   OpShiftRightArithmetic
   //   OpShiftLeftLogical
-  //   OpNot
   //   OpBitReverse
   //   OpBitCount
 
diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.cpp b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
index 50d03e7..3e15c26 100644
--- a/source/fuzz/transformation_add_bit_instruction_synonym.cpp
+++ b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
@@ -98,7 +98,9 @@
     case SpvOpBitwiseOr:
     case SpvOpBitwiseXor:
     case SpvOpBitwiseAnd:
-      AddBitwiseSynonym(ir_context, transformation_context, bit_instruction);
+    case SpvOpNot:
+      AddOpBitwiseOrOpNotSynonym(ir_context, transformation_context,
+                                 bit_instruction);
       break;
     default:
       assert(false && "Should be unreachable.");
@@ -123,7 +125,9 @@
     case SpvOpBitwiseOr:
     case SpvOpBitwiseXor:
     case SpvOpBitwiseAnd:
-      return 4 * ir_context->get_type_mgr()
+    case SpvOpNot:
+      return (2 + bit_instruction->NumInOperands()) *
+                 ir_context->get_type_mgr()
                      ->GetType(bit_instruction->type_id())
                      ->AsInteger()
                      ->width() -
@@ -134,7 +138,7 @@
   }
 }
 
-void TransformationAddBitInstructionSynonym::AddBitwiseSynonym(
+void TransformationAddBitInstructionSynonym::AddOpBitwiseOrOpNotSynonym(
     opt::IRContext* ir_context, TransformationContext* transformation_context,
     opt::Instruction* bit_instruction) const {
   // Fresh id iterator.
@@ -150,9 +154,10 @@
   const uint32_t count = fuzzerutil::MaybeGetIntegerConstant(
       ir_context, *transformation_context, {1}, 32, false, false);
 
-  // |bitwise_ids| is the collection of OpBiwise* instructions that evaluate a
-  // pair of extracted bits. Those ids will be used to insert the result bits.
-  std::vector<uint32_t> bitwise_ids(width);
+  // |extracted_bit_instructions| is the collection of OpBiwise* or OpNot
+  // instructions that evaluate the extracted bits. Those ids will be used to
+  // insert the result bits.
+  std::vector<uint32_t> extracted_bit_instructions(width);
 
   for (uint32_t i = 0; i < width; i++) {
     // |offset| is the current bit index.
@@ -160,7 +165,7 @@
         ir_context, *transformation_context, {i}, 32, false, false);
 
     // |bit_extract_ids| are the two extracted bits from the operands.
-    std::vector<uint32_t> bit_extract_ids;
+    opt::Instruction::OperandList bit_extract_ids;
 
     // Extracts the i-th bit from operands.
     for (auto operand = bit_instruction->begin() + 2;
@@ -173,30 +178,31 @@
                             {SPV_OPERAND_TYPE_ID, {count}}});
       bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bit_extract));
       fuzzerutil::UpdateModuleIdBound(ir_context, bit_extract.result_id());
-      bit_extract_ids.push_back(bit_extract.result_id());
+      bit_extract_ids.push_back(
+          {SPV_OPERAND_TYPE_ID, {bit_extract.result_id()}});
     }
 
-    // Applies |bit_instruction| to the pair of extracted bits.
-    auto bitwise =
-        opt::Instruction(ir_context, bit_instruction->opcode(),
-                         bit_instruction->type_id(), *fresh_id++,
-                         {{SPV_OPERAND_TYPE_ID, {bit_extract_ids[0]}},
-                          {SPV_OPERAND_TYPE_ID, {bit_extract_ids[1]}}});
-    bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bitwise));
-    fuzzerutil::UpdateModuleIdBound(ir_context, bitwise.result_id());
-    bitwise_ids[i] = bitwise.result_id();
+    // Applies |bit_instruction| to the extracted bits.
+    auto extracted_bit_instruction = opt::Instruction(
+        ir_context, bit_instruction->opcode(), bit_instruction->type_id(),
+        *fresh_id++, bit_extract_ids);
+    bit_instruction->InsertBefore(
+        MakeUnique<opt::Instruction>(extracted_bit_instruction));
+    fuzzerutil::UpdateModuleIdBound(ir_context,
+                                    extracted_bit_instruction.result_id());
+    extracted_bit_instructions[i] = extracted_bit_instruction.result_id();
   }
 
-  // The first two ids in |bitwise_ids| are used to insert the first two bits of
-  // the result.
+  // The first two ids in |extracted_bit_instructions| are used to insert the
+  // first two bits of the result.
   uint32_t offset = fuzzerutil::MaybeGetIntegerConstant(
       ir_context, *transformation_context, {1}, 32, false, false);
-  auto bit_insert = opt::Instruction(ir_context, SpvOpBitFieldInsert,
-                                     bit_instruction->type_id(), *fresh_id++,
-                                     {{SPV_OPERAND_TYPE_ID, {bitwise_ids[0]}},
-                                      {SPV_OPERAND_TYPE_ID, {bitwise_ids[1]}},
-                                      {SPV_OPERAND_TYPE_ID, {offset}},
-                                      {SPV_OPERAND_TYPE_ID, {count}}});
+  auto bit_insert = opt::Instruction(
+      ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(), *fresh_id++,
+      {{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[0]}},
+       {SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[1]}},
+       {SPV_OPERAND_TYPE_ID, {offset}},
+       {SPV_OPERAND_TYPE_ID, {count}}});
   bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bit_insert));
   fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id());
 
@@ -204,13 +210,13 @@
   for (uint32_t i = 2; i < width; i++) {
     offset = fuzzerutil::MaybeGetIntegerConstant(
         ir_context, *transformation_context, {i}, 32, false, false);
-    bit_insert =
-        opt::Instruction(ir_context, SpvOpBitFieldInsert,
-                         bit_instruction->type_id(), *fresh_id++,
-                         {{SPV_OPERAND_TYPE_ID, {bit_insert.result_id()}},
-                          {SPV_OPERAND_TYPE_ID, {bitwise_ids[i]}},
-                          {SPV_OPERAND_TYPE_ID, {offset}},
-                          {SPV_OPERAND_TYPE_ID, {count}}});
+    bit_insert = opt::Instruction(
+        ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(),
+        *fresh_id++,
+        {{SPV_OPERAND_TYPE_ID, {bit_insert.result_id()}},
+         {SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[i]}},
+         {SPV_OPERAND_TYPE_ID, {offset}},
+         {SPV_OPERAND_TYPE_ID, {count}}});
     bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bit_insert));
     fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id());
   }
diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.h b/source/fuzz/transformation_add_bit_instruction_synonym.h
index 1baf959..c87d015 100644
--- a/source/fuzz/transformation_add_bit_instruction_synonym.h
+++ b/source/fuzz/transformation_add_bit_instruction_synonym.h
@@ -129,10 +129,10 @@
  private:
   protobufs::TransformationAddBitInstructionSynonym message_;
 
-  // Adds an OpBitwise* synonym.
-  void AddBitwiseSynonym(opt::IRContext* ir_context,
-                         TransformationContext* transformation_context,
-                         opt::Instruction* bitwise_instruction) const;
+  // Adds OpBitwise* or OpNot synonym.
+  void AddOpBitwiseOrOpNotSynonym(opt::IRContext* ir_context,
+                                  TransformationContext* transformation_context,
+                                  opt::Instruction* bitwise_instruction) const;
 };
 
 }  // namespace fuzz
diff --git a/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
index bf59064..e0e623c 100644
--- a/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
+++ b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
@@ -160,7 +160,7 @@
       transformation.IsApplicable(context.get(), transformation_context));
 }
 
-TEST(TransformationAddBitInstructionSynonymTest, AddBitwiseSynonym) {
+TEST(TransformationAddBitInstructionSynonymTest, AddOpBitwiseOrSynonym) {
   std::string reference_shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -209,7 +209,7 @@
 ; main function
          %37 = OpFunction %3 None %4
          %38 = OpLabel
-         %39 = OpBitwiseOr %2 %5 %6
+         %39 = OpBitwiseOr %2 %5 %6 ; bit instruction
                OpReturn
                OpFunctionEnd
   )";
@@ -223,6 +223,8 @@
   spvtools::ValidatorOptions validator_options;
   TransformationContext transformation_context(
       MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Adds OpBitwiseOr synonym.
   auto transformation = TransformationAddBitInstructionSynonym(
       39, {40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,
            53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,
@@ -235,6 +237,8 @@
            144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
            157, 158, 159, 160, 161, 162, 163, 164, 165, 166});
   transformation.Apply(context.get(), &transformation_context);
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(166, {}), MakeDataDescriptor(39, {})));
 
   std::string variant_shader = R"(
                OpCapability Shader
@@ -285,6 +289,7 @@
          %37 = OpFunction %3 None %4
          %38 = OpLabel
 
+; Add OpBitwiseOr synonym
          %40 = OpBitFieldUExtract %2 %5 %5 %6 ; extracts bit 0 from %5
          %41 = OpBitFieldUExtract %2 %6 %5 %6 ; extracts bit 0 from %6
          %42 = OpBitwiseOr %2 %40 %41
@@ -451,8 +456,269 @@
 
   ASSERT_TRUE(IsValid(env, context.get()));
   ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
+}
+
+TEST(TransformationAddBitInstructionSynonymTest, AddOpNotSynonym) {
+  std::string reference_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %37 "main"
+
+; Types
+          %2 = OpTypeInt 32 0
+          %3 = OpTypeVoid
+          %4 = OpTypeFunction %3
+
+; Constants
+          %5 = OpConstant %2 0
+          %6 = OpConstant %2 1
+          %7 = OpConstant %2 2
+          %8 = OpConstant %2 3
+          %9 = OpConstant %2 4
+         %10 = OpConstant %2 5
+         %11 = OpConstant %2 6
+         %12 = OpConstant %2 7
+         %13 = OpConstant %2 8
+         %14 = OpConstant %2 9
+         %15 = OpConstant %2 10
+         %16 = OpConstant %2 11
+         %17 = OpConstant %2 12
+         %18 = OpConstant %2 13
+         %19 = OpConstant %2 14
+         %20 = OpConstant %2 15
+         %21 = OpConstant %2 16
+         %22 = OpConstant %2 17
+         %23 = OpConstant %2 18
+         %24 = OpConstant %2 19
+         %25 = OpConstant %2 20
+         %26 = OpConstant %2 21
+         %27 = OpConstant %2 22
+         %28 = OpConstant %2 23
+         %29 = OpConstant %2 24
+         %30 = OpConstant %2 25
+         %31 = OpConstant %2 26
+         %32 = OpConstant %2 27
+         %33 = OpConstant %2 28
+         %34 = OpConstant %2 29
+         %35 = OpConstant %2 30
+         %36 = OpConstant %2 31
+
+; main function
+         %37 = OpFunction %3 None %4
+         %38 = OpLabel
+         %39 = OpNot %2 %5 ; bit instruction
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context =
+      BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Adds OpNot synonym.
+  auto transformation = TransformationAddBitInstructionSynonym(
+      39, {40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,
+           54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
+           68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,
+           82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
+           96,  97,  98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+           110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123,
+           124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134});
+  transformation.Apply(context.get(), &transformation_context);
   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
-      MakeDataDescriptor(166, {}), MakeDataDescriptor(39, {})));
+      MakeDataDescriptor(134, {}), MakeDataDescriptor(39, {})));
+
+  std::string variant_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %37 "main"
+
+; Types
+          %2 = OpTypeInt 32 0
+          %3 = OpTypeVoid
+          %4 = OpTypeFunction %3
+
+; Constants
+          %5 = OpConstant %2 0
+          %6 = OpConstant %2 1
+          %7 = OpConstant %2 2
+          %8 = OpConstant %2 3
+          %9 = OpConstant %2 4
+         %10 = OpConstant %2 5
+         %11 = OpConstant %2 6
+         %12 = OpConstant %2 7
+         %13 = OpConstant %2 8
+         %14 = OpConstant %2 9
+         %15 = OpConstant %2 10
+         %16 = OpConstant %2 11
+         %17 = OpConstant %2 12
+         %18 = OpConstant %2 13
+         %19 = OpConstant %2 14
+         %20 = OpConstant %2 15
+         %21 = OpConstant %2 16
+         %22 = OpConstant %2 17
+         %23 = OpConstant %2 18
+         %24 = OpConstant %2 19
+         %25 = OpConstant %2 20
+         %26 = OpConstant %2 21
+         %27 = OpConstant %2 22
+         %28 = OpConstant %2 23
+         %29 = OpConstant %2 24
+         %30 = OpConstant %2 25
+         %31 = OpConstant %2 26
+         %32 = OpConstant %2 27
+         %33 = OpConstant %2 28
+         %34 = OpConstant %2 29
+         %35 = OpConstant %2 30
+         %36 = OpConstant %2 31
+
+; main function
+         %37 = OpFunction %3 None %4
+         %38 = OpLabel
+
+; Add OpNot synonym
+         %40 = OpBitFieldUExtract %2 %5 %5 %6 ; extracts bit 0 from %5
+         %41 = OpNot %2 %40
+
+         %42 = OpBitFieldUExtract %2 %5 %6 %6 ; extracts bit 1 from %5
+         %43 = OpNot %2 %42
+
+         %44 = OpBitFieldUExtract %2 %5 %7 %6 ; extracts bit 2 from %5
+         %45 = OpNot %2 %44
+
+         %46 = OpBitFieldUExtract %2 %5 %8 %6 ; extracts bit 3 from %5
+         %47 = OpNot %2 %46
+
+         %48 = OpBitFieldUExtract %2 %5 %9 %6 ; extracts bit 4 from %5
+         %49 = OpNot %2 %48
+
+         %50 = OpBitFieldUExtract %2 %5 %10 %6 ; extracts bit 5 from %5
+         %51 = OpNot %2 %50
+
+         %52 = OpBitFieldUExtract %2 %5 %11 %6 ; extracts bit 6 from %5
+         %53 = OpNot %2 %52
+
+         %54 = OpBitFieldUExtract %2 %5 %12 %6 ; extracts bit 7 from %5
+         %55 = OpNot %2 %54
+
+         %56 = OpBitFieldUExtract %2 %5 %13 %6 ; extracts bit 8 from %5
+         %57 = OpNot %2 %56
+
+         %58 = OpBitFieldUExtract %2 %5 %14 %6 ; extracts bit 9 from %5
+         %59 = OpNot %2 %58
+
+         %60 = OpBitFieldUExtract %2 %5 %15 %6 ; extracts bit 10 from %5
+         %61 = OpNot %2 %60
+
+         %62 = OpBitFieldUExtract %2 %5 %16 %6 ; extracts bit 11 from %5
+         %63 = OpNot %2 %62
+
+         %64 = OpBitFieldUExtract %2 %5 %17 %6 ; extracts bit 12 from %5
+         %65 = OpNot %2 %64
+
+         %66 = OpBitFieldUExtract %2 %5 %18 %6 ; extracts bit 13 from %5
+         %67 = OpNot %2 %66
+
+         %68 = OpBitFieldUExtract %2 %5 %19 %6 ; extracts bit 14 from %5
+         %69 = OpNot %2 %68
+
+         %70 = OpBitFieldUExtract %2 %5 %20 %6 ; extracts bit 15 from %5
+         %71 = OpNot %2 %70
+
+         %72 = OpBitFieldUExtract %2 %5 %21 %6 ; extracts bit 16 from %5
+         %73 = OpNot %2 %72
+
+         %74 = OpBitFieldUExtract %2 %5 %22 %6 ; extracts bit 17 from %5
+         %75 = OpNot %2 %74
+
+         %76 = OpBitFieldUExtract %2 %5 %23 %6 ; extracts bit 18 from %5
+         %77 = OpNot %2 %76
+
+         %78 = OpBitFieldUExtract %2 %5 %24 %6 ; extracts bit 19 from %5
+         %79 = OpNot %2 %78
+
+         %80 = OpBitFieldUExtract %2 %5 %25 %6 ; extracts bit 20 from %5
+         %81 = OpNot %2 %80
+
+         %82 = OpBitFieldUExtract %2 %5 %26 %6 ; extracts bit 21 from %5
+         %83 = OpNot %2 %82
+
+         %84 = OpBitFieldUExtract %2 %5 %27 %6 ; extracts bit 22 from %5
+         %85 = OpNot %2 %84
+
+         %86 = OpBitFieldUExtract %2 %5 %28 %6 ; extracts bit 23 from %5
+         %87 = OpNot %2 %86
+
+         %88 = OpBitFieldUExtract %2 %5 %29 %6 ; extracts bit 24 from %5
+         %89 = OpNot %2 %88
+
+         %90 = OpBitFieldUExtract %2 %5 %30 %6 ; extracts bit 25 from %5
+         %91 = OpNot %2 %90
+
+         %92 = OpBitFieldUExtract %2 %5 %31 %6 ; extracts bit 26 from %5
+         %93 = OpNot %2 %92
+
+         %94 = OpBitFieldUExtract %2 %5 %32 %6 ; extracts bit 27 from %5
+         %95 = OpNot %2 %94
+
+         %96 = OpBitFieldUExtract %2 %5 %33 %6 ; extracts bit 28 from %5
+         %97 = OpNot %2 %96
+
+         %98 = OpBitFieldUExtract %2 %5 %34 %6 ; extracts bit 29 from %5
+         %99 = OpNot %2 %98
+
+        %100 = OpBitFieldUExtract %2 %5 %35 %6 ; extracts bit 30 from %5
+        %101 = OpNot %2 %100
+
+        %102 = OpBitFieldUExtract %2 %5 %36 %6 ; extracts bit 31 from %5
+        %103 = OpNot %2 %102
+
+        %104 = OpBitFieldInsert %2 %41 %43 %6 %6 ; inserts bit 1
+        %105 = OpBitFieldInsert %2 %104 %45 %7 %6 ; inserts bit 2
+        %106 = OpBitFieldInsert %2 %105 %47 %8 %6 ; inserts bit 3
+        %107 = OpBitFieldInsert %2 %106 %49 %9 %6 ; inserts bit 4
+        %108 = OpBitFieldInsert %2 %107 %51 %10 %6 ; inserts bit 5
+        %109 = OpBitFieldInsert %2 %108 %53 %11 %6 ; inserts bit 6
+        %110 = OpBitFieldInsert %2 %109 %55 %12 %6 ; inserts bit 7
+        %111 = OpBitFieldInsert %2 %110 %57 %13 %6 ; inserts bit 8
+        %112 = OpBitFieldInsert %2 %111 %59 %14 %6 ; inserts bit 9
+        %113 = OpBitFieldInsert %2 %112 %61 %15 %6 ; inserts bit 10
+        %114 = OpBitFieldInsert %2 %113 %63 %16 %6 ; inserts bit 11
+        %115 = OpBitFieldInsert %2 %114 %65 %17 %6 ; inserts bit 12
+        %116 = OpBitFieldInsert %2 %115 %67 %18 %6 ; inserts bit 13
+        %117 = OpBitFieldInsert %2 %116 %69 %19 %6 ; inserts bit 14
+        %118 = OpBitFieldInsert %2 %117 %71 %20 %6 ; inserts bit 15
+        %119 = OpBitFieldInsert %2 %118 %73 %21 %6 ; inserts bit 16
+        %120 = OpBitFieldInsert %2 %119 %75 %22 %6 ; inserts bit 17
+        %121 = OpBitFieldInsert %2 %120 %77 %23 %6 ; inserts bit 18
+        %122 = OpBitFieldInsert %2 %121 %79 %24 %6 ; inserts bit 19
+        %123 = OpBitFieldInsert %2 %122 %81 %25 %6 ; inserts bit 20
+        %124 = OpBitFieldInsert %2 %123 %83 %26 %6 ; inserts bit 21
+        %125 = OpBitFieldInsert %2 %124 %85 %27 %6 ; inserts bit 22
+        %126 = OpBitFieldInsert %2 %125 %87 %28 %6 ; inserts bit 23
+        %127 = OpBitFieldInsert %2 %126 %89 %29 %6 ; inserts bit 24
+        %128 = OpBitFieldInsert %2 %127 %91 %30 %6 ; inserts bit 25
+        %129 = OpBitFieldInsert %2 %128 %93 %31 %6 ; inserts bit 26
+        %130 = OpBitFieldInsert %2 %129 %95 %32 %6 ; inserts bit 27
+        %131 = OpBitFieldInsert %2 %130 %97 %33 %6 ; inserts bit 28
+        %132 = OpBitFieldInsert %2 %131 %99 %34 %6 ; inserts bit 29
+        %133 = OpBitFieldInsert %2 %132 %101 %35 %6 ; inserts bit 30
+        %134 = OpBitFieldInsert %2 %133 %103 %36 %6 ; inserts bit 31
+         %39 = OpNot %2 %5
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  ASSERT_TRUE(IsValid(env, context.get()));
+  ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
 }
 
 }  // namespace