gfx-rs/wgpu · error

Unexpected firstLeadingBit({:?})

Error message

Unexpected firstLeadingBit({:?})

What it means

Panic from the `MathFunction::FirstLeadingBit` lowering in the SPIR-V backend. For 32-bit operands it maps to GLSL.std.450 FindUMsb/FindSMsb by scalar kind; any other kind (Float, Bool, None) hits `unimplemented!()`. Widths other than 32 bits are validated out entirely (`unreachable!`).

Source

Thrown at naga/src/back/spv/block.rs:1944

                        ));

                        MathOp::Custom(Instruction::quaternary(
                            spirv::Op::BitFieldInsert,
                            result_type_id,
                            id,
                            arg0_id,
                            arg1_id,
                            offset_id,
                            count_id,
                        ))
                    }
                    Mf::FirstTrailingBit => MathOp::Ext(spirv::GlslStd450Op::FindILsb),
                    Mf::FirstLeadingBit => {
                        if arg_ty.scalar_width() == Some(4) {
                            let thing = match arg_scalar_kind {
                                Some(crate::ScalarKind::Uint) => spirv::GlslStd450Op::FindUMsb,
                                Some(crate::ScalarKind::Sint) => spirv::GlslStd450Op::FindSMsb,
                                other => unimplemented!("Unexpected firstLeadingBit({:?})", other),
                            };
                            MathOp::Ext(thing)
                        } else {
                            unreachable!("This is validated out until a polyfill is implemented. https://github.com/gfx-rs/wgpu/issues/5276");
                        }
                    }
                    Mf::Pack4x8unorm => MathOp::Ext(spirv::GlslStd450Op::PackUnorm4x8),
                    Mf::Pack4x8snorm => MathOp::Ext(spirv::GlslStd450Op::PackSnorm4x8),
                    Mf::Pack2x16float => MathOp::Ext(spirv::GlslStd450Op::PackHalf2x16),
                    Mf::Pack2x16unorm => MathOp::Ext(spirv::GlslStd450Op::PackUnorm2x16),
                    Mf::Pack2x16snorm => MathOp::Ext(spirv::GlslStd450Op::PackSnorm2x16),
                    fun @ (Mf::Pack4xI8 | Mf::Pack4xU8 | Mf::Pack4xI8Clamp | Mf::Pack4xU8Clamp) => {
                        let is_signed = matches!(fun, Mf::Pack4xI8 | Mf::Pack4xI8Clamp);
                        let should_clamp = matches!(fun, Mf::Pack4xI8Clamp | Mf::Pack4xU8Clamp);

                        let last_instruction =
                            if self.writer.require_all(&[spirv::Capability::Int8]).is_ok() {
                                self.write_pack4x8_optimized(

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. Bitcast to an integer first: `firstLeadingBit(bitcast<u32>(x))`
  2. Confirm the operand is i32/u32 and not f32 after constant folding
  3. Run the shader through naga's validator/CLI to isolate the failing expression
  4. Update naga/wgpu; report a reproducer if the shader is valid WGSL

Example fix

// before
let fb = firstLeadingBit(x); // x: f32
// after
let fb = firstLeadingBit(bitcast<i32>(x));
Defensive patterns

Strategy: validation

Validate before calling

fn check_first_leading_bit(module: &naga::Module) -> bool {
    // firstLeadingBit requires 32-bit Sint/Uint operands
    module.global_expressions.iter().all(|(_, e)| match e {
        naga::Expression::Math { fun: naga::MathFunction::FirstLeadingBit, args, .. } => args.first().map_or(true, |a| {
            matches!(ty_of(module, *a).inner,
                naga::TypeInner::Scalar(s) | naga::TypeInner::Vector { scalar: s, .. }
                if s.width == 4 && matches!(s.kind, naga::ScalarKind::Sint | naga::ScalarKind::Uint))
        }),
        _ => true,
    })
}

Type guard

fn first_leading_bit_supported(s: naga::Scalar) -> bool {
    s.width == 4 && matches!(s.kind, naga::ScalarKind::Sint | naga::ScalarKind::Uint)
}

Prevention

When it happens

Trigger: `firstLeadingBit(x)` where x's scalar kind is neither Uint nor Sint (e.g. float operand), or where the kind info is missing, during SPIR-V emission.

Common situations: Bit-manipulation-heavy shaders transpiled from other languages where the intrinsic accepts floats or where types were inferred incorrectly; extremely rare in valid WGSL.

Related errors


AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03). Data as JSON: /api/errors/eb05a572ca7d3da5. Report an issue: GitHub.