Add validation for SPV_EXT_shader_atomic_float_min_max (#4105)

* Add an "extra_defs" parameter to GenerateShaderCode in atomics_test

* Add validation for SPV_EXT_shader_atomic_float_min_max
diff --git a/source/opcode.cpp b/source/opcode.cpp
index d87e828..c96cde8 100644
--- a/source/opcode.cpp
+++ b/source/opcode.cpp
@@ -417,8 +417,10 @@
     case SpvOpAtomicISub:
     case SpvOpAtomicSMin:
     case SpvOpAtomicUMin:
+    case SpvOpAtomicFMinEXT:
     case SpvOpAtomicSMax:
     case SpvOpAtomicUMax:
+    case SpvOpAtomicFMaxEXT:
     case SpvOpAtomicAnd:
     case SpvOpAtomicOr:
     case SpvOpAtomicXor:
diff --git a/source/opt/code_sink.cpp b/source/opt/code_sink.cpp
index e49029f..cd77797 100644
--- a/source/opt/code_sink.cpp
+++ b/source/opt/code_sink.cpp
@@ -218,8 +218,10 @@
       case SpvOpAtomicISub:
       case SpvOpAtomicSMin:
       case SpvOpAtomicUMin:
+      case SpvOpAtomicFMinEXT:
       case SpvOpAtomicSMax:
       case SpvOpAtomicUMax:
+      case SpvOpAtomicFMaxEXT:
       case SpvOpAtomicAnd:
       case SpvOpAtomicOr:
       case SpvOpAtomicXor:
diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp
index a9fc2b4..fa53ca1 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -61,6 +61,8 @@
 bool HasOnlyFloatReturnType(uint32_t opcode) {
   switch (opcode) {
     case SpvOpAtomicFAddEXT:
+    case SpvOpAtomicFMinEXT:
+    case SpvOpAtomicFMaxEXT:
       return true;
       break;
     default:
@@ -132,8 +134,10 @@
     case SpvOpAtomicISub:
     case SpvOpAtomicSMin:
     case SpvOpAtomicUMin:
+    case SpvOpAtomicFMinEXT:
     case SpvOpAtomicSMax:
     case SpvOpAtomicUMax:
+    case SpvOpAtomicFMaxEXT:
     case SpvOpAtomicAnd:
     case SpvOpAtomicOr:
     case SpvOpAtomicXor:
@@ -232,6 +236,29 @@
                    << ": float add atomics require the AtomicFloat64AddEXT "
                       "capability";
           }
+        } else if (opcode == SpvOpAtomicFMinEXT ||
+                   opcode == SpvOpAtomicFMaxEXT) {
+          if ((_.GetBitWidth(result_type) == 16) &&
+              (!_.HasCapability(SpvCapabilityAtomicFloat16MinMaxEXT))) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << spvOpcodeString(opcode)
+                   << ": float min/max atomics require the "
+                      "AtomicFloat16MinMaxEXT capability";
+          }
+          if ((_.GetBitWidth(result_type) == 32) &&
+              (!_.HasCapability(SpvCapabilityAtomicFloat32MinMaxEXT))) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << spvOpcodeString(opcode)
+                   << ": float min/max atomics require the "
+                      "AtomicFloat32MinMaxEXT capability";
+          }
+          if ((_.GetBitWidth(result_type) == 64) &&
+              (!_.HasCapability(SpvCapabilityAtomicFloat64MinMaxEXT))) {
+            return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                   << spvOpcodeString(opcode)
+                   << ": float min/max atomics require the "
+                      "AtomicFloat64MinMaxEXT capability";
+          }
         }
       }
 
diff --git a/test/enum_string_mapping_test.cpp b/test/enum_string_mapping_test.cpp
index 9bbd8ca..52aa653 100644
--- a/test/enum_string_mapping_test.cpp
+++ b/test/enum_string_mapping_test.cpp
@@ -181,6 +181,8 @@
          {SpvCapabilityDeviceGroup, "DeviceGroup"},
          {SpvCapabilityAtomicFloat32AddEXT, "AtomicFloat32AddEXT"},
          {SpvCapabilityAtomicFloat64AddEXT, "AtomicFloat64AddEXT"},
+         {SpvCapabilityAtomicFloat32MinMaxEXT, "AtomicFloat32MinMaxEXT"},
+         {SpvCapabilityAtomicFloat64MinMaxEXT, "AtomicFloat64MinMaxEXT"},
          {SpvCapabilityMultiView, "MultiView"},
          {SpvCapabilityInt64ImageEXT, "Int64ImageEXT"},
          {SpvCapabilitySampleMaskOverrideCoverageNV,
diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp
index e60f596..e2ca71f 100644
--- a/test/val/val_atomics_test.cpp
+++ b/test/val/val_atomics_test.cpp
@@ -95,6 +95,7 @@
 std::string GenerateShaderCode(
     const std::string& body,
     const std::string& capabilities_and_extensions = "",
+    const std::string& extra_defs = "",
     const std::string& memory_model = "GLSL450") {
   const std::string execution = R"(
 OpEntryPoint Fragment %main "main"
@@ -113,7 +114,8 @@
 %s64_var = OpVariable %s64_ptr Workgroup
 )";
   return GenerateShaderCodeImpl(
-      body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
+      body, "OpCapability Int64\n" + capabilities_and_extensions,
+      defintions + extra_defs,
       memory_model, execution);
 }
 
@@ -304,6 +306,32 @@
                 "AtomicFloat32AddEXT AtomicFloat64AddEXT"));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloatVulkan) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body));
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Opcode AtomicFMinEXT requires one of these capabilities: "
+                "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloatVulkan) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body));
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Opcode AtomicFMaxEXT requires one of these capabilities: "
+                "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
+}
+
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType1) {
   const std::string body = R"(
 %val1 = OpAtomicFAddEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
@@ -320,6 +348,38 @@
                         "expected Result Type to be float scalar type"));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType1) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMinEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType1) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMaxEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType2) {
   const std::string body = R"(
 %val1 = OpAtomicFAddEXT %u32 %u32_var %device %relaxed %u32_1
@@ -336,6 +396,38 @@
                         "expected Result Type to be float scalar type"));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType2) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %u32 %u32_var %device %relaxed %u32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMinEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType2) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %u32 %u32_var %device %relaxed %u32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMaxEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType3) {
   const std::string body = R"(
 %val1 = OpAtomicFAddEXT %u64 %u64_var %device %relaxed %u64_1
@@ -352,6 +444,38 @@
                         "expected Result Type to be float scalar type"));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType3) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %u64 %u64_var %device %relaxed %u64_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMinEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType3) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %u64 %u64_var %device %relaxed %u64_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMaxEXT: "
+                        "expected Result Type to be float scalar type"));
+}
+
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongCapability) {
   const std::string body = R"(
 %val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
@@ -368,6 +492,38 @@
                         "require the AtomicFloat32AddEXT capability"));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongCapability) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat64MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMinEXT: float min/max atomics "
+                        "require the AtomicFloat32MinMaxEXT capability"));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongCapability) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat64MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("AtomicFMaxEXT: float min/max atomics "
+                        "require the AtomicFloat32MinMaxEXT capability"));
+}
+
 TEST_F(ValidateAtomics, AtomicAddFloatVulkanSuccess) {
   const std::string body = R"(
 %val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
@@ -382,6 +538,112 @@
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
 }
 
+TEST_F(ValidateAtomics, AtomicMinFloat16VulkanSuccess) {
+  const std::string defs = R"(
+%f16 = OpTypeFloat 16
+%f16_1 = OpConstant %f16 1
+%f16_ptr = OpTypePointer Workgroup %f16
+%f16_var = OpVariable %f16_ptr Workgroup
+)";
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f16 %f16_var %device %relaxed %f16_1
+)";
+  const std::string extra = R"(
+OpCapability Float16
+OpCapability AtomicFloat16MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloat16VulkanSuccess) {
+  const std::string defs = R"(
+%f16 = OpTypeFloat 16
+%f16_1 = OpConstant %f16 1
+%f16_ptr = OpTypePointer Workgroup %f16
+%f16_var = OpVariable %f16_ptr Workgroup
+)";
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f16 %f16_var %device %relaxed %f16_1
+)";
+  const std::string extra = R"(
+OpCapability Float16
+OpCapability AtomicFloat16MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateAtomics, AtomicMinFloat32VulkanSuccess) {
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloat32VulkanSuccess) {
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
+)";
+  const std::string extra = R"(
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateAtomics, AtomicMinFloat64VulkanSuccess) {
+  const std::string defs = R"(
+%f64 = OpTypeFloat 64
+%f64_1 = OpConstant %f64 1
+%f64_ptr = OpTypePointer Workgroup %f64
+%f64_var = OpVariable %f64_ptr Workgroup
+)";
+  const std::string body = R"(
+%val1 = OpAtomicFMinEXT %f64 %f64_var %device %relaxed %f64_1
+)";
+  const std::string extra = R"(
+OpCapability Float64
+OpCapability AtomicFloat64MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateAtomics, AtomicMaxFloat64VulkanSuccess) {
+  const std::string defs = R"(
+%f64 = OpTypeFloat 64
+%f64_1 = OpConstant %f64 1
+%f64_ptr = OpTypePointer Workgroup %f64
+%f64_var = OpVariable %f64_ptr Workgroup
+)";
+  const std::string body = R"(
+%val1 = OpAtomicFMaxEXT %f64 %f64_var %device %relaxed %f64_1
+)";
+  const std::string extra = R"(
+OpCapability Float64
+OpCapability AtomicFloat64MinMaxEXT
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
 TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
   const std::string body = R"(
 %val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
@@ -1479,7 +1741,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1498,7 +1760,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1518,7 +1780,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1538,7 +1800,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1558,7 +1820,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1578,7 +1840,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1598,7 +1860,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1617,7 +1879,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1636,7 +1898,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1655,7 +1917,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1674,7 +1936,28 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
+                      SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("SequentiallyConsistent memory semantics cannot be "
+                        "used with the VulkanKHR memory model."));
+}
+
+TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicFMinEXT) {
+  const std::string body = R"(
+%max = OpAtomicFMinEXT %f32 %f32_var %workgroup %sequentially_consistent %f32_0
+)";
+
+  const std::string extra = R"(
+OpCapability VulkanMemoryModelKHR
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1693,7 +1976,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1712,7 +1995,28 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
+                      SPV_ENV_UNIVERSAL_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("SequentiallyConsistent memory semantics cannot be "
+                        "used with the VulkanKHR memory model."));
+}
+
+TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicFMaxEXT) {
+  const std::string body = R"(
+%max = OpAtomicFMaxEXT %f32 %f32_var %workgroup %sequentially_consistent %f32_0
+)";
+
+  const std::string extra = R"(
+OpCapability VulkanMemoryModelKHR
+OpCapability AtomicFloat32MinMaxEXT
+OpExtension "SPV_KHR_vulkan_memory_model"
+OpExtension "SPV_EXT_shader_atomic_float_min_max"
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1731,7 +2035,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1750,7 +2054,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1769,7 +2073,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -1993,7 +2297,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_VULKAN_1_1);
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
 }
@@ -2121,7 +2425,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
@@ -2141,7 +2445,7 @@
 OpExtension "SPV_KHR_vulkan_memory_model"
 )";
 
-  CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"),
+  CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
                       SPV_ENV_UNIVERSAL_1_3);
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
 }