# The float functions the JPEG AI exact decoder must not call. # # The exact decoder (`src/jpegai_decode.rs` and the modules it runs through) reproduces # bit for bit across platforms because its float stages use only IEEE-754 basic # operations, with `exp` and rounding built from them in `src/float_repro.rs`. The # methods below would put something else on that path: a platform math-library # function, whose last bits are not fixed by any standard, or an operation whose # lowering or result differs between targets. # # Clippy resolves each use by type, so it catches `x.exp()`, `f64::exp(x)` and # `.map(f64::exp)` alike, and not `crate::float_repro::exp` or an integer `max`. # The lint is allowed for the package (`[lints.clippy]` in Cargo.toml) and denied # by each module on the decode path (`#![deny(clippy::disallowed_methods)]`), so the # rest of the crate may use these methods. `.github/workflows/wai-conformance.yml` # runs clippy on the library. What it does not see (an operator such as a float `%`, # a call in a module without the attribute or in another crate) is covered by # `tests/jpegai_decode_symbols.rs`, which inspects the linked executable. disallowed-methods = [ # Transcendental and power functions: a platform math library is not required to # round them correctly, so libraries disagree in the last bits. { path = "f64::exp", reason = "platform math library; use crate::float_repro::exp" }, { path = "f32::exp", reason = "platform math library; use crate::float_repro::exp" }, { path = "f64::exp2", reason = "platform math library" }, { path = "f32::exp2", reason = "platform math library" }, { path = "f64::exp_m1", reason = "platform math library" }, { path = "f32::exp_m1", reason = "platform math library" }, { path = "f64::ln", reason = "platform math library" }, { path = "f32::ln", reason = "platform math library" }, { path = "f64::ln_1p", reason = "platform math library" }, { path = "f32::ln_1p", reason = "platform math library" }, { path = "f64::log", reason = "platform math library" }, { path = "f32::log", reason = "platform math library" }, { path = "f64::log2", reason = "platform math library" }, { path = "f32::log2", reason = "platform math library" }, { path = "f64::log10", reason = "platform math library" }, { path = "f32::log10", reason = "platform math library" }, { path = "f64::powf", reason = "platform math library" }, { path = "f32::powf", reason = "platform math library" }, { path = "f64::powi", reason = "not correctly rounded, and its expansion depends on the optimiser" }, { path = "f32::powi", reason = "not correctly rounded, and its expansion depends on the optimiser" }, { path = "f64::sin", reason = "platform math library" }, { path = "f32::sin", reason = "platform math library" }, { path = "f64::cos", reason = "platform math library" }, { path = "f32::cos", reason = "platform math library" }, { path = "f64::tan", reason = "platform math library" }, { path = "f32::tan", reason = "platform math library" }, { path = "f64::sin_cos", reason = "platform math library" }, { path = "f32::sin_cos", reason = "platform math library" }, { path = "f64::asin", reason = "platform math library" }, { path = "f32::asin", reason = "platform math library" }, { path = "f64::acos", reason = "platform math library" }, { path = "f32::acos", reason = "platform math library" }, { path = "f64::atan", reason = "platform math library" }, { path = "f32::atan", reason = "platform math library" }, { path = "f64::atan2", reason = "platform math library" }, { path = "f32::atan2", reason = "platform math library" }, { path = "f64::sinh", reason = "platform math library" }, { path = "f32::sinh", reason = "platform math library" }, { path = "f64::cosh", reason = "platform math library" }, { path = "f32::cosh", reason = "platform math library" }, { path = "f64::tanh", reason = "platform math library" }, { path = "f32::tanh", reason = "platform math library" }, { path = "f64::asinh", reason = "platform math library" }, { path = "f32::asinh", reason = "platform math library" }, { path = "f64::acosh", reason = "platform math library" }, { path = "f32::acosh", reason = "platform math library" }, { path = "f64::atanh", reason = "platform math library" }, { path = "f32::atanh", reason = "platform math library" }, { path = "f64::cbrt", reason = "platform math library" }, { path = "f32::cbrt", reason = "platform math library" }, { path = "f64::hypot", reason = "platform math library" }, { path = "f32::hypot", reason = "platform math library" }, { path = "f64::abs_sub", reason = "platform math library (fdim)" }, { path = "f32::abs_sub", reason = "platform math library (fdim)" }, # Rounding to an integer and remainders: exactly specified, but on some targets # (baseline x86_64, wasm32) they compile to a call whose provider depends on the # link. The decode takes rounding from crate::float_repro. { path = "f64::round", reason = "may compile to a library call; use crate::float_repro::round_half_away" }, { path = "f32::round", reason = "may compile to a library call; use crate::float_repro::round_half_away_f32" }, { path = "f64::round_ties_even", reason = "may compile to a library call; use crate::float_repro::round_half_even" }, { path = "f32::round_ties_even", reason = "may compile to a library call" }, { path = "f64::floor", reason = "may compile to a library call" }, { path = "f32::floor", reason = "may compile to a library call" }, { path = "f64::ceil", reason = "may compile to a library call" }, { path = "f32::ceil", reason = "may compile to a library call" }, { path = "f64::trunc", reason = "may compile to a library call" }, { path = "f32::trunc", reason = "may compile to a library call" }, { path = "f64::fract", reason = "may compile to a library call (trunc)" }, { path = "f32::fract", reason = "may compile to a library call (trunc)" }, { path = "f64::rem_euclid", reason = "compiles to a library call (fmod)" }, { path = "f32::rem_euclid", reason = "compiles to a library call (fmod)" }, { path = "f64::div_euclid", reason = "may compile to a library call (trunc)" }, { path = "f32::div_euclid", reason = "may compile to a library call (trunc)" }, # Fused multiply-add rounds once where `a * b + c` rounds twice, and falls back to a # library `fma` on targets without the instruction. { path = "f64::mul_add", reason = "fused: one rounding where the decode's arithmetic has two" }, { path = "f32::mul_add", reason = "fused: one rounding where the decode's arithmetic has two" }, # IEEE maxNum/minNum leave the sign of a zero result unspecified, and some targets # call the library's fmax/fmin. The decode clamps with `clamp`, which compares. { path = "f64::max", reason = "sign of a zero result unspecified; may call fmax" }, { path = "f32::max", reason = "sign of a zero result unspecified; may call fmaxf" }, { path = "f64::min", reason = "sign of a zero result unspecified; may call fmin" }, { path = "f32::min", reason = "sign of a zero result unspecified; may call fminf" }, ]