Skip to content
volt
GitHub

std::softfloat

IEEE 754 arithmetic on the bits of floats, with integer instructions only, rounding to nearest with ties to even like the hardware: what a CPU without a floating-point unit uses (std/bare.volt hands these to LLVM under the names it calls, __adddf3 and the rest). The f64 code follows compiler-rt's generic soft-float; the f32 operations go through f64 and round once more, which gives the exact f32 result for +, -, * and / (53 bits is more than twice 24, plus two). The f128 operations are the f64 ones on u128 bits; on aarch64 macOS, whose C runtime has no quad routines, and on os=none, which has no C runtime, they're exported under compiler-rt's names (namespace quad_rt, at the end).

Source: std/softfloat.volt

Functions

std::softfloat::clz64

fn clz64(x: u64) -> i32

the number of leading zero bits of x (64 for 0)

std::softfloat::shift_sticky

fn shift_sticky(x: u64, by: i32) -> u64

x >> by, with a 1 in the lowest bit when anything nonzero was shifted out ("sticky")

std::softfloat::pack64

fn pack64(sign: u64, exp0: i32, sig0: u64) -> u64

the result from its sign, biased exponent and significand: the significand's leading 1 at bit 55 (for exp >= 1), its low three bits the guard, round and sticky bits. Below the smallest normal the significand shifts right (a subnormal, or zero); past the largest it's infinity

std::softfloat::pack32

fn pack32(sign: u32, exp0: i32, sig0: u64) -> u32

the same for an f32: the significand's leading 1 at bit 26, three rounding bits below it

std::softfloat::is_nan

fn is_nan(a: u64) -> bool

std::softfloat::unpack

fn unpack(a: u64, sig: u64&, exp: i32&) -> void

a finite nonzero |a|'s significand (leading 1 at bit 52) and exponent, subnormals normalized (their exponent goes to 0 or below)

std::softfloat::add64

fn add64(a: u64, b: u64) -> u64

std::softfloat::sub64

fn sub64(a: u64, b: u64) -> u64

std::softfloat::mul_wide

fn mul_wide(a: u64, b: u64, hi: u64&, lo: u64&) -> void

the 128-bit product of a and b, from 32-bit pieces (32-bit cores have no 64-bit multiply high)

std::softfloat::mul64

fn mul64(a: u64, b: u64) -> u64

std::softfloat::div64

fn div64(a: u64, b: u64) -> u64

std::softfloat::cmp64

fn cmp64(a: u64, b: u64) -> i32

-1, 0 or 1 as a is less than, equal to or greater than b; 2 when either is NaN. -0 equals 0

std::softfloat::f32_to_f64

fn f32_to_f64(a: u32) -> u64

std::softfloat::f64_to_f32

fn f64_to_f32(a: u64) -> u32

std::softfloat::u64_to_f64

fn u64_to_f64(neg: bool, v: u64) -> u64

an integer's magnitude, and whether it's negative, as an f64 or f32 (rounded once)

std::softfloat::u64_to_f32

fn u64_to_f32(neg: bool, v: u64) -> u32

std::softfloat::i64_to_f64

fn i64_to_f64(v: i64) -> u64

std::softfloat::i64_to_f32

fn i64_to_f32(v: i64) -> u32

std::softfloat::f64_to_magnitude

fn f64_to_magnitude(a: u64, bits: i32) -> u64

a's integer part (toward zero) as an unsigned magnitude no wider than bits, saturating past it; NaN gives the largest

std::softfloat::f64_to_i64

fn f64_to_i64(a: u64) -> i64

std::softfloat::f64_to_u64

fn f64_to_u64(a: u64) -> u64

std::softfloat::f64_to_i32

fn f64_to_i32(a: u64) -> i32

std::softfloat::f64_to_u32

fn f64_to_u32(a: u64) -> u32

std::softfloat::add32

fn add32(a: u32, b: u32) -> u32

std::softfloat::sub32

fn sub32(a: u32, b: u32) -> u32

std::softfloat::mul32

fn mul32(a: u32, b: u32) -> u32

std::softfloat::div32

fn div32(a: u32, b: u32) -> u32

std::softfloat::cmp32

fn cmp32(a: u32, b: u32) -> i32

std::softfloat::clz128

fn clz128(x: u128) -> i32

std::softfloat::shift_sticky128

fn shift_sticky128(x: u128, by: i32) -> u128

std::softfloat::pack128

fn pack128(sign: u128, exp0: i32, sig0: u128) -> u128

pack64's f128 twin: the significand's leading 1 at bit 115, three rounding bits below it

std::softfloat::is_nan128

fn is_nan128(a: u128) -> bool

std::softfloat::unpack128

fn unpack128(a: u128, sig: u128&, exp: i32&) -> void

a finite nonzero |a|'s significand (leading 1 at bit 112) and exponent, subnormals normalized

std::softfloat::add128

fn add128(a: u128, b: u128) -> u128

std::softfloat::sub128

fn sub128(a: u128, b: u128) -> u128

std::softfloat::mul_wide64

fn mul_wide64(a: u64, b: u64) -> u128

the 64-bit halves' product as a u128 (from mul_wide: no 128-bit multiply needed)

std::softfloat::mul128

fn mul128(a: u128, b: u128) -> u128

std::softfloat::div128

fn div128(a: u128, b: u128) -> u128

std::softfloat::cmp128

fn cmp128(a: u128, b: u128) -> i32

-1, 0 or 1 as a is less than, equal to or greater than b; 2 when either is NaN

std::softfloat::widen128

fn widen128(a: u64, fbits: i32, ebits: i32) -> u128

a narrower float's bits (f16, f32 or f64: fbits fraction bits under ebits exponent bits) as an f128, exactly; a NaN keeps its payload, quieted

std::softfloat::narrow128

fn narrow128(a: u128, fbits: i32, ebits: i32) -> u64

an f128 rounded to a narrower float (widen128's parameters), its bits in the low end of a u64

std::softfloat::f16_to_f128

fn f16_to_f128(a: u16) -> u128

std::softfloat::f32_to_f128

fn f32_to_f128(a: u32) -> u128

std::softfloat::f64_to_f128

fn f64_to_f128(a: u64) -> u128

std::softfloat::f128_to_f16

fn f128_to_f16(a: u128) -> u16

std::softfloat::f128_to_f32

fn f128_to_f32(a: u128) -> u32

std::softfloat::f128_to_f64

fn f128_to_f64(a: u128) -> u64

std::softfloat::u128_to_f128

fn u128_to_f128(neg: bool, v: u128) -> u128

an integer's magnitude, and whether it's negative, as an f128 (exact up to 113 bits)

std::softfloat::i128_to_f128

fn i128_to_f128(v: i128) -> u128

std::softfloat::f128_to_magnitude

fn f128_to_magnitude(a: u128, bits: i32) -> u128

a's integer part (toward zero) as an unsigned magnitude no wider than bits, saturating past it; NaN gives the largest

std::softfloat::f128_to_signed

fn f128_to_signed(a: u128, bits: i32) -> i128

to a signed integer of bits bits (32, 64 or 128), saturating by the sign bit as compiler-rt does: a NaN gives the largest, or the smallest when its sign bit is set

std::softfloat::f128_to_unsigned

fn f128_to_unsigned(a: u128, bits: i32) -> u128

std::softfloat::rem128

fn rem128(a: u128, b: u128) -> u128

the remainder of a / b with a's sign, exact (C's fmod, which can't round: the remainder is a binary128 itself): the significands reduced a bit of the exponent gap at a time by shifting and subtracting (no 128-bit division, which bare metal doesn't have), stopping early at a zero remainder; at most about 32900 steps for the widest gap

std::softfloat::volt_f128_rem

export fn volt_f128_rem(x: f128, y: f128) -> f128

f128 % for both backends (voltc calls it for every f128 remainder, on every target)

std::softfloat::parse128

fn parse128(text: str) -> u128

the binary128 nearest the unsigned decimal number text spells (digits, _ between them, an optional fraction and e/E exponent), ties to even: num / den exactly, its quotient taken to 116 or 117 bits by long division, the remainder sticky, and pack128 rounding (subnormals, inf)

std::softfloat::quad_rt::b

fn b(v: f128) -> u128

std::softfloat::quad_rt::q

fn q(v: u128) -> f128

std::softfloat::quad_rt::le

fn le(x: f128, y: f128) -> i32

as libgcc's: <0, 0 or >0 like x - y; a NaN gives 1 to eq/ne/lt/le, -1 to ge/gt

std::softfloat::quad_rt::ge

fn ge(x: f128, y: f128) -> i32

std::softfloat::quad_rt::unord

fn unord(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__addtf3

export fn __addtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::apple::__subtf3

export fn __subtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::apple::__multf3

export fn __multf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::apple::__divtf3

export fn __divtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::apple::__negtf2

export fn __negtf2(x: f128) -> f128

std::softfloat::quad_rt::apple::__eqtf2

export fn __eqtf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__netf2

export fn __netf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__lttf2

export fn __lttf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__letf2

export fn __letf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__getf2

export fn __getf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__gttf2

export fn __gttf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__unordtf2

export fn __unordtf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::apple::__extendhftf2

export fn __extendhftf2(x: f16) -> f128

std::softfloat::quad_rt::apple::__extendsftf2

export fn __extendsftf2(x: f32) -> f128

std::softfloat::quad_rt::apple::__extenddftf2

export fn __extenddftf2(x: f64) -> f128

std::softfloat::quad_rt::apple::__trunctfhf2

export fn __trunctfhf2(x: f128) -> f16

std::softfloat::quad_rt::apple::__trunctfsf2

export fn __trunctfsf2(x: f128) -> f32

std::softfloat::quad_rt::apple::__trunctfdf2

export fn __trunctfdf2(x: f128) -> f64

std::softfloat::quad_rt::apple::__fixtfsi

export fn __fixtfsi(x: f128) -> i32

std::softfloat::quad_rt::apple::__fixtfdi

export fn __fixtfdi(x: f128) -> i64

std::softfloat::quad_rt::apple::__fixtfti

export fn __fixtfti(x: f128) -> i128

std::softfloat::quad_rt::apple::__fixunstfsi

export fn __fixunstfsi(x: f128) -> u32

std::softfloat::quad_rt::apple::__fixunstfdi

export fn __fixunstfdi(x: f128) -> u64

std::softfloat::quad_rt::apple::__fixunstfti

export fn __fixunstfti(x: f128) -> u128

std::softfloat::quad_rt::apple::__floatsitf

export fn __floatsitf(i: i32) -> f128

std::softfloat::quad_rt::apple::__floatditf

export fn __floatditf(i: i64) -> f128

std::softfloat::quad_rt::apple::__floattitf

export fn __floattitf(i: i128) -> f128

std::softfloat::quad_rt::apple::__floatunsitf

export fn __floatunsitf(i: u32) -> f128

std::softfloat::quad_rt::apple::__floatunditf

export fn __floatunditf(i: u64) -> f128

std::softfloat::quad_rt::apple::__floatuntitf

export fn __floatuntitf(i: u128) -> f128

std::softfloat::quad_rt::bare::__addtf3

export fn __addtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::bare::__subtf3

export fn __subtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::bare::__multf3

export fn __multf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::bare::__divtf3

export fn __divtf3(x: f128, y: f128) -> f128

std::softfloat::quad_rt::bare::__negtf2

export fn __negtf2(x: f128) -> f128

std::softfloat::quad_rt::bare::__eqtf2

export fn __eqtf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__netf2

export fn __netf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__lttf2

export fn __lttf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__letf2

export fn __letf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__getf2

export fn __getf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__gttf2

export fn __gttf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__unordtf2

export fn __unordtf2(x: f128, y: f128) -> i32

std::softfloat::quad_rt::bare::__extendhftf2

export fn __extendhftf2(x: f16) -> f128

std::softfloat::quad_rt::bare::__extendsftf2

export fn __extendsftf2(x: f32) -> f128

std::softfloat::quad_rt::bare::__extenddftf2

export fn __extenddftf2(x: f64) -> f128

std::softfloat::quad_rt::bare::__trunctfhf2

export fn __trunctfhf2(x: f128) -> f16

std::softfloat::quad_rt::bare::__trunctfsf2

export fn __trunctfsf2(x: f128) -> f32

std::softfloat::quad_rt::bare::__trunctfdf2

export fn __trunctfdf2(x: f128) -> f64

std::softfloat::quad_rt::bare::__fixtfsi

export fn __fixtfsi(x: f128) -> i32

std::softfloat::quad_rt::bare::__fixtfdi

export fn __fixtfdi(x: f128) -> i64

std::softfloat::quad_rt::bare::__fixtfti

export fn __fixtfti(x: f128) -> i128

std::softfloat::quad_rt::bare::__fixunstfsi

export fn __fixunstfsi(x: f128) -> u32

std::softfloat::quad_rt::bare::__fixunstfdi

export fn __fixunstfdi(x: f128) -> u64

std::softfloat::quad_rt::bare::__fixunstfti

export fn __fixunstfti(x: f128) -> u128

std::softfloat::quad_rt::bare::__floatsitf

export fn __floatsitf(i: i32) -> f128

std::softfloat::quad_rt::bare::__floatditf

export fn __floatditf(i: i64) -> f128

std::softfloat::quad_rt::bare::__floattitf

export fn __floattitf(i: i128) -> f128

std::softfloat::quad_rt::bare::__floatunsitf

export fn __floatunsitf(i: u32) -> f128

std::softfloat::quad_rt::bare::__floatunditf

export fn __floatunditf(i: u64) -> f128

std::softfloat::quad_rt::bare::__floatuntitf

export fn __floatuntitf(i: u128) -> f128

Globals

val SIGN: u64 = 0x8000000000000000
val INF: u64 = 0x7FF0000000000000
val FRAC: u64 = 0x000FFFFFFFFFFFFF
val IMPLICIT: u64 = 0x0010000000000000
val QUIET: u64 = 0x0008000000000000
val NAN: u64 = 0x7FF8000000000000
val Q_ABS: u128 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
val Q_INF: u128 = 0x7FFF0000000000000000000000000000
val Q_FRAC: u128 = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
val Q_IMPLICIT: u128 = 0x00010000000000000000000000000000
val Q_QUIET: u128 = 0x00008000000000000000000000000000
val Q_NAN: u128 = 0x7FFF8000000000000000000000000000