Skip to content

[WebGPU EP] Gate int64 Clip kernel behind enable_int64 - #29918

Merged
hariharans29 merged 2 commits into
microsoft:mainfrom
mingmingtasd:int64clip
Jul 30, 2026
Merged

[WebGPU EP] Gate int64 Clip kernel behind enable_int64#29918
hariharans29 merged 2 commits into
microsoft:mainfrom
mingmingtasd:int64clip

Conversation

@mingmingtasd

Copy link
Copy Markdown
Contributor

The int64 Clip kernel was registered unconditionally via the static kernel table, unlike every other int64 kernel (Cast, Expand, Equal, Sub, Where, ReduceSum, Reshape, Unsqueeze, Range), which register their int64 variant only when the enable_int64 option is set. As a result an int64 Clip node was claimed by the EP even when int64 support was left disabled.

Remove the int64 Clip entries from the static kernel table and register the dedicated ClipInt64 kernels conditionally in RegisterKernels, gated on enable_int64. The int64 Clip WebGPU tests now build the EP with the option enabled.

This is an enhancement for landed PR #29834

The int64 Clip kernel was registered unconditionally via the static
kernel table, unlike every other int64 kernel (Cast, Expand, Equal,
Sub, Where, ReduceSum, Reshape, Unsqueeze, Range), which register their
int64 variant only when the enable_int64 option is set. As a result an
int64 Clip node was claimed by the EP even when int64 support was left
disabled.

Remove the int64 Clip entries from the static kernel table and register
the dedicated ClipInt64 kernels conditionally in RegisterKernels, gated
on enable_int64. The int64 Clip WebGPU tests now build the EP with the
option enabled.
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@mingmingtasd
mingmingtasd marked this pull request as draft July 28, 2026 07:26
@mingmingtasd
mingmingtasd marked this pull request as ready for review July 29, 2026 02:07
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@mingmingtasd

Copy link
Copy Markdown
Contributor Author

@hariharans29, PTAL, thanks!
cc/ @huningxin @ibelem @adrastogi

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes WebGPU EP kernel registration so that the dedicated int64 Clip kernels are only registered when the WebGPU provider is created with enableInt64 enabled, aligning Clip with the existing behavior of other int64-gated WebGPU kernels (Cast, Expand, Range, etc.). This prevents WebGPU from claiming int64 Clip nodes when int64 support is disabled.

Changes:

  • Remove int64 Clip entries from the static WebGPU kernel create-info table and register them conditionally at RegisterKernels(...) time.
  • Introduce RegisterClipInt64Kernels(...) in the unary elementwise ops module and invoke it from the WebGPU EP registry setup.
  • Update WebGPU int64 Clip unit tests to construct the EP with kEnableInt64=1.
Show a summary per file
File Description
onnxruntime/test/providers/cpu/math/clip_test.cc Updates WebGPU int64 Clip tests to enable kEnableInt64 when creating the WebGPU EP.
onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc Removes unconditional int64 Clip from the static table and conditionally registers it during RegisterKernels.
onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.h Declares RegisterClipInt64Kernels(...) for conditional registration.
onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc Implements RegisterClipInt64Kernels(...) and performs gated registration for opset 12 and 13+.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment thread onnxruntime/test/providers/cpu/math/clip_test.cc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@edgchen1 edgchen1 added the ep:WebGPU ort-web webgpu provider label Jul 29, 2026
@hariharans29

Copy link
Copy Markdown
Member

Review: PR #29918 — [WebGPU EP] Gate int64 Clip kernel behind enable_int64 (head e40f089)

Author: @mingmingtasd. Branch mingmingtasd:int64clipmicrosoft:main. 2 commits, +38 / -6 across 4 files. CI: catching up on the second commit (e40f089 "fix error on CI" — was 1/68 at fetch time; first commit 4c6a68f had 36/86 with test-file compilation failures on non-WebGPU builds, which this commit fixes). Reviewers: Copilot AI (1 comment on first pass, resolved; 0 new comments on second pass), @edgchen1 (added ep:WebGPU label). Follow-up to landed PR #29834 (which added the ClipInt64 kernel itself).

Verdict: approve. Small, focused hygiene fix that aligns Clip's int64 kernel registration with the pattern used by every other int64-capable WebGPU kernel (Cast, Expand, Equal, Sub, Where, ReduceSum, Reshape, Unsqueeze, Range). Removes a leaky-abstraction bug where the WebGPU EP would silently claim int64 Clip nodes even when the user hadn't opted into int64 support via kEnableInt64. No behavioral change for the four existing Clip type variants (float, MLFloat16, int32_t, uint32_t).


The inconsistency this fixes

Before this PR, PR #29834 registered ClipInt64 via the static build_kernel_create_info_function_table[] in webgpu_execution_provider.cc:

BuildKernelCreateInfo<class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 12, 12, int64_t, Clip)>,
BuildKernelCreateInfo<class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, int64_t, Clip)>,

...where the surrounding int64 kernels for other ops are dispatched via RegisterKernels(...) and gated on enable_int64:

ORT_THROW_IF_ERROR(kernel_registry->Register(CreateCastKernelInfo<...>(enable_int64)));
...
RegisterRangeKernels(*kernel_registry, enable_int64);

The user-visible effect: setting WebGpuProviderOptions::enableInt64 = false (the default) was supposed to prevent WebGPU from claiming int64 kernels during partitioning. But int64 Clip was silently exposed anyway. On a model with an int64 Clip node between two float/int32 WebGPU-eligible nodes, the WebGPU EP would grab it — inserting Memcpy transitions if the surrounding nodes ended up on CPU, or worse, silently running the WebGPU int64 Clip kernel whose behavior is lossy on the upper 32 bits (see test comment: "stores int64 as vec2 and the dedicated ClipInt64 kernel clamps on the truncated low 32 bits (interpreted as i32), then sign-extends on write").

Gating behind enable_int64 restores the intended opt-in semantics.


What this PR does

Four files, mechanical fix:

  1. onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.h — new declaration:

    #include "core/framework/kernel_registry.h"  // ← added for the KernelRegistry type
    ...
    // Register int64 Clip kernels (dedicated ClipInt64 kernel) with conditional int64 support.
    void RegisterClipInt64Kernels(KernelRegistry& kernel_registry, bool enable_int64);
  2. onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc — definition, positioned right after the existing WEBGPU_CLIP_INT64_KERNEL() macro invocation:

    void RegisterClipInt64Kernels(KernelRegistry& kernel_registry, bool enable_int64) {
      // int64 Clip is opt-in: register the dedicated ClipInt64 kernels only when int64 support is
      // enabled, consistent with the other int64 kernels (Cast, Expand, Range, ...).
      if (enable_int64) {
        ORT_THROW_IF_ERROR(kernel_registry.Register(
            BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(
                kWebGpuExecutionProvider, kOnnxDomain, 12, 12, int64_t, Clip)>()));
        ORT_THROW_IF_ERROR(kernel_registry.Register(
            BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(
                kWebGpuExecutionProvider, kOnnxDomain, 13, int64_t, Clip)>()));
      }
    }
  3. onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc — three edits:

    // Include added
    #include "core/providers/webgpu/math/unary_elementwise_ops.h"
    ...
    // Static table entries replaced with an explanatory comment
    BuildKernelCreateInfo<... uint32_t, Clip>,
    // int64 Clip is registered conditionally in RegisterKernels (gated on enable_int64).
    KERNEL_CREATE_INFO(6, Elu),
    ...
    // RegisterKernels() body — new call positioned alongside the other conditional int64 registrations
    ORT_THROW_IF_ERROR(kernel_registry->Register(CreateCastKernelInfo<24>(enable_int64)));
    
    // Register int64 Clip kernels with conditional int64 support
    RegisterClipInt64Kernels(*kernel_registry, enable_int64);
    
    // Register Range kernels with conditional int64 support
    RegisterRangeKernels(*kernel_registry, enable_int64);
  4. onnxruntime/test/providers/cpu/math/clip_test.cc — four WebGPU int64 tests (Clip_int64_WebGpu, Clip_int64_saturate_WebGpu, Clip_int64_min_only_opset12_WebGpu, Clip_int64_max_only_opset12_WebGpu) updated:

    // Before:
    auto webgpu_ep = DefaultWebGpuExecutionProvider();
    
    // After:
    ConfigOptions config_options{};
    ASSERT_STATUS_OK(config_options.AddConfigEntry(webgpu::options::kEnableInt64, "1"));
    auto webgpu_ep = WebGpuExecutionProviderWithOptions(config_options);

    Plus a #ifdef USE_WEBGPU guard added around the entire block (previously not present because the webgpu::options::kEnableInt64 symbol wasn't yet referenced — commit e40f089 fixed the resulting compile break on non-WebGPU builds).


Correctness notes

Registration pattern parity. The PR description enumerates the pre-existing conditional-int64 kernels: Cast, Expand, Equal, Sub, Where, ReduceSum, Reshape, Unsqueeze, Range. This PR extends that list to include Clip. Verified against the file: RegisterClipInt64Kernels(*kernel_registry, enable_int64) is invoked in RegisterKernels() on line 481, immediately after CreateCastKernelInfo<24>(enable_int64) (line 478) and immediately before RegisterRangeKernels(*kernel_registry, enable_int64) (line 484). Correct positioning. ✓

Include hygiene. Adding #include "core/framework/kernel_registry.h" to unary_elementwise_ops.h is required because the header now declares a function taking KernelRegistry&. Alternative would be a forward declaration, but pulling the full header matches the pattern of other Register*Kernels helpers in the codebase. ✓

Function signature choice. void RegisterClipInt64Kernels(KernelRegistry& kernel_registry, bool enable_int64) matches the exact signature of RegisterRangeKernels(*kernel_registry, enable_int64) on the very next line in the caller. Different from the CreateCastKernelInfo<Version>(enable_int64) template-returning-info pattern used for Cast, but that's a stylistic split that already exists in the codebase and this PR follows the closest local convention. ✓

Test-side EP construction. Switching from DefaultWebGpuExecutionProvider() to WebGpuExecutionProviderWithOptions(config_options) with kEnableInt64=1 is necessary because the default no-options constructor now correctly does NOT register int64 Clip. The if (webgpu_ep == nullptr) GTEST_SKIP() guard is preserved for builds without WebGPU. ✓

#ifdef USE_WEBGPU guard. Copilot's first-round comment (visible in the review history — Show resolved link) flagged that webgpu::options::kEnableInt64 may not be available in non-WebGPU builds. Commit e40f089 "fix error on CI" wrapped the entire int64 test block in #ifdef USE_WEBGPU, restoring the same conditional-compilation pattern used by other test blocks that reference WebGPU-specific symbols. The previous tests weren't compiled on non-WebGPU builds because they only referenced DefaultWebGpuExecutionProvider() (which returns nullptr on non-WebGPU builds via a stub), but the new webgpu::options::kEnableInt64 needs actual WebGPU headers. Correct fix. ✓


Impact analysis

The lossy int64 → i32 truncation semantic of the ClipInt64 kernel is documented in the test comment:

WebGPU has no native 64-bit integer type; the EP stores int64 as vec2 and the dedicated ClipInt64 kernel clamps on the truncated low 32 bits (interpreted as i32), then sign-extends on write. Values are kept within the int32 range — the realistic index/position case and where the truncated clamp matches the reference result.

This lossy behavior is precisely why int64 support is opt-in in the WebGPU EP. Prior to this PR, users who hadn't opted in were nonetheless getting the lossy int64 Clip behavior silently. The fix restores the invariant that "enable_int64=false means WebGPU claims zero int64 nodes."

Concretely, this matters for two use cases:

  1. Models with mixed int64 nodes: Users who deliberately want int64 nodes on CPU (for correctness on the upper 32 bits) will no longer see WebGPU silently claim Clip.
  2. Graph capture: Similar to the PRelu situation in PR [WebGPU EP] Add PRelu support #30512 — unexpected EP claims can insert Memcpy transitions that break WebGPU graph capture. Aligning Clip with the standard pattern reduces the surface area for such issues.

Nits (all non-blocking)

  1. CI recovery. First commit 4c6a68f was 36/86 OK due to the compile break on non-WebGPU builds. Second commit e40f089 should restore CI to ≥80/86 (matching sibling PRs in this cohort). Watch that it settles cleanly.
  2. PR description references PR [WebGPU EP] Support int64 Clip via a dedicated ClipInt64 kernel #29834 but doesn't link to a specific issue. Good practice would be to reference an umbrella issue (Microsoft WebNN demo applications cannot successfully run in ORT-WebGPU backend with CPU fallback disabled #29756 or similar) that tracks all the int64-related EP hygiene work — but the description is clear enough on its own.
  3. RegisterClipInt64Kernels and RegisterRangeKernels are both void Register*Kernels(KernelRegistry&, bool) signatures, while CreateCastKernelInfo<...>(bool) returns a KernelCreateInfo. Both patterns coexist in the file. Not worth reconciling in this PR.
  4. Comment at the static-table removal site: // int64 Clip is registered conditionally in RegisterKernels (gated on enable_int64). — good pointer for a future reader who might otherwise wonder why the two lines were removed. Nice hygiene.

CI / merge state

  • Head e40f089: CI catching up (1/68 at fetch); previous CI-failing commit 4c6a68f was 36/86.
  • Approvals: none yet. Copilot AI comment resolved. @edgchen1 engaged.
  • @hariharans29, @huningxin, @ibelem, @adrastogi cc'd.

Bottom line

Clean 38-line hygiene fix that closes a genuine leaky-abstraction bug from PR #29834. Follows the exact convention already established by 9 other int64-capable WebGPU kernels. Test-side changes correctly opt into kEnableInt64=1 and Windows-CI compile break was caught by Copilot and fixed in the second commit.

Action items:

  1. @edgchen1 or @hariharans29 — approve when CI settles on e40f089.
  2. Future work: audit the WebGPU EP for any other int64-related registrations that may still be sitting in the static table unconditionally. This PR closes the Clip gap; the umbrella hygiene sweep is worth a follow-up issue.

Ready to merge.

@hariharans29
hariharans29 enabled auto-merge (squash) July 30, 2026 03:37
@hariharans29
hariharans29 merged commit 3963664 into microsoft:main Jul 30, 2026
86 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ep:WebGPU ort-web webgpu provider

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants