fp64Lower()
Function in Emulated f64
Rewrite every f64 value in a module into its two-f32 emulation, so that no backend has to spell the type.
import { fp64Lower } from 'typeshade'
The signature, the description and the examples come from the compiler's own source at commit 26de7be8.
Syntax
function fp64Lower(m: ModuleDecl, opts?: Fp64LowerOptions): ModuleDeclParameters
mModuleDeclthe module to lower.
optsoptionalFp64LowerOptionsflavorselects which primitives back the helpers; seeFp64Flavor.
Return value
a new module with its f64 declarations and bodies rewritten and the helper functions
appended, or m itself when it contains no f64.
Exceptions
SD0041SD0041 for an operation on f64 operands that has no emulation.
SD0042SD0042 when the module declares a
_fp64binding whose type differs from the guard’s.SD0043SD0043 when the module declares a function named
df64_*or a struct namedDF64Vec*orDF64Mat*; those names are reserved for the injected helpers.SD0044SD0044 for an f64 in an interpolated
@locationstruct field, a fragment input, or a stage entry’s return value; interpolating a (hi, lo) pair is numerically wrong.
Description
An f64 scalar becomes a vec2<f32> holding a (hi, lo) pair, vecN<f64>
becomes a DF64VecN struct of two vecN<f32> planes, matNxN<f64> becomes a DF64MatN
struct, and the arithmetic, comparisons and supported builtins over them become calls to
injected df64_* helper functions, which are appended to the module’s funcs. A module with
no f64 anywhere is returned as the same object.
Supported on f64 operands: + - * /, negation, the six comparisons, sqrt, abs, min,
max, mix (with an f32 interpolant), floor, fract, sin, cos, widening from f32 and
narrowing to f32. On vecN<f64> additionally dot, length, distance, normalize and
the componentwise forms of the list above; on matNxN<f64>, * and transpose. Any other
builtin on an f64 operand throws; narrow the operand to f32 first when you need one.
Two kinds of multiply take a cheaper form. x * x, when x has no side effect, is
df64_sqr(x), the multiply specialised to one operand. A multiply by a power-of-two
literal, or a divide by such a literal, scales the two words of the pair by an f32 literal,
which is exact barring overflow and underflow. A scale that can grow the value (|s| > 1)
is taken only when x is computed at run time, so that WGSL never evaluates a constant
that overflows while it creates the shader; a constant x keeps the general multiply.
When an injected helper reads the runtime guard, the pass also declares the _fp64 guard
binding at group 0, first index past the module’s own group-0 bindings. Declare
fp64Guard in the module to pin that slot yourself. The host writes 1.0 into it.
Those helpers take the guard as a trailing _fp64_g: f32 parameter rather than fetching
it themselves, and every call of one from the module’s own functions passes the texel
fetch as that argument. The emit functions then read it once per function, into a let
named _fp64_g at the top of the body, after the optimizer has run.
The emit functions run this pass for you; pass fp64Flavor in EmitOptions to select
the flavour there. Call it directly when you want to inspect the lowered module.
Examples
Example
import { fp64Lower } from 'typeshade'
// authored: a ModuleDecl whose functions use f64const lowered = fp64Lower(authored, { flavor: 'integer' })// lowered.funcs ends with the df64_* helpers the module needsIn the guide
See also
Source
src/core/passes/fp64-lower.ts, line 1543, at commit 26de7be8