spirv-val: Add support for SPV_AMD_shader_early_and_late_fragment_tests (#4812)

- Update SPIR-V headers.
- Add validator support.
- Add validator tests.
diff --git a/DEPS b/DEPS
index 808ef6c..78c9dd3 100644
--- a/DEPS
+++ b/DEPS
@@ -6,7 +6,7 @@
   'effcee_revision': 'ddf5e2bb92957dc8a12c5392f8495333d6844133',
   'googletest_revision': '548b13dc3c02b93f60eeff9a0cc6e11c1ea722ca',
   're2_revision': '5723bb8950318135ed9cf4fc76bed988a087f536',
-  'spirv_headers_revision': '5a121866927a16ab9d49bed4788b532c7fcea766',
+  'spirv_headers_revision': 'b2a156e1c0434bc8c99aaebba1c7be98be7ac580',
 }
 
 deps = {
diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp
index 9635268..67b10c5 100644
--- a/source/val/validate_mode_setting.cpp
+++ b/source/val/validate_mode_setting.cpp
@@ -112,6 +112,44 @@
                  << "Fragment execution model entry points can specify at most "
                     "one fragment shader interlock execution mode.";
         }
+        if (execution_modes &&
+            1 < std::count_if(
+                    execution_modes->begin(), execution_modes->end(),
+                    [](const SpvExecutionMode& mode) {
+                      switch (mode) {
+                        case SpvExecutionModeStencilRefUnchangedFrontAMD:
+                        case SpvExecutionModeStencilRefLessFrontAMD:
+                        case SpvExecutionModeStencilRefGreaterFrontAMD:
+                          return true;
+                        default:
+                          return false;
+                      }
+                    })) {
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << "Fragment execution model entry points can specify at most "
+                    "one of StencilRefUnchangedFrontAMD, "
+                    "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
+                    "execution modes.";
+        }
+        if (execution_modes &&
+            1 < std::count_if(
+                    execution_modes->begin(), execution_modes->end(),
+                    [](const SpvExecutionMode& mode) {
+                      switch (mode) {
+                        case SpvExecutionModeStencilRefUnchangedBackAMD:
+                        case SpvExecutionModeStencilRefLessBackAMD:
+                        case SpvExecutionModeStencilRefGreaterBackAMD:
+                          return true;
+                        default:
+                          return false;
+                      }
+                    })) {
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << "Fragment execution model entry points can specify at most "
+                    "one of StencilRefUnchangedBackAMD, "
+                    "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
+                    "execution modes.";
+        }
         break;
       case SpvExecutionModelTessellationControl:
       case SpvExecutionModelTessellationEvaluation:
@@ -412,6 +450,13 @@
     case SpvExecutionModeSampleInterlockUnorderedEXT:
     case SpvExecutionModeShadingRateInterlockOrderedEXT:
     case SpvExecutionModeShadingRateInterlockUnorderedEXT:
+    case SpvExecutionModeEarlyAndLateFragmentTestsAMD:
+    case SpvExecutionModeStencilRefUnchangedFrontAMD:
+    case SpvExecutionModeStencilRefGreaterFrontAMD:
+    case SpvExecutionModeStencilRefLessFrontAMD:
+    case SpvExecutionModeStencilRefUnchangedBackAMD:
+    case SpvExecutionModeStencilRefGreaterBackAMD:
+    case SpvExecutionModeStencilRefLessBackAMD:
       if (!std::all_of(models->begin(), models->end(),
                        [](const SpvExecutionModel& model) {
                          return model == SpvExecutionModelFragment;
diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp
index a37989b..689f0ba 100644
--- a/test/val/val_modes_test.cpp
+++ b/test/val/val_modes_test.cpp
@@ -1101,6 +1101,89 @@
   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
 }
 
+
+TEST_F(ValidateMode, FragmentShaderStencilRefFrontTooManyModesBad) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability StencilExportEXT
+OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
+OpExtension "SPV_EXT_shader_stencil_export"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpExecutionMode %main EarlyAndLateFragmentTestsAMD
+OpExecutionMode %main StencilRefLessFrontAMD
+OpExecutionMode %main StencilRefGreaterFrontAMD
+)" + kVoidFunction;
+
+  CompileSuccessfully(spirv);
+  EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Fragment execution model entry points can specify at most "
+                "one of StencilRefUnchangedFrontAMD, "
+                "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
+                "execution modes."));
+}
+
+TEST_F(ValidateMode, FragmentShaderStencilRefBackTooManyModesBad) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability StencilExportEXT
+OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
+OpExtension "SPV_EXT_shader_stencil_export"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpExecutionMode %main EarlyAndLateFragmentTestsAMD
+OpExecutionMode %main StencilRefLessBackAMD
+OpExecutionMode %main StencilRefGreaterBackAMD
+)" + kVoidFunction;
+
+  CompileSuccessfully(spirv);
+  EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Fragment execution model entry points can specify at most "
+                "one of StencilRefUnchangedBackAMD, "
+                "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
+                "execution modes."));
+}
+
+TEST_F(ValidateMode, FragmentShaderStencilRefFrontGood) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability StencilExportEXT
+OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
+OpExtension "SPV_EXT_shader_stencil_export"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpExecutionMode %main EarlyAndLateFragmentTestsAMD
+OpExecutionMode %main StencilRefLessFrontAMD
+)" + kVoidFunction;
+
+  CompileSuccessfully(spirv);
+  EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMode, FragmentShaderStencilRefBackGood) {
+  const std::string spirv = R"(
+OpCapability Shader
+OpCapability StencilExportEXT
+OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
+OpExtension "SPV_EXT_shader_stencil_export"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpExecutionMode %main EarlyAndLateFragmentTestsAMD
+OpExecutionMode %main StencilRefLessBackAMD
+)" + kVoidFunction;
+
+  CompileSuccessfully(spirv);
+  EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
+}
+
 TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) {
   const std::string spirv = R"(
 OpCapability Shader