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
- Bitcast to an integer first: `firstLeadingBit(bitcast<u32>(x))`
- Confirm the operand is i32/u32 and not f32 after constant folding
- Run the shader through naga's validator/CLI to isolate the failing expression
- 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
- Bitcast float operands to i32/u32 before firstLeadingBit
- Remember only 32-bit widths are supported in SPIR-V output (issue #5276)
- Validate with the naga CLI before runtime compilation
- Catch panics when compiling third-party shaders
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
- Unexpected saturate({:?})
- Unexpected sign({:?})
- Unexpected pointer expression {:?}
- not implemented
- not implemented
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/eb05a572ca7d3da5.
Report an issue: GitHub.