gfx-rs/wgpu · error

Unexpected sign({:?})

Error message

Unexpected sign({:?})

What it means

Panic in the SPIR-V backend's `MathFunction::Sign` lowering. The GLSL.std.450 extended instruction differs per scalar kind (FSign for floats, SSign for signed ints); if `arg_scalar_kind` is None or an unsupported kind (e.g. Uint, Bool), the `unimplemented!()` arm fires. Note unsigned `sign` is not provided by GLSL.std.450.

Source

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

                    )),
                    Mf::Cross => MathOp::Ext(spirv::GlslStd450Op::Cross),
                    Mf::Distance => MathOp::Ext(spirv::GlslStd450Op::Distance),
                    Mf::Length => MathOp::Ext(spirv::GlslStd450Op::Length),
                    Mf::Normalize => MathOp::Ext(spirv::GlslStd450Op::Normalize),
                    Mf::FaceForward => MathOp::Ext(spirv::GlslStd450Op::FaceForward),
                    Mf::Reflect => MathOp::Ext(spirv::GlslStd450Op::Reflect),
                    Mf::Refract => MathOp::Ext(spirv::GlslStd450Op::Refract),
                    // exponent
                    Mf::Exp => MathOp::Ext(spirv::GlslStd450Op::Exp),
                    Mf::Exp2 => MathOp::Ext(spirv::GlslStd450Op::Exp2),
                    Mf::Log => MathOp::Ext(spirv::GlslStd450Op::Log),
                    Mf::Log2 => MathOp::Ext(spirv::GlslStd450Op::Log2),
                    Mf::Pow => MathOp::Ext(spirv::GlslStd450Op::Pow),
                    // computational
                    Mf::Sign => MathOp::Ext(match arg_scalar_kind {
                        Some(crate::ScalarKind::Float) => spirv::GlslStd450Op::FSign,
                        Some(crate::ScalarKind::Sint) => spirv::GlslStd450Op::SSign,
                        other => unimplemented!("Unexpected sign({:?})", other),
                    }),
                    Mf::Fma => MathOp::Ext(spirv::GlslStd450Op::Fma),
                    Mf::Mix => {
                        let selector = arg2.unwrap();
                        let selector_ty =
                            self.fun_info[selector].ty.inner_with(&self.ir_module.types);
                        match (arg_ty, selector_ty) {
                            // if the selector is a scalar, we need to splat it
                            (
                                &crate::TypeInner::Vector { size, .. },
                                &crate::TypeInner::Scalar(scalar),
                            ) => {
                                let selector_type_id =
                                    self.get_numeric_type_id(NumericType::Vector { size, scalar });
                                self.temp_list.clear();
                                self.temp_list.resize(size as usize, arg2_id);

                                let selector_id = self.gen_id();

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. Avoid `sign` on unsigned values: for uint, replace with `select(0u, 1u, x != 0u)` or compare directly
  2. Cast to i32/f32 before calling sign: `sign(i32(x))`
  3. Update naga to a version that either supports the case or reports a validation error
  4. File a wgpu issue with a minimal shader if the case should be supported

Example fix

// before
let s = sign(u);
// after
let s = sign(i32(u));
Defensive patterns

Strategy: validation

Validate before calling

fn check_sign_operand(module: &naga::Module) -> bool {
    // sign supports only Float (FSign) and Sint (SSign)
    module.global_expressions.iter().all(|(_, e)| match e {
        naga::Expression::Math { fun: naga::MathFunction::Sign, args, .. } => args.iter().all(|a| {
            matches!(ty_of(module, *a).inner,
                naga::TypeInner::Scalar(s) | naga::TypeInner::Vector { scalar: s, .. }
                if matches!(s.kind, naga::ScalarKind::Float | naga::ScalarKind::Sint))
        }),
        _ => true,
    })
}

Type guard

fn sign_supported(s: naga::Scalar) -> bool {
    matches!(s.kind, naga::ScalarKind::Float | naga::ScalarKind::Sint)
}

Prevention

When it happens

Trigger: A `sign(x)` call in a shader where x's scalar kind is not Float or Sint, most commonly `sign(uint_value)` or a bool-typed expression, during SPIR-V emission in `cache_expression_value`.

Common situations: Ported code from languages where sign works on unsigned ints (e.g. HLSL or generated code); WGSL authors normally get a frontend error first, so this appears with other frontends or IR constructed programmatically.

Related errors


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