spirv-fuzz: Handle Vulkan SPIR-V versions (#4156)

Fixes #4155.
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 8f6c6c9..8a23392 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -775,14 +775,15 @@
 
 bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces(
     const opt::IRContext* ir_context) {
-  // TODO(afd): We capture the universal environments for which this requirement
-  //  holds.  The check should be refined on demand for other target
-  //  environments.
+  // TODO(afd): We capture the environments for which this requirement holds.
+  //  The check should be refined on demand for other target environments.
   switch (ir_context->grammar().target_env()) {
     case SPV_ENV_UNIVERSAL_1_0:
     case SPV_ENV_UNIVERSAL_1_1:
     case SPV_ENV_UNIVERSAL_1_2:
     case SPV_ENV_UNIVERSAL_1_3:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_VULKAN_1_1:
       return false;
     default:
       return true;
diff --git a/source/fuzz/transformation_flatten_conditional_branch.cpp b/source/fuzz/transformation_flatten_conditional_branch.cpp
index fdee513..c2c1a94 100644
--- a/source/fuzz/transformation_flatten_conditional_branch.cpp
+++ b/source/fuzz/transformation_flatten_conditional_branch.cpp
@@ -844,7 +844,9 @@
     case SPV_ENV_UNIVERSAL_1_0:
     case SPV_ENV_UNIVERSAL_1_1:
     case SPV_ENV_UNIVERSAL_1_2:
-    case SPV_ENV_UNIVERSAL_1_3: {
+    case SPV_ENV_UNIVERSAL_1_3:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_VULKAN_1_1: {
       return true;
     }
     default:
diff --git a/source/fuzz/transformation_set_loop_control.cpp b/source/fuzz/transformation_set_loop_control.cpp
index b2180d8..7e53911 100644
--- a/source/fuzz/transformation_set_loop_control.cpp
+++ b/source/fuzz/transformation_set_loop_control.cpp
@@ -199,14 +199,16 @@
 
 bool TransformationSetLoopControl::PeelCountIsSupported(
     opt::IRContext* ir_context) {
-  // TODO(afd): We capture the universal environments for which this loop
-  //  control is definitely not supported.  The check should be refined on
-  //  demand for other target environments.
+  // TODO(afd): We capture the environments for which this loop control is
+  //  definitely not supported.  The check should be refined on demand for other
+  //  target environments.
   switch (ir_context->grammar().target_env()) {
     case SPV_ENV_UNIVERSAL_1_0:
     case SPV_ENV_UNIVERSAL_1_1:
     case SPV_ENV_UNIVERSAL_1_2:
     case SPV_ENV_UNIVERSAL_1_3:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_VULKAN_1_1:
       return false;
     default:
       return true;
diff --git a/source/fuzz/transformation_set_memory_operands_mask.cpp b/source/fuzz/transformation_set_memory_operands_mask.cpp
index deb207a..370a70e 100644
--- a/source/fuzz/transformation_set_memory_operands_mask.cpp
+++ b/source/fuzz/transformation_set_memory_operands_mask.cpp
@@ -53,7 +53,9 @@
                SpvOpCopyMemory ||
            message_.memory_access_instruction().target_instruction_opcode() ==
                SpvOpCopyMemorySized);
-    assert(MultipleMemoryOperandMasksAreSupported(ir_context));
+    assert(MultipleMemoryOperandMasksAreSupported(ir_context) &&
+           "Multiple memory operand masks are not supported for this SPIR-V "
+           "version.");
   }
 
   auto instruction =
@@ -205,14 +207,16 @@
 
 bool TransformationSetMemoryOperandsMask::
     MultipleMemoryOperandMasksAreSupported(opt::IRContext* ir_context) {
-  // TODO(afd): We capture the universal environments for which this loop
-  //  control is definitely not supported.  The check should be refined on
-  //  demand for other target environments.
+  // TODO(afd): We capture the environments for which this loop control is
+  //  definitely not supported.  The check should be refined on demand for other
+  //  target environments.
   switch (ir_context->grammar().target_env()) {
     case SPV_ENV_UNIVERSAL_1_0:
     case SPV_ENV_UNIVERSAL_1_1:
     case SPV_ENV_UNIVERSAL_1_2:
     case SPV_ENV_UNIVERSAL_1_3:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_VULKAN_1_1:
       return false;
     default:
       return true;
diff --git a/test/fuzz/transformation_add_global_variable_test.cpp b/test/fuzz/transformation_add_global_variable_test.cpp
index eb958a7..747cc32 100644
--- a/test/fuzz/transformation_add_global_variable_test.cpp
+++ b/test/fuzz/transformation_add_global_variable_test.cpp
@@ -225,12 +225,10 @@
           %8 = OpTypeVector %6 2
           %9 = OpTypePointer Function %6
          %10 = OpTypePointer Private %6
-         %20 = OpTypePointer Uniform %6
          %11 = OpTypePointer Function %7
          %12 = OpTypePointer Private %7
          %13 = OpTypePointer Private %8
          %14 = OpVariable %10 Private
-         %15 = OpVariable %20 Uniform
          %16 = OpConstant %7 1
          %17 = OpTypePointer Private %10
          %18 = OpTypeBool
@@ -246,48 +244,96 @@
                OpFunctionEnd
   )";
 
-  const auto env = SPV_ENV_UNIVERSAL_1_4;
-  const auto consumer = nullptr;
-  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
-  spvtools::ValidatorOptions validator_options;
-  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
-                                               kConsoleMessageConsumer));
-  TransformationContext transformation_context(
-      MakeUnique<FactManager>(context.get()), validator_options);
-  TransformationAddGlobalVariable transformations[] = {
-      // %100 = OpVariable %12 Private
-      TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
-                                      true),
+  for (auto env : {SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
+                   SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_2}) {
+    const auto consumer = nullptr;
+    const auto context =
+        BuildModule(env, consumer, shader, kFuzzAssembleOption);
+    spvtools::ValidatorOptions validator_options;
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+    TransformationContext transformation_context(
+        MakeUnique<FactManager>(context.get()), validator_options);
+    TransformationAddGlobalVariable transformations[] = {
+        // %100 = OpVariable %12 Private
+        TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
+                                        true),
 
-      // %101 = OpVariable %12 Private %16
-      TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
-                                      false),
+        // %101 = OpVariable %12 Private %16
+        TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
+                                        false),
 
-      // %102 = OpVariable %19 Private %21
-      TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
-                                      true)};
+        // %102 = OpVariable %19 Private %21
+        TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
+                                        true)};
 
-  for (auto& transformation : transformations) {
+    for (auto& transformation : transformations) {
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
     ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-  ASSERT_TRUE(
-      transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
-  ASSERT_TRUE(
-      transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
-  ASSERT_FALSE(
-      transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
-  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
-                                               kConsoleMessageConsumer));
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
+    ASSERT_TRUE(
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
+    ASSERT_FALSE(
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
 
-  std::string after_transformation = R"(
+    std::string after_transformation_enlarged_interface = R"(
+                 OpCapability Shader
+            %1 = OpExtInstImport "GLSL.std.450"
+                 OpMemoryModel Logical GLSL450
+                 OpEntryPoint Fragment %4 "m1" %100 %101 %102
+                 OpEntryPoint Vertex %5 "m2" %100 %101 %102
+                 OpExecutionMode %4 OriginUpperLeft
+                 OpSource ESSL 310
+            %2 = OpTypeVoid
+            %3 = OpTypeFunction %2
+            %6 = OpTypeFloat 32
+            %7 = OpTypeInt 32 1
+            %8 = OpTypeVector %6 2
+            %9 = OpTypePointer Function %6
+           %10 = OpTypePointer Private %6
+           %11 = OpTypePointer Function %7
+           %12 = OpTypePointer Private %7
+           %13 = OpTypePointer Private %8
+           %14 = OpVariable %10 Private
+           %16 = OpConstant %7 1
+           %17 = OpTypePointer Private %10
+           %18 = OpTypeBool
+           %19 = OpTypePointer Private %18
+           %21 = OpConstantTrue %18
+          %100 = OpVariable %12 Private %16
+          %101 = OpVariable %12 Private %16
+          %102 = OpVariable %19 Private %21
+            %4 = OpFunction %2 None %3
+           %30 = OpLabel
+                 OpReturn
+                 OpFunctionEnd
+            %5 = OpFunction %2 None %3
+           %31 = OpLabel
+                 OpReturn
+                 OpFunctionEnd
+    )";
+
+    ASSERT_TRUE(
+        IsEqual(env, after_transformation_enlarged_interface, context.get()));
+  }
+}
+
+TEST(TransformationAddGlobalVariableTest,
+     TestEntryPointInterfaceNoEnlargement) {
+  // This checks that when global variables are added to a SPIR-V 1.3- module,
+  // they are not added to entry points of that module.
+  std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %4 "m1" %100 %101 %102
-               OpEntryPoint Vertex %5 "m2" %100 %101 %102
+               OpEntryPoint Fragment %4 "m1"
+               OpEntryPoint Vertex %5 "m2"
                OpExecutionMode %4 OriginUpperLeft
                OpSource ESSL 310
           %2 = OpTypeVoid
@@ -297,20 +343,15 @@
           %8 = OpTypeVector %6 2
           %9 = OpTypePointer Function %6
          %10 = OpTypePointer Private %6
-         %20 = OpTypePointer Uniform %6
          %11 = OpTypePointer Function %7
          %12 = OpTypePointer Private %7
          %13 = OpTypePointer Private %8
          %14 = OpVariable %10 Private
-         %15 = OpVariable %20 Uniform
          %16 = OpConstant %7 1
          %17 = OpTypePointer Private %10
          %18 = OpTypeBool
          %19 = OpTypePointer Private %18
          %21 = OpConstantTrue %18
-        %100 = OpVariable %12 Private %16
-        %101 = OpVariable %12 Private %16
-        %102 = OpVariable %19 Private %21
           %4 = OpFunction %2 None %3
          %30 = OpLabel
                OpReturn
@@ -320,7 +361,86 @@
                OpReturn
                OpFunctionEnd
   )";
-  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+
+  for (auto env :
+       {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
+        SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
+    const auto consumer = nullptr;
+    const auto context =
+        BuildModule(env, consumer, shader, kFuzzAssembleOption);
+    spvtools::ValidatorOptions validator_options;
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+    TransformationContext transformation_context(
+        MakeUnique<FactManager>(context.get()), validator_options);
+    TransformationAddGlobalVariable transformations[] = {
+        // %100 = OpVariable %12 Private
+        TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
+                                        true),
+
+        // %101 = OpVariable %12 Private %16
+        TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
+                                        false),
+
+        // %102 = OpVariable %19 Private %21
+        TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
+                                        true)};
+
+    for (auto& transformation : transformations) {
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+    ASSERT_TRUE(
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
+    ASSERT_TRUE(
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
+    ASSERT_FALSE(
+        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+
+    std::string after_transformation_fixed_interface = R"(
+                 OpCapability Shader
+            %1 = OpExtInstImport "GLSL.std.450"
+                 OpMemoryModel Logical GLSL450
+                 OpEntryPoint Fragment %4 "m1"
+                 OpEntryPoint Vertex %5 "m2"
+                 OpExecutionMode %4 OriginUpperLeft
+                 OpSource ESSL 310
+            %2 = OpTypeVoid
+            %3 = OpTypeFunction %2
+            %6 = OpTypeFloat 32
+            %7 = OpTypeInt 32 1
+            %8 = OpTypeVector %6 2
+            %9 = OpTypePointer Function %6
+           %10 = OpTypePointer Private %6
+           %11 = OpTypePointer Function %7
+           %12 = OpTypePointer Private %7
+           %13 = OpTypePointer Private %8
+           %14 = OpVariable %10 Private
+           %16 = OpConstant %7 1
+           %17 = OpTypePointer Private %10
+           %18 = OpTypeBool
+           %19 = OpTypePointer Private %18
+           %21 = OpConstantTrue %18
+          %100 = OpVariable %12 Private %16
+          %101 = OpVariable %12 Private %16
+          %102 = OpVariable %19 Private %21
+            %4 = OpFunction %2 None %3
+           %30 = OpLabel
+                 OpReturn
+                 OpFunctionEnd
+            %5 = OpFunction %2 None %3
+           %31 = OpLabel
+                 OpReturn
+                 OpFunctionEnd
+    )";
+
+    ASSERT_TRUE(
+        IsEqual(env, after_transformation_fixed_interface, context.get()));
+  }
 }
 
 TEST(TransformationAddGlobalVariableTest, TestAddingWorkgroupGlobals) {
diff --git a/test/fuzz/transformation_flatten_conditional_branch_test.cpp b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
index 1a0ff6a..800af0e 100644
--- a/test/fuzz/transformation_flatten_conditional_branch_test.cpp
+++ b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
@@ -1334,20 +1334,24 @@
                OpFunctionEnd
   )";
 
-  const auto env = SPV_ENV_UNIVERSAL_1_3;
-  const auto consumer = nullptr;
-  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
-  spvtools::ValidatorOptions validator_options;
-  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
-                                               kConsoleMessageConsumer));
+  for (auto env :
+       {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
+        SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
+    const auto consumer = nullptr;
+    const auto context =
+        BuildModule(env, consumer, shader, kFuzzAssembleOption);
+    spvtools::ValidatorOptions validator_options;
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
 
-  TransformationContext transformation_context(
-      MakeUnique<FactManager>(context.get()), validator_options);
+    TransformationContext transformation_context(
+        MakeUnique<FactManager>(context.get()), validator_options);
 
-  auto transformation =
-      TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
-  ASSERT_FALSE(
-      transformation.IsApplicable(context.get(), transformation_context));
+    auto transformation =
+        TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
+    ASSERT_FALSE(
+        transformation.IsApplicable(context.get(), transformation_context));
+  }
 }
 
 TEST(TransformationFlattenConditionalBranchTest,
diff --git a/test/fuzz/transformation_set_loop_control_test.cpp b/test/fuzz/transformation_set_loop_control_test.cpp
index 3312a67..060d9a8 100644
--- a/test/fuzz/transformation_set_loop_control_test.cpp
+++ b/test/fuzz/transformation_set_loop_control_test.cpp
@@ -947,7 +947,9 @@
 
   for (auto env :
        {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
-        SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5}) {
+        SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
+        SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4,
+        SPV_ENV_VULKAN_1_2}) {
     const auto consumer = nullptr;
     const auto context =
         BuildModule(env, consumer, shader, kFuzzAssembleOption);
@@ -964,6 +966,8 @@
       case SPV_ENV_UNIVERSAL_1_1:
       case SPV_ENV_UNIVERSAL_1_2:
       case SPV_ENV_UNIVERSAL_1_3:
+      case SPV_ENV_VULKAN_1_0:
+      case SPV_ENV_VULKAN_1_1:
         // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not
         // valid in the context of older versions.
         ASSERT_FALSE(
@@ -971,6 +975,8 @@
         break;
       case SPV_ENV_UNIVERSAL_1_4:
       case SPV_ENV_UNIVERSAL_1_5:
+      case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
+      case SPV_ENV_VULKAN_1_2:
         ASSERT_TRUE(
             transformation.IsApplicable(context.get(), transformation_context));
         break;
diff --git a/test/fuzz/transformation_set_memory_operands_mask_test.cpp b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
index 4763d7a..29e57f4 100644
--- a/test/fuzz/transformation_set_memory_operands_mask_test.cpp
+++ b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
@@ -90,187 +90,205 @@
                OpFunctionEnd
   )";
 
-  const auto env = SPV_ENV_UNIVERSAL_1_3;
-  const auto consumer = nullptr;
-  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
-  spvtools::ValidatorOptions validator_options;
-  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
-                                               kConsoleMessageConsumer));
-  TransformationContext transformation_context(
-      MakeUnique<FactManager>(context.get()), validator_options);
-  // Not OK: the instruction is not a memory access.
-  ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                   MakeInstructionDescriptor(21, SpvOpAccessChain, 0),
-                   SpvMemoryAccessMaskNone, 0)
-                   .IsApplicable(context.get(), transformation_context));
+  for (auto env :
+       {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
+        SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
+    const auto consumer = nullptr;
+    const auto context =
+        BuildModule(env, consumer, shader, kFuzzAssembleOption);
+    spvtools::ValidatorOptions validator_options;
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+    TransformationContext transformation_context(
+        MakeUnique<FactManager>(context.get()), validator_options);
 
-  // Not OK to remove Aligned
-  ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                   MakeInstructionDescriptor(147, SpvOpLoad, 0),
-                   SpvMemoryAccessVolatileMask | SpvMemoryAccessNontemporalMask,
-                   0)
-                   .IsApplicable(context.get(), transformation_context));
+#ifndef NDEBUG
+    {
+      // Not OK: multiple operands are not supported pre SPIR-V 1.4.
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 3),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+      ASSERT_DEATH(
+          transformation.IsApplicable(context.get(), transformation_context),
+          "Multiple memory operand masks are not supported");
+    }
+#endif
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(147, SpvOpLoad, 0),
-        SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
+    // Not OK: the instruction is not a memory access.
+    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                     MakeInstructionDescriptor(21, SpvOpAccessChain, 0),
+                     SpvMemoryAccessMaskNone, 0)
+                     .IsApplicable(context.get(), transformation_context));
+
+    // Not OK to remove Aligned
+    ASSERT_FALSE(
+        TransformationSetMemoryOperandsMask(
+            MakeInstructionDescriptor(147, SpvOpLoad, 0),
+            SpvMemoryAccessVolatileMask | SpvMemoryAccessNontemporalMask, 0)
+            .IsApplicable(context.get(), transformation_context));
+
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(147, SpvOpLoad, 0),
+          SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    // Not OK to remove Aligned
+    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                     MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+                     SpvMemoryAccessMaskNone, 0)
+                     .IsApplicable(context.get(), transformation_context));
+
+    // OK: leaves the mask as is
+    ASSERT_TRUE(TransformationSetMemoryOperandsMask(
+                    MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+                    SpvMemoryAccessAlignedMask, 0)
+                    .IsApplicable(context.get(), transformation_context));
+
+    {
+      // OK: adds Nontemporal and Volatile
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+          SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
+              SpvMemoryAccessVolatileMask,
+          0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    // Not OK to remove Volatile
+    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                     MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+                     SpvMemoryAccessNontemporalMask, 0)
+                     .IsApplicable(context.get(), transformation_context));
+
+    // Not OK to add Aligned
+    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                     MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+                     SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask,
+                     0)
+                     .IsApplicable(context.get(), transformation_context));
+
+    {
+      // OK: adds Nontemporal
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    {
+      // OK: adds Nontemporal (creates new operand)
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    {
+      // OK: adds Nontemporal and Volatile
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    {
+      // OK: removes Nontemporal, adds Volatile
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(148, SpvOpStore, 0),
+          SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
+
+    std::string after_transformation = R"(
+                 OpCapability Shader
+            %1 = OpExtInstImport "GLSL.std.450"
+                 OpMemoryModel Logical GLSL450
+                 OpEntryPoint Fragment %4 "main"
+                 OpExecutionMode %4 OriginUpperLeft
+                 OpSource ESSL 310
+                 OpName %4 "main"
+                 OpName %7 "Point3D"
+                 OpMemberName %7 0 "x"
+                 OpMemberName %7 1 "y"
+                 OpMemberName %7 2 "z"
+                 OpName %12 "global_points"
+                 OpName %15 "block"
+                 OpMemberName %15 0 "in_points"
+                 OpMemberName %15 1 "in_point"
+                 OpName %17 ""
+                 OpName %133 "local_points"
+                 OpMemberDecorate %7 0 Offset 0
+                 OpMemberDecorate %7 1 Offset 4
+                 OpMemberDecorate %7 2 Offset 8
+                 OpDecorate %10 ArrayStride 16
+                 OpMemberDecorate %15 0 Offset 0
+                 OpMemberDecorate %15 1 Offset 192
+                 OpDecorate %15 Block
+                 OpDecorate %17 DescriptorSet 0
+                 OpDecorate %17 Binding 0
+            %2 = OpTypeVoid
+            %3 = OpTypeFunction %2
+            %6 = OpTypeFloat 32
+            %7 = OpTypeStruct %6 %6 %6
+            %8 = OpTypeInt 32 0
+            %9 = OpConstant %8 12
+           %10 = OpTypeArray %7 %9
+           %11 = OpTypePointer Private %10
+           %12 = OpVariable %11 Private
+           %15 = OpTypeStruct %10 %7
+           %16 = OpTypePointer Uniform %15
+           %17 = OpVariable %16 Uniform
+           %18 = OpTypeInt 32 1
+           %19 = OpConstant %18 0
+           %20 = OpTypePointer Uniform %10
+           %24 = OpTypePointer Private %7
+           %27 = OpTypePointer Private %6
+           %30 = OpConstant %18 1
+          %132 = OpTypePointer Function %10
+          %135 = OpTypePointer Uniform %7
+          %145 = OpTypePointer Function %7
+            %4 = OpFunction %2 None %3
+            %5 = OpLabel
+          %133 = OpVariable %132 Function
+           %21 = OpAccessChain %20 %17 %19
+                 OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16
+                 OpCopyMemory %133 %12 Nontemporal|Volatile
+                 OpCopyMemory %133 %12 Nontemporal|Volatile
+          %136 = OpAccessChain %135 %17 %30
+          %138 = OpAccessChain %24 %12 %19
+                 OpCopyMemory %138 %136 Nontemporal|Volatile
+          %146 = OpAccessChain %145 %133 %30
+          %147 = OpLoad %7 %146 Aligned|Volatile 16
+          %148 = OpAccessChain %24 %12 %19
+                 OpStore %148 %147 Volatile
+                 OpReturn
+                 OpFunctionEnd
+    )";
+    ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
   }
-
-  // Not OK to remove Aligned
-  ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                   MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
-                   SpvMemoryAccessMaskNone, 0)
-                   .IsApplicable(context.get(), transformation_context));
-
-  // OK: leaves the mask as is
-  ASSERT_TRUE(TransformationSetMemoryOperandsMask(
-                  MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
-                  SpvMemoryAccessAlignedMask, 0)
-                  .IsApplicable(context.get(), transformation_context));
-
-  {
-    // OK: adds Nontemporal and Volatile
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
-        SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
-            SpvMemoryAccessVolatileMask,
-        0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-
-  // Not OK to remove Volatile
-  ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                   MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
-                   SpvMemoryAccessNontemporalMask, 0)
-                   .IsApplicable(context.get(), transformation_context));
-
-  // Not OK to add Aligned
-  ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                   MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
-                   SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0)
-                   .IsApplicable(context.get(), transformation_context));
-
-  {
-    // OK: adds Nontemporal
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-
-  {
-    // OK: adds Nontemporal (creates new operand)
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-
-  {
-    // OK: adds Nontemporal and Volatile
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-
-  {
-    // OK: removes Nontemporal, adds Volatile
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(148, SpvOpStore, 0),
-        SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
-
-  std::string after_transformation = R"(
-               OpCapability Shader
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %4 "main"
-               OpExecutionMode %4 OriginUpperLeft
-               OpSource ESSL 310
-               OpName %4 "main"
-               OpName %7 "Point3D"
-               OpMemberName %7 0 "x"
-               OpMemberName %7 1 "y"
-               OpMemberName %7 2 "z"
-               OpName %12 "global_points"
-               OpName %15 "block"
-               OpMemberName %15 0 "in_points"
-               OpMemberName %15 1 "in_point"
-               OpName %17 ""
-               OpName %133 "local_points"
-               OpMemberDecorate %7 0 Offset 0
-               OpMemberDecorate %7 1 Offset 4
-               OpMemberDecorate %7 2 Offset 8
-               OpDecorate %10 ArrayStride 16
-               OpMemberDecorate %15 0 Offset 0
-               OpMemberDecorate %15 1 Offset 192
-               OpDecorate %15 Block
-               OpDecorate %17 DescriptorSet 0
-               OpDecorate %17 Binding 0
-          %2 = OpTypeVoid
-          %3 = OpTypeFunction %2
-          %6 = OpTypeFloat 32
-          %7 = OpTypeStruct %6 %6 %6
-          %8 = OpTypeInt 32 0
-          %9 = OpConstant %8 12
-         %10 = OpTypeArray %7 %9
-         %11 = OpTypePointer Private %10
-         %12 = OpVariable %11 Private
-         %15 = OpTypeStruct %10 %7
-         %16 = OpTypePointer Uniform %15
-         %17 = OpVariable %16 Uniform
-         %18 = OpTypeInt 32 1
-         %19 = OpConstant %18 0
-         %20 = OpTypePointer Uniform %10
-         %24 = OpTypePointer Private %7
-         %27 = OpTypePointer Private %6
-         %30 = OpConstant %18 1
-        %132 = OpTypePointer Function %10
-        %135 = OpTypePointer Uniform %7
-        %145 = OpTypePointer Function %7
-          %4 = OpFunction %2 None %3
-          %5 = OpLabel
-        %133 = OpVariable %132 Function
-         %21 = OpAccessChain %20 %17 %19
-               OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16
-               OpCopyMemory %133 %12 Nontemporal|Volatile
-               OpCopyMemory %133 %12 Nontemporal|Volatile
-        %136 = OpAccessChain %135 %17 %30
-        %138 = OpAccessChain %24 %12 %19
-               OpCopyMemory %138 %136 Nontemporal|Volatile
-        %146 = OpAccessChain %145 %133 %30
-        %147 = OpLoad %7 %146 Aligned|Volatile 16
-        %148 = OpAccessChain %24 %12 %19
-               OpStore %148 %147 Volatile
-               OpReturn
-               OpFunctionEnd
-  )";
-  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
 }
 
-TEST(TransformationSetMemoryOperandsMaskTest, Spirv14) {
+TEST(TransformationSetMemoryOperandsMaskTest, Spirv14OrHigher) {
   std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -339,180 +357,183 @@
                OpFunctionEnd
   )";
 
-  const auto env = SPV_ENV_UNIVERSAL_1_4;
-  const auto consumer = nullptr;
-  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
-  spvtools::ValidatorOptions validator_options;
-  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
-                                               kConsoleMessageConsumer));
-  TransformationContext transformation_context(
-      MakeUnique<FactManager>(context.get()), validator_options);
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
-        SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
-    // Bad: cannot remove aligned
-    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                     MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
-                     SpvMemoryAccessVolatileMask, 1)
-                     .IsApplicable(context.get(), transformation_context));
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+  for (auto env : {SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
+                   SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_2}) {
+    const auto consumer = nullptr;
+    const auto context =
+        BuildModule(env, consumer, shader, kFuzzAssembleOption);
+    spvtools::ValidatorOptions validator_options;
+    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
+        context.get(), validator_options, kConsoleMessageConsumer));
+    TransformationContext transformation_context(
+        MakeUnique<FactManager>(context.get()), validator_options);
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+          SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
+      // Bad: cannot remove aligned
+      ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                       MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+                       SpvMemoryAccessVolatileMask, 1)
+                       .IsApplicable(context.get(), transformation_context));
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
-    // Bad: cannot remove volatile
-    ASSERT_FALSE(TransformationSetMemoryOperandsMask(
-                     MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
-                     SpvMemoryAccessNontemporalMask, 0)
-                     .IsApplicable(context.get(), transformation_context));
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+      // Bad: cannot remove volatile
+      ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+                       MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+                       SpvMemoryAccessNontemporalMask, 0)
+                       .IsApplicable(context.get(), transformation_context));
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    // Creates the first operand.
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      // Creates the first operand.
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    // Creates both operands.
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(21, SpvOpCopyMemory, 3),
-        SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      // Creates both operands.
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(21, SpvOpCopyMemory, 3),
+          SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
-        SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
-    // Bad: the first mask is None, so Aligned cannot be added to it.
-    ASSERT_FALSE(
-        TransformationSetMemoryOperandsMask(
-            MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
-            SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 0)
-            .IsApplicable(context.get(), transformation_context));
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+          SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
+      // Bad: the first mask is None, so Aligned cannot be added to it.
+      ASSERT_FALSE(
+          TransformationSetMemoryOperandsMask(
+              MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+              SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 0)
+              .IsApplicable(context.get(), transformation_context));
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
-        SpvMemoryAccessVolatileMask, 1);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
+          SpvMemoryAccessVolatileMask, 1);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(147, SpvOpLoad, 0),
-        SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(147, SpvOpLoad, 0),
+          SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  {
-    TransformationSetMemoryOperandsMask transformation(
-        MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone,
-        0);
-    ASSERT_TRUE(
-        transformation.IsApplicable(context.get(), transformation_context));
-    ApplyAndCheckFreshIds(transformation, context.get(),
-                          &transformation_context);
-  }
+    {
+      TransformationSetMemoryOperandsMask transformation(
+          MakeInstructionDescriptor(148, SpvOpStore, 0),
+          SpvMemoryAccessMaskNone, 0);
+      ASSERT_TRUE(
+          transformation.IsApplicable(context.get(), transformation_context));
+      ApplyAndCheckFreshIds(transformation, context.get(),
+                            &transformation_context);
+    }
 
-  std::string after_transformation = R"(
-               OpCapability Shader
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %4 "main" %12 %17
-               OpExecutionMode %4 OriginUpperLeft
-               OpSource ESSL 310
-               OpName %4 "main"
-               OpName %7 "Point3D"
-               OpMemberName %7 0 "x"
-               OpMemberName %7 1 "y"
-               OpMemberName %7 2 "z"
-               OpName %12 "global_points"
-               OpName %15 "block"
-               OpMemberName %15 0 "in_points"
-               OpMemberName %15 1 "in_point"
-               OpName %17 ""
-               OpName %133 "local_points"
-               OpMemberDecorate %7 0 Offset 0
-               OpMemberDecorate %7 1 Offset 4
-               OpMemberDecorate %7 2 Offset 8
-               OpDecorate %10 ArrayStride 16
-               OpMemberDecorate %15 0 Offset 0
-               OpMemberDecorate %15 1 Offset 192
-               OpDecorate %15 Block
-               OpDecorate %17 DescriptorSet 0
-               OpDecorate %17 Binding 0
-          %2 = OpTypeVoid
-          %3 = OpTypeFunction %2
-          %6 = OpTypeFloat 32
-          %7 = OpTypeStruct %6 %6 %6
-          %8 = OpTypeInt 32 0
-          %9 = OpConstant %8 12
-         %10 = OpTypeArray %7 %9
-         %11 = OpTypePointer Private %10
-         %12 = OpVariable %11 Private
-         %15 = OpTypeStruct %10 %7
-         %16 = OpTypePointer Uniform %15
-         %17 = OpVariable %16 Uniform
-         %18 = OpTypeInt 32 1
-         %19 = OpConstant %18 0
-         %20 = OpTypePointer Uniform %10
-         %24 = OpTypePointer Private %7
-         %27 = OpTypePointer Private %6
-         %30 = OpConstant %18 1
-        %132 = OpTypePointer Function %10
-        %135 = OpTypePointer Uniform %7
-        %145 = OpTypePointer Function %7
-          %4 = OpFunction %2 None %3
-          %5 = OpLabel
-        %133 = OpVariable %132 Function
-         %21 = OpAccessChain %20 %17 %19
-               OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16
-               OpCopyMemory %133 %12 Volatile Nontemporal|Volatile
-               OpCopyMemory %133 %12 Nontemporal|Volatile
-               OpCopyMemory %133 %12 None Nontemporal|Volatile
-        %136 = OpAccessChain %135 %17 %30
-        %138 = OpAccessChain %24 %12 %19
-               OpCopyMemory %138 %136 None Aligned|Nontemporal 16
-               OpCopyMemory %138 %136 Aligned 16 Volatile
-        %146 = OpAccessChain %145 %133 %30
-        %147 = OpLoad %7 %146 Volatile|Aligned 16
-        %148 = OpAccessChain %24 %12 %19
-               OpStore %148 %147 None
-               OpReturn
-               OpFunctionEnd
-  )";
-  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+    std::string after_transformation = R"(
+                 OpCapability Shader
+            %1 = OpExtInstImport "GLSL.std.450"
+                 OpMemoryModel Logical GLSL450
+                 OpEntryPoint Fragment %4 "main" %12 %17
+                 OpExecutionMode %4 OriginUpperLeft
+                 OpSource ESSL 310
+                 OpName %4 "main"
+                 OpName %7 "Point3D"
+                 OpMemberName %7 0 "x"
+                 OpMemberName %7 1 "y"
+                 OpMemberName %7 2 "z"
+                 OpName %12 "global_points"
+                 OpName %15 "block"
+                 OpMemberName %15 0 "in_points"
+                 OpMemberName %15 1 "in_point"
+                 OpName %17 ""
+                 OpName %133 "local_points"
+                 OpMemberDecorate %7 0 Offset 0
+                 OpMemberDecorate %7 1 Offset 4
+                 OpMemberDecorate %7 2 Offset 8
+                 OpDecorate %10 ArrayStride 16
+                 OpMemberDecorate %15 0 Offset 0
+                 OpMemberDecorate %15 1 Offset 192
+                 OpDecorate %15 Block
+                 OpDecorate %17 DescriptorSet 0
+                 OpDecorate %17 Binding 0
+            %2 = OpTypeVoid
+            %3 = OpTypeFunction %2
+            %6 = OpTypeFloat 32
+            %7 = OpTypeStruct %6 %6 %6
+            %8 = OpTypeInt 32 0
+            %9 = OpConstant %8 12
+           %10 = OpTypeArray %7 %9
+           %11 = OpTypePointer Private %10
+           %12 = OpVariable %11 Private
+           %15 = OpTypeStruct %10 %7
+           %16 = OpTypePointer Uniform %15
+           %17 = OpVariable %16 Uniform
+           %18 = OpTypeInt 32 1
+           %19 = OpConstant %18 0
+           %20 = OpTypePointer Uniform %10
+           %24 = OpTypePointer Private %7
+           %27 = OpTypePointer Private %6
+           %30 = OpConstant %18 1
+          %132 = OpTypePointer Function %10
+          %135 = OpTypePointer Uniform %7
+          %145 = OpTypePointer Function %7
+            %4 = OpFunction %2 None %3
+            %5 = OpLabel
+          %133 = OpVariable %132 Function
+           %21 = OpAccessChain %20 %17 %19
+                 OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16
+                 OpCopyMemory %133 %12 Volatile Nontemporal|Volatile
+                 OpCopyMemory %133 %12 Nontemporal|Volatile
+                 OpCopyMemory %133 %12 None Nontemporal|Volatile
+          %136 = OpAccessChain %135 %17 %30
+          %138 = OpAccessChain %24 %12 %19
+                 OpCopyMemory %138 %136 None Aligned|Nontemporal 16
+                 OpCopyMemory %138 %136 Aligned 16 Volatile
+          %146 = OpAccessChain %145 %133 %30
+          %147 = OpLoad %7 %146 Volatile|Aligned 16
+          %148 = OpAccessChain %24 %12 %19
+                 OpStore %148 %147 None
+                 OpReturn
+                 OpFunctionEnd
+    )";
+    ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+  }
 }
 
 }  // namespace