webgpu: Skip MatMulNBitsMlpFusion when kernel unavailable (#29089)
## Summary
- Add kernel availability check at transformer registration time
- Query WebGPU EP kernel registry for MatMulNBitsMlp before enabling
fusion
- Skip fusion gracefully when kernel is not registered
- Add unit test for kernel-unavailable case
## Motivation
MatMulNBitsMlpFusion is a WebGPU-specific optimization that fuses gated
MLP patterns into a single MatMulNBitsMlp kernel operation. However, it
was previously registered unconditionally without verifying that the
MatMulNBitsMlp kernel actually exists at runtime.
This created a mismatch scenario: **The fusion optimizer could be
compiled into ORT, but the kernel might not be registered on the WebGPU
EP**, leading to "kernel not found" failures at inference time.
### Realistic Scenario: Version Mismatch
Consider a common deployment scenario:
- **ORT** is compiled with MatMulNBitsMlpFusion and MatMulNBitsMlp
kernel support in WebGPU
- **WebGPU plugin** (deployed separately) is an older version that
predates MatMulNBitsMlp kernel implementation
- At inference time:
- The ORT optimizer successfully runs MatMulNBitsMlpFusion and creates
fused nodes
- The WebGPU plugin loads, but its kernel registry does not have
MatMulNBitsMlp
- Inference fails: "kernel 'MatMulNBitsMlp' not found on
WebGpuExecutionProvider"
This can occur when optimizer versions and EP plugin versions diverge in
production deployments.
### The Fix
Rather than unconditionally assuming the kernel exists, the fix queries
the WebGPU EP's kernel registry at graph optimization time (session
initialization). If the kernel is not found, fusion is skipped entirely,
preventing "kernel not found" errors and allowing graceful fallback to
unfused (but functional) operators.
## Test plan
- [x] Build ORT with WebGPU EP succeeds
- [x] Model loads and infers correctly (phi4-graph-prune verified)
- [x] Fusion enabled when kernel available (40 MatMulNBitsMlp nodes
fused)
- [x] New test \MatMulNBitsMlpFusionSkipsWhenKernelUnavailable\ verifies
graceful skip when kernel unavailable
- [x] Lintrunner reports no issues