Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430)

* Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass.

* Add SPV_NV_compute_shader_derivatives to allow lists

No tests needed for this. The code path is well tested. Just adding new
data.

diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp
index 55feca8..b372571 100644
--- a/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -941,6 +941,8 @@
 
 void AggressiveDCEPass::InitExtensions() {
   extensions_allowlist_.clear();
+
+  // clang-format off
   extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
@@ -1001,7 +1003,9 @@
       "SPV_NV_bindless_texture",
       "SPV_EXT_shader_atomic_float_add",
       "SPV_EXT_fragment_shader_interlock",
+      "SPV_NV_compute_shader_derivatives"
   });
+  // clang-format on
 }
 
 Instruction* AggressiveDCEPass::GetHeaderBranch(BasicBlock* blk) {
diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp
index fac4cea..ea1bdee 100644
--- a/source/opt/local_access_chain_convert_pass.cpp
+++ b/source/opt/local_access_chain_convert_pass.cpp
@@ -428,7 +428,8 @@
        "SPV_KHR_uniform_group_instructions",
        "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model",
        "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add",
-       "SPV_EXT_fragment_shader_interlock"});
+       "SPV_EXT_fragment_shader_interlock",
+       "SPV_NV_compute_shader_derivatives"});
 }
 
 bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(
diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp
index 0acffda..7502d04 100644
--- a/source/opt/local_single_block_elim_pass.cpp
+++ b/source/opt/local_single_block_elim_pass.cpp
@@ -289,7 +289,8 @@
                                 "SPV_KHR_vulkan_memory_model",
                                 "SPV_NV_bindless_texture",
                                 "SPV_EXT_shader_atomic_float_add",
-                                "SPV_EXT_fragment_shader_interlock"});
+                                "SPV_EXT_fragment_shader_interlock",
+                                "SPV_NV_compute_shader_derivatives"});
 }
 
 }  // namespace opt
diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp
index 77b3420..f6fc276 100644
--- a/source/opt/local_single_store_elim_pass.cpp
+++ b/source/opt/local_single_store_elim_pass.cpp
@@ -139,7 +139,8 @@
                                 "SPV_KHR_vulkan_memory_model",
                                 "SPV_NV_bindless_texture",
                                 "SPV_EXT_shader_atomic_float_add",
-                                "SPV_EXT_fragment_shader_interlock"});
+                                "SPV_EXT_fragment_shader_interlock",
+                                "SPV_NV_compute_shader_derivatives"});
 }
 bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
   std::vector<Instruction*> users;
diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h
index 9202b2e..92777a2 100644
--- a/source/opt/trim_capabilities_pass.h
+++ b/source/opt/trim_capabilities_pass.h
@@ -91,7 +91,9 @@
       spv::Capability::StoragePushConstant16,
       spv::Capability::StorageUniform16,
       spv::Capability::StorageUniformBufferBlock16,
-      spv::Capability::ImageMSArray
+      spv::Capability::ImageMSArray,
+      spv::Capability::ComputeDerivativeGroupQuadsNV,
+      spv::Capability::ComputeDerivativeGroupLinearNV
       // clang-format on
   };
 
diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp
index 8aaf860..8f49c55 100644
--- a/test/opt/trim_capabilities_pass_test.cpp
+++ b/test/opt/trim_capabilities_pass_test.cpp
@@ -63,6 +63,8 @@
                OpCapability DotProductInput4x8BitKHR
                OpCapability DotProductInput4x8BitPackedKHR
                OpCapability DotProductKHR
+               OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability ComputeDerivativeGroupLinearNV
 ; CHECK: OpCapability Linkage
 ; CHECK-NOT: OpCapability StorageUniform16
 ; CHECK-NOT: OpCapability StorageUniformBufferBlock16
@@ -89,6 +91,8 @@
 ; CHECK-NOT: OpCapability DotProductInput4x8BitKHR
 ; CHECK-NOT: OpCapability DotProductInput4x8BitPackedKHR
 ; CHECK-NOT: OpCapability DotProductKHR
+; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearNV
 ; CHECK: OpCapability UniformAndStorageBuffer16BitAccess
 ; CHECK: OpCapability StorageBuffer16BitAccess
 ; CHECK: OpCapability ShaderViewportIndexLayerEXT
@@ -2129,6 +2133,59 @@
   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
 }
 
+TEST_F(TrimCapabilitiesPassTest,
+       ComputeDerivativeGroupQuads_ReamainsWithExecMode) {
+  const std::string kTest = R"(
+               OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability ComputeDerivativeGroupLinearNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupLinearNV
+; CHECK:       OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupLinearNV
+               OpCapability Shader
+; CHECK:       OpExtension "SPV_NV_compute_shader_derivatives"
+               OpExtension "SPV_NV_compute_shader_derivatives"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %1 DerivativeGroupQuadsNV
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
+TEST_F(TrimCapabilitiesPassTest,
+       ComputeDerivativeGroupLinear_ReamainsWithExecMode) {
+  const std::string kTest = R"(
+               OpCapability ComputeDerivativeGroupLinearNV
+               OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupQuadsNV
+; CHECK:       OpCapability ComputeDerivativeGroupLinearNV
+; CHECK-NOT:   OpCapability ComputeDerivativeGroupQuadsNV
+               OpCapability Shader
+; CHECK:       OpExtension "SPV_NV_compute_shader_derivatives"
+               OpExtension "SPV_NV_compute_shader_derivatives"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %1 "main"
+               OpExecutionMode %1 DerivativeGroupLinearNV
+       %void = OpTypeVoid
+      %float = OpTypeFloat 64
+          %3 = OpTypeFunction %void
+          %1 = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  const auto result =
+      SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
+  EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools