fp64Lower
On this page

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): ModuleDecl

Parameters

m ModuleDecl

the module to lower.

optsoptional Fp64LowerOptions

flavor selects which primitives back the helpers; see Fp64Flavor.

Return value

ModuleDecl

a new module with its f64 declarations and bodies rewritten and the helper functions appended, or m itself when it contains no f64.

Exceptions

SD0041

SD0041 for an operation on f64 operands that has no emulation.

SD0042

SD0042 when the module declares a _fp64 binding whose type differs from the guard’s.

SD0043

SD0043 when the module declares a function named df64_* or a struct named DF64Vec* or DF64Mat*; those names are reserved for the injected helpers.

SD0044

SD0044 for an f64 in an interpolated @location struct 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 f64
const lowered = fp64Lower(authored, { flavor: 'integer' })
// lowered.funcs ends with the df64_* helpers the module needs

In the guide

See also

Source

src/core/passes/fp64-lower.ts, line 1543, at commit 26de7be8

Edit this page Report a problem