[naga] Properly evaluate abs(most negative abstract int).

Have constant evaluator use `wrapping_abs` instead of `abs` when
applying `MathFunction::Abs` to AbstractInt values. WGSL says that
applying `abs` to the most negative AbstractInt value must return it
unchanged, which is what Rust's `i64::wrapping_abs` does.
This commit is contained in:
Jim Blandy 2025-04-10 09:48:38 -07:00 committed by Erich Gubler
parent e5a2e440b2
commit 22c4033cb3
2 changed files with 22 additions and 1 deletions

View File

@ -1080,7 +1080,7 @@ impl<'a> ConstantEvaluator<'a> {
Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])),
Scalar::F16([e]) => Ok(Scalar::F16([e.abs()])),
Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.abs()])),
Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.wrapping_abs()])),
Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])),
Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz
Scalar::I64([e]) => Ok(Scalar::I64([e.wrapping_abs()])),

View File

@ -3572,3 +3572,24 @@ fn struct_names_in_init_errors() {
assert!(variant("1.0").is_err());
assert!(variant("A()").is_err());
}
/// Constant evaluation with interesting values.
#[test]
fn const_eval_value_errors() {
#[track_caller]
fn variant(expr: &str) -> Result<naga::Module, naga::front::wgsl::ParseError> {
let input = format!(
r#"
fn f() {{ _ = {expr}; }}
"#
);
naga::front::wgsl::parse_str(&input)
}
assert!(variant("1/1").is_ok());
assert!(variant("1/0").is_err());
assert!(variant("f32(abs(1))").is_ok());
assert!(variant("f32(abs(-9223372036854775807))").is_ok());
assert!(variant("f32(abs(-9223372036854775807 - 1))").is_ok());
}