Dawn: Tighten the scope of ScopedTintICEHandler

This CL tightens the scope of ScopedTintICEHandler to prepare for
further code refactor. Currently ScopedTintICEHandler can not be
nested in a single thread, tightening its scope can help prevent
such overlapping.

Bug: dawn:718, 396023091
Change-Id: Idb23b8298fd7bf907dfedf0f7a46a7883830ef68
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/226056
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@microsoft.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 283d38b..d0c6823 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -1094,11 +1094,12 @@
     return std::move(metadata);
 }
 
-MaybeError ReflectShaderUsingTint(const DeviceBase* device,
+MaybeError ReflectShaderUsingTint(DeviceBase* device,
                                   const tint::Program* program,
                                   OwnedCompilationMessages* compilationMessages,
                                   EntryPointMetadataTable* entryPointMetadataTable) {
     DAWN_ASSERT(program->IsValid());
+    ScopedTintICEHandler scopedICEHandler(device);
 
     tint::inspector::Inspector inspector(*program);
 
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
index 0b9c7b5..3b5120a 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
@@ -71,7 +71,6 @@
 
 MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
                                     OwnedCompilationMessages* compilationMessages) {
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
     return InitializeBase(parseResult, compilationMessages);
 }
 
@@ -86,7 +85,6 @@
     TRACE_EVENT0(device->GetPlatform(), General, "ShaderModuleD3D11::Compile");
     DAWN_ASSERT(!IsError());
 
-    ScopedTintICEHandler scopedICEHandler(device);
     const EntryPointMetadata& entryPoint = GetEntryPoint(programmableStage.entryPoint);
     const bool useTintIR = device->IsToggleEnabled(Toggle::UseTintIR);
 
@@ -261,8 +259,11 @@
     req.hlsl.tintOptions.polyfill_pack_unpack_4x8 = true;
 
     CacheResult<d3d::CompiledShader> compiledShader;
-    DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), d3d::CompiledShader::FromBlob,
-                         d3d::CompileShader, "D3D11.CompileShader");
+    {
+        ScopedTintICEHandler scopedICEHandler(device);
+        DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), d3d::CompiledShader::FromBlob,
+                             d3d::CompileShader, "D3D11.CompileShader");
+    }
 
     if (device->IsToggleEnabled(Toggle::DumpShaders)) {
         d3d::DumpFXCCompiledShader(device, *compiledShader, compileFlags);
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index 0f17f0d..2511bbd 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -116,7 +116,6 @@
 
 MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
                                     OwnedCompilationMessages* compilationMessages) {
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
     return InitializeBase(parseResult, compilationMessages);
 }
 
@@ -131,7 +130,6 @@
     TRACE_EVENT0(device->GetPlatform(), General, "ShaderModuleD3D12::Compile");
     DAWN_ASSERT(!IsError());
 
-    ScopedTintICEHandler scopedICEHandler(device);
     const EntryPointMetadata& entryPoint = GetEntryPoint(programmableStage.entryPoint);
     const bool useTintIR = device->IsToggleEnabled(Toggle::UseTintIR);
 
@@ -387,8 +385,11 @@
     req.hlsl.adapter = UnsafeUnkeyedValue(static_cast<const AdapterBase*>(device->GetAdapter()));
 
     CacheResult<d3d::CompiledShader> compiledShader;
-    DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), d3d::CompiledShader::FromBlob,
-                         d3d::CompileShader, "D3D12.CompileShader");
+    {
+        ScopedTintICEHandler scopedICEHandler(device);
+        DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), d3d::CompiledShader::FromBlob,
+                             d3d::CompileShader, "D3D12.CompileShader");
+    }
 
     if (device->IsToggleEnabled(Toggle::DumpShaders)) {
         if (device->IsToggleEnabled(Toggle::UseDXC)) {
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index d8494a5..f9640a3 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -110,7 +110,6 @@
 
 MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
                                     OwnedCompilationMessages* compilationMessages) {
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
     return InitializeBase(parseResult, compilationMessages);
 }
 
@@ -213,7 +212,6 @@
     uint32_t sampleMask,
     const RenderPipeline* renderPipeline,
     const BindingInfoArray& moduleBindingInfo) {
-    ScopedTintICEHandler scopedICEHandler(device);
 
     std::ostringstream errorStream;
     errorStream << "Tint MSL failure:\n";
@@ -299,83 +297,91 @@
     req.adapter = UnsafeUnkeyedValue(static_cast<const AdapterBase*>(device->GetAdapter()));
 
     CacheResult<MslCompilation> mslCompilation;
-    DAWN_TRY_LOAD_OR_RUN(
-        mslCompilation, device, std::move(req), MslCompilation::FromBlob,
-        [](MslCompilationRequest r) -> ResultOrError<MslCompilation> {
-            tint::ast::transform::Manager transformManager;
-            tint::ast::transform::DataMap transformInputs;
+    {
+        ScopedTintICEHandler scopedICEHandler(device);
+        DAWN_TRY_LOAD_OR_RUN(
+            mslCompilation, device, std::move(req), MslCompilation::FromBlob,
+            [](MslCompilationRequest r) -> ResultOrError<MslCompilation> {
+                tint::ast::transform::Manager transformManager;
+                tint::ast::transform::DataMap transformInputs;
 
-            // We only remap bindings for the target entry point, so we need to strip all other
-            // entry points to avoid generating invalid bindings for them.
-            // Run before the renamer so that the entry point name matches `entryPointName` still.
-            transformManager.Add<tint::ast::transform::SingleEntryPoint>();
-            transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(r.entryPointName);
+                // We only remap bindings for the target entry point, so we need to strip all other
+                // entry points to avoid generating invalid bindings for them.
+                // Run before the renamer so that the entry point name matches `entryPointName`
+                // still.
+                transformManager.Add<tint::ast::transform::SingleEntryPoint>();
+                transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(
+                    r.entryPointName);
 
-            if (r.substituteOverrideConfig) {
-                // This needs to run after SingleEntryPoint transform which removes unused overrides
-                // for current entry point.
-                transformManager.Add<tint::ast::transform::SubstituteOverride>();
-                transformInputs.Add<tint::ast::transform::SubstituteOverride::Config>(
-                    std::move(r.substituteOverrideConfig).value());
-            }
+                if (r.substituteOverrideConfig) {
+                    // This needs to run after SingleEntryPoint transform which removes unused
+                    // overrides for current entry point.
+                    transformManager.Add<tint::ast::transform::SubstituteOverride>();
+                    transformInputs.Add<tint::ast::transform::SubstituteOverride::Config>(
+                        std::move(r.substituteOverrideConfig).value());
+                }
 
-            tint::Program program;
-            tint::ast::transform::DataMap transformOutputs;
-            {
-                TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "RunTransforms");
-                DAWN_TRY_ASSIGN(program,
-                                RunTransforms(&transformManager, r.inputProgram, transformInputs,
-                                              &transformOutputs, nullptr));
-            }
+                tint::Program program;
+                tint::ast::transform::DataMap transformOutputs;
+                {
+                    TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "RunTransforms");
+                    DAWN_TRY_ASSIGN(
+                        program, RunTransforms(&transformManager, r.inputProgram, transformInputs,
+                                               &transformOutputs, nullptr));
+                }
 
-            Extent3D localSize{0, 0, 0};
+                Extent3D localSize{0, 0, 0};
 
-            TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "tint::msl::writer::Generate");
+                TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "tint::msl::writer::Generate");
 
-            // Convert the AST program to an IR module.
-            auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
-            DAWN_INVALID_IF(ir != tint::Success, "An error occurred while generating Tint IR\n%s",
-                            ir.Failure().reason.Str());
+                // Convert the AST program to an IR module.
+                auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
+                DAWN_INVALID_IF(ir != tint::Success,
+                                "An error occurred while generating Tint IR\n%s",
+                                ir.Failure().reason.Str());
 
-            // Generate MSL.
-            auto result = tint::msl::writer::Generate(ir.Get(), r.tintOptions);
-            DAWN_INVALID_IF(result != tint::Success, "An error occurred while generating MSL:\n%s",
-                            result.Failure().reason.Str());
+                // Generate MSL.
+                auto result = tint::msl::writer::Generate(ir.Get(), r.tintOptions);
+                DAWN_INVALID_IF(result != tint::Success,
+                                "An error occurred while generating MSL:\n%s",
+                                result.Failure().reason.Str());
 
-            // Workgroup validation has to come after `Generate` because it may require
-            // overrides to have been substituted.
-            if (r.stage == SingleShaderStage::Compute) {
-                // Validate workgroup size and workgroup storage size.
-                DAWN_TRY_ASSIGN(localSize,
-                                ValidateComputeStageWorkgroupSize(
-                                    result->workgroup_info.x, result->workgroup_info.y,
-                                    result->workgroup_info.z, result->workgroup_info.storage_size,
-                                    r.limits, r.adapter.UnsafeGetValue()));
-            }
+                // Workgroup validation has to come after `Generate` because it may require
+                // overrides to have been substituted.
+                if (r.stage == SingleShaderStage::Compute) {
+                    // Validate workgroup size and workgroup storage size.
+                    DAWN_TRY_ASSIGN(
+                        localSize,
+                        ValidateComputeStageWorkgroupSize(
+                            result->workgroup_info.x, result->workgroup_info.y,
+                            result->workgroup_info.z, result->workgroup_info.storage_size, r.limits,
+                            r.adapter.UnsafeGetValue()));
+                }
 
-            // Metal uses Clang to compile the shader as C++14. Disable everything in the -Wall
-            // category. -Wunused-variable in particular comes up a lot in generated code, and some
-            // (old?) Metal drivers accidentally treat it as a MTLLibraryErrorCompileError instead
-            // of a warning.
-            auto msl = std::move(result->msl);
-            msl = R"(
-                #ifdef __clang__
-                #pragma clang diagnostic ignored "-Wall"
-                #endif
-            )" + msl;
+                // Metal uses Clang to compile the shader as C++14. Disable everything in the -Wall
+                // category. -Wunused-variable in particular comes up a lot in generated code, and
+                // some (old?) Metal drivers accidentally treat it as a MTLLibraryErrorCompileError
+                // instead of a warning.
+                auto msl = std::move(result->msl);
+                msl = R"(
+                    #ifdef __clang__
+                    #pragma clang diagnostic ignored "-Wall"
+                    #endif
+                )" + msl;
 
-            auto workgroupAllocations =
-                std::move(result->workgroup_info.allocations.at(kRemappedEntryPointName));
-            return MslCompilation{{
-                std::move(msl),
-                std::move(kRemappedEntryPointName),
-                result->needs_storage_buffer_sizes,
-                result->has_invariant_attribute,
-                std::move(workgroupAllocations),
-                localSize,
-            }};
-        },
-        "Metal.CompileShaderToMSL");
+                auto workgroupAllocations =
+                    std::move(result->workgroup_info.allocations.at(kRemappedEntryPointName));
+                return MslCompilation{{
+                    std::move(msl),
+                    std::move(kRemappedEntryPointName),
+                    result->needs_storage_buffer_sizes,
+                    result->has_invariant_attribute,
+                    std::move(workgroupAllocations),
+                    localSize,
+                }};
+            },
+            "Metal.CompileShaderToMSL");
+    }
 
     if (device->IsToggleEnabled(Toggle::DumpShaders)) {
         std::ostringstream dumpedMsg;
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index 54cae69..fbf212a 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -295,8 +295,6 @@
 
 MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
                                     OwnedCompilationMessages* compilationMessages) {
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
-
     DAWN_TRY(InitializeBase(parseResult, compilationMessages));
 
     return {};
@@ -497,59 +495,68 @@
         GetDevice()->IsToggleEnabled(Toggle::DisablePolyfillsOnIntegerDivisonAndModulo);
 
     CacheResult<GLSLCompilation> compilationResult;
-    DAWN_TRY_LOAD_OR_RUN(
-        compilationResult, GetDevice(), std::move(req), GLSLCompilation::FromBlob,
-        [](GLSLCompilationRequest r) -> ResultOrError<GLSLCompilation> {
-            tint::ast::transform::Manager transformManager;
-            tint::ast::transform::DataMap transformInputs;
+    {
+        ScopedTintICEHandler scopedICEHandler(GetDevice());
+        DAWN_TRY_LOAD_OR_RUN(
+            compilationResult, GetDevice(), std::move(req), GLSLCompilation::FromBlob,
+            [](GLSLCompilationRequest r) -> ResultOrError<GLSLCompilation> {
+                tint::ast::transform::Manager transformManager;
+                tint::ast::transform::DataMap transformInputs;
 
-            transformManager.Add<tint::ast::transform::SingleEntryPoint>();
-            transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(r.entryPointName);
+                transformManager.Add<tint::ast::transform::SingleEntryPoint>();
+                transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(
+                    r.entryPointName);
 
-            if (r.substituteOverrideConfig) {
-                // This needs to run after SingleEntryPoint transform which removes unused overrides
-                // for current entry point.
-                transformManager.Add<tint::ast::transform::SubstituteOverride>();
-                transformInputs.Add<tint::ast::transform::SubstituteOverride::Config>(
-                    std::move(r.substituteOverrideConfig).value());
-            }
+                if (r.substituteOverrideConfig) {
+                    // This needs to run after SingleEntryPoint transform which removes unused
+                    // overrides for current entry point.
+                    transformManager.Add<tint::ast::transform::SubstituteOverride>();
+                    transformInputs.Add<tint::ast::transform::SubstituteOverride::Config>(
+                        std::move(r.substituteOverrideConfig).value());
+                }
 
-            tint::Program program;
-            tint::ast::transform::DataMap transformOutputs;
-            DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, r.inputProgram,
-                                                   transformInputs, &transformOutputs, nullptr));
+                tint::Program program;
+                tint::ast::transform::DataMap transformOutputs;
+                DAWN_TRY_ASSIGN(program,
+                                RunTransforms(&transformManager, r.inputProgram, transformInputs,
+                                              &transformOutputs, nullptr));
 
-            // Intentionally assign entry point to empty to avoid a redundant 'SingleEntryPoint'
-            // transform in Tint.
-            // TODO(crbug.com/356424898): In the long run, we want to move SingleEntryPoint to Tint,
-            // but that has interactions with SubstituteOverrides which need to be handled first.
-            const std::string remappedEntryPoint = "";
+                // Intentionally assign entry point to empty to avoid a redundant 'SingleEntryPoint'
+                // transform in Tint.
+                // TODO(crbug.com/356424898): In the long run, we want to move SingleEntryPoint to
+                // Tint, but that has interactions with SubstituteOverrides which need to be handled
+                // first.
+                const std::string remappedEntryPoint = "";
 
-            // Convert the AST program to an IR module.
-            auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
-            DAWN_INVALID_IF(ir != tint::Success, "An error occurred while generating Tint IR\n%s",
-                            ir.Failure().reason.Str());
+                // Convert the AST program to an IR module.
+                auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
+                DAWN_INVALID_IF(ir != tint::Success,
+                                "An error occurred while generating Tint IR\n%s",
+                                ir.Failure().reason.Str());
 
-            // Generate GLSL from Tint IR.
-            auto result = tint::glsl::writer::Generate(ir.Get(), r.tintOptions, remappedEntryPoint);
-            DAWN_INVALID_IF(result != tint::Success, "An error occurred while generating GLSL:\n%s",
-                            result.Failure().reason.Str());
+                // Generate GLSL from Tint IR.
+                auto result =
+                    tint::glsl::writer::Generate(ir.Get(), r.tintOptions, remappedEntryPoint);
+                DAWN_INVALID_IF(result != tint::Success,
+                                "An error occurred while generating GLSL:\n%s",
+                                result.Failure().reason.Str());
 
-            // Workgroup validation has to come after `Generate` because it may require overrides to
-            // have been substituted.
-            if (r.stage == SingleShaderStage::Compute) {
-                // Validate workgroup size after program runs transforms.
-                Extent3D _;
-                DAWN_TRY_ASSIGN(
-                    _, ValidateComputeStageWorkgroupSize(
-                           result->workgroup_info.x, result->workgroup_info.y,
-                           result->workgroup_info.z, result->workgroup_info.storage_size, r.limits,
-                           r.adapter.UnsafeGetValue()));
-            }
+                // Workgroup validation has to come after `Generate` because it may require
+                // overrides to have been substituted.
+                if (r.stage == SingleShaderStage::Compute) {
+                    // Validate workgroup size after program runs transforms.
+                    Extent3D _;
+                    DAWN_TRY_ASSIGN(
+                        _, ValidateComputeStageWorkgroupSize(
+                               result->workgroup_info.x, result->workgroup_info.y,
+                               result->workgroup_info.z, result->workgroup_info.storage_size,
+                               r.limits, r.adapter.UnsafeGetValue()));
+                }
 
-            return GLSLCompilation{{std::move(result->glsl)}};
-        },
-        "OpenGL.CompileShaderToGLSL");
+                return GLSLCompilation{{std::move(result->glsl)}};
+            },
+            "OpenGL.CompileShaderToGLSL");
+    }
 
     if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
         std::ostringstream dumpedMsg;
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 3ac2e63..5d29f63 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -180,7 +180,6 @@
 
 MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
                                     OwnedCompilationMessages* compilationMessages) {
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
     return InitializeBase(parseResult, compilationMessages);
 }
 
@@ -217,8 +216,6 @@
     const ImmediateConstantMask& pipelineImmediateMask) {
     TRACE_EVENT0(GetDevice()->GetPlatform(), General, "ShaderModuleVk::GetHandleAndSpirv");
 
-    ScopedTintICEHandler scopedICEHandler(GetDevice());
-
     // Check to see if we have the handle and spirv cached already
     // TODO(chromium:345359083): Improve the computation of the cache key. For example, it isn't
     // ideal to use `reinterpret_cast<uintptr_t>(layout)` as the layout may be freed and
@@ -396,67 +393,73 @@
     req.adapter = UnsafeUnkeyedValue(static_cast<const AdapterBase*>(GetDevice()->GetAdapter()));
 
     CacheResult<CompiledSpirv> compilation;
-    DAWN_TRY_LOAD_OR_RUN(
-        compilation, GetDevice(), std::move(req), CompiledSpirv::FromBlob,
-        [](SpirvCompilationRequest r) -> ResultOrError<CompiledSpirv> {
-            tint::ast::transform::Manager transformManager;
-            tint::ast::transform::DataMap transformInputs;
+    {
+        ScopedTintICEHandler scopedICEHandler(GetDevice());
+        DAWN_TRY_LOAD_OR_RUN(
+            compilation, GetDevice(), std::move(req), CompiledSpirv::FromBlob,
+            [](SpirvCompilationRequest r) -> ResultOrError<CompiledSpirv> {
+                tint::ast::transform::Manager transformManager;
+                tint::ast::transform::DataMap transformInputs;
 
-            // Many Vulkan drivers can't handle multi-entrypoint shader modules.
-            transformManager.append(std::make_unique<tint::ast::transform::SingleEntryPoint>());
-            transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(
-                std::string(r.entryPointName));
+                // Many Vulkan drivers can't handle multi-entrypoint shader modules.
+                transformManager.append(std::make_unique<tint::ast::transform::SingleEntryPoint>());
+                transformInputs.Add<tint::ast::transform::SingleEntryPoint::Config>(
+                    std::string(r.entryPointName));
 
-            tint::Program program;
-            tint::ast::transform::DataMap transformOutputs;
-            {
-                TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "RunTransforms");
-                DAWN_TRY_ASSIGN(program,
-                                RunTransforms(&transformManager, r.inputProgram, transformInputs,
-                                              &transformOutputs, nullptr));
-            }
+                tint::Program program;
+                tint::ast::transform::DataMap transformOutputs;
+                {
+                    TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "RunTransforms");
+                    DAWN_TRY_ASSIGN(
+                        program, RunTransforms(&transformManager, r.inputProgram, transformInputs,
+                                               &transformOutputs, nullptr));
+                }
 
-            TRACE_EVENT0(r.platform.UnsafeGetValue(), General, "tint::spirv::writer::Generate()");
+                TRACE_EVENT0(r.platform.UnsafeGetValue(), General,
+                             "tint::spirv::writer::Generate()");
 
-            // Convert the AST program to an IR module.
-            auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
-            DAWN_INVALID_IF(ir != tint::Success, "An error occurred while generating Tint IR\n%s",
-                            ir.Failure().reason.Str());
+                // Convert the AST program to an IR module.
+                auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
+                DAWN_INVALID_IF(ir != tint::Success,
+                                "An error occurred while generating Tint IR\n%s",
+                                ir.Failure().reason.Str());
 
-            if (r.substituteOverrideConfig) {
-                // this needs to run after SingleEntryPoint transform which removes unused overrides
-                // for the current entry point.
-                tint::core::ir::transform::SubstituteOverridesConfig cfg;
-                cfg.map = r.substituteOverrideConfig->map;
-                auto substituteOverridesResult =
-                    tint::core::ir::transform::SubstituteOverrides(ir.Get(), cfg);
-                DAWN_INVALID_IF(substituteOverridesResult != tint::Success,
-                                "Pipeline override substitution (IR) failed:\n%s",
-                                substituteOverridesResult.Failure().reason.Str());
-            }
+                if (r.substituteOverrideConfig) {
+                    // this needs to run after SingleEntryPoint transform which removes unused
+                    // overrides for the current entry point.
+                    tint::core::ir::transform::SubstituteOverridesConfig cfg;
+                    cfg.map = r.substituteOverrideConfig->map;
+                    auto substituteOverridesResult =
+                        tint::core::ir::transform::SubstituteOverrides(ir.Get(), cfg);
+                    DAWN_INVALID_IF(substituteOverridesResult != tint::Success,
+                                    "Pipeline override substitution (IR) failed:\n%s",
+                                    substituteOverridesResult.Failure().reason.Str());
+                }
 
-            // Generate SPIR-V from Tint IR.
-            auto tintResult = tint::spirv::writer::Generate(ir.Get(), r.tintOptions);
-            DAWN_INVALID_IF(tintResult != tint::Success,
-                            "An error occurred while generating SPIR-V\n%s",
-                            tintResult.Failure().reason.Str());
+                // Generate SPIR-V from Tint IR.
+                auto tintResult = tint::spirv::writer::Generate(ir.Get(), r.tintOptions);
+                DAWN_INVALID_IF(tintResult != tint::Success,
+                                "An error occurred while generating SPIR-V\n%s",
+                                tintResult.Failure().reason.Str());
 
-            // Workgroup validation has to come after `Generate` because it may require overrides to
-            // have been substituted.
-            if (r.stage == SingleShaderStage::Compute) {
-                Extent3D _;
-                DAWN_TRY_ASSIGN(
-                    _, ValidateComputeStageWorkgroupSize(
-                           tintResult->workgroup_info.x, tintResult->workgroup_info.y,
-                           tintResult->workgroup_info.z, tintResult->workgroup_info.storage_size,
-                           r.limits, r.adapter.UnsafeGetValue()));
-            }
+                // Workgroup validation has to come after `Generate` because it may require
+                // overrides to have been substituted.
+                if (r.stage == SingleShaderStage::Compute) {
+                    Extent3D _;
+                    DAWN_TRY_ASSIGN(
+                        _,
+                        ValidateComputeStageWorkgroupSize(
+                            tintResult->workgroup_info.x, tintResult->workgroup_info.y,
+                            tintResult->workgroup_info.z, tintResult->workgroup_info.storage_size,
+                            r.limits, r.adapter.UnsafeGetValue()));
+                }
 
-            CompiledSpirv result;
-            result.spirv = std::move(tintResult.Get().spirv);
-            return result;
-        },
-        "Vulkan.CompileShaderToSPIRV");
+                CompiledSpirv result;
+                result.spirv = std::move(tintResult.Get().spirv);
+                return result;
+            },
+            "Vulkan.CompileShaderToSPIRV");
+    }
 
 #ifdef DAWN_ENABLE_SPIRV_VALIDATION
     DAWN_TRY(ValidateSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size(),