master
 1const math = @import("std").math;
 2const common = @import("./common.zig");
 3const trunc_f80 = @import("./truncf.zig").trunc_f80;
 4
 5pub const panic = common.panic;
 6
 7comptime {
 8    @export(&__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage, .visibility = common.visibility });
 9}
10
11pub fn __trunctfxf2(a: f128) callconv(.c) f80 {
12    const src_sig_bits = math.floatMantissaBits(f128);
13    const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit
14
15    // Various constants whose values follow from the type parameters.
16    // Any reasonable optimizer will fold and propagate all of these.
17    const src_bits = @typeInfo(f128).float.bits;
18    const src_exp_bits = src_bits - src_sig_bits - 1;
19    const src_inf_exp = 0x7FFF;
20
21    const src_inf = src_inf_exp << src_sig_bits;
22    const src_sign_mask = 1 << (src_sig_bits + src_exp_bits);
23    const src_abs_mask = src_sign_mask - 1;
24    const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1;
25    const halfway = 1 << (src_sig_bits - dst_sig_bits - 1);
26
27    // Break a into a sign and representation of the absolute value
28    const a_rep = @as(u128, @bitCast(a));
29    const a_abs = a_rep & src_abs_mask;
30    const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0;
31    const integer_bit = 1 << 63;
32
33    var res: math.F80 = undefined;
34
35    if (a_abs > src_inf) {
36        // a is NaN.
37        // Conjure the result by beginning with infinity, setting the qNaN
38        // bit and inserting the (truncated) trailing NaN field.
39        res.exp = 0x7fff;
40        res.fraction = 0x8000000000000000;
41        res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits)));
42    } else {
43        // The exponent of a is within the range of normal numbers in the
44        // destination format.  We can convert by simply right-shifting with
45        // rounding, adding the explicit integer bit, and adjusting the exponent
46        res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit;
47        res.exp = @truncate(a_abs >> src_sig_bits);
48
49        const round_bits = a_abs & round_mask;
50        if (round_bits > halfway) {
51            // Round to nearest
52            const ov = @addWithOverflow(res.fraction, 1);
53            res.fraction = ov[0];
54            res.exp += ov[1];
55            res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
56        } else if (round_bits == halfway) {
57            // Ties to even
58            const ov = @addWithOverflow(res.fraction, res.fraction & 1);
59            res.fraction = ov[0];
60            res.exp += ov[1];
61            res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry
62        }
63        if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
64    }
65
66    res.exp |= sign;
67    return res.toFloat();
68}