aboutsummaryrefslogtreecommitdiff
path: root/lib/compiler_rt/extendxftf2.zig
blob: 39d66d399ca73f0390183b3270df9fea9a3af64d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const std = @import("std");
const common = @import("./common.zig");

pub const panic = common.panic;

comptime {
    @export(&__extendxftf2, .{ .name = "__extendxftf2", .linkage = common.linkage, .visibility = common.visibility });
}

fn __extendxftf2(a: f80) callconv(.c) f128 {
    const src_int_bit: u64 = 0x8000000000000000;
    const src_sig_mask = ~src_int_bit;
    const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit
    const dst_sig_bits = std.math.floatMantissaBits(f128);

    const dst_bits = @bitSizeOf(f128);

    // Break a into a sign and representation of the absolute value
    var a_rep = std.math.F80.fromFloat(a);
    const sign = a_rep.exp & 0x8000;
    a_rep.exp &= 0x7FFF;
    var abs_result: u128 = undefined;

    if (a_rep.exp == 0 and a_rep.fraction == 0) {
        // zero
        abs_result = 0;
    } else if (a_rep.exp == 0x7FFF) {
        // a is nan or infinite
        abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits);
        abs_result |= @as(u128, a_rep.exp) << dst_sig_bits;
    } else if (a_rep.fraction & src_int_bit != 0) {
        // a is a normal value
        abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits);
        abs_result |= @as(u128, a_rep.exp) << dst_sig_bits;
    } else {
        // a is denormal
        abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits);
    }

    // Apply the signbit to (dst_t)abs(a).
    const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16);
    return @bitCast(result);
}