mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 06:15:21 +00:00
The purpose of this branch is to switch to using an object file for each independent function, in order to make linking simpler - instead of relying on `-ffunction-sections` and `--gc-sections`, which involves the linker doing the work of linking everything and then undoing work via garbage collection, this will allow the linker to only include the compilation units that are depended on in the first place. This commit makes progress towards that goal.
67 lines
2.7 KiB
Zig
67 lines
2.7 KiB
Zig
const math = @import("std").math;
|
|
const common = @import("./common.zig");
|
|
const trunc_f80 = @import("./truncf.zig").trunc_f80;
|
|
|
|
pub const panic = common.panic;
|
|
|
|
comptime {
|
|
@export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage });
|
|
}
|
|
|
|
fn __trunctfxf2(a: f128) callconv(.C) f80 {
|
|
const src_sig_bits = math.floatMantissaBits(f128);
|
|
const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit
|
|
|
|
// Various constants whose values follow from the type parameters.
|
|
// Any reasonable optimizer will fold and propagate all of these.
|
|
const src_bits = @typeInfo(f128).Float.bits;
|
|
const src_exp_bits = src_bits - src_sig_bits - 1;
|
|
const src_inf_exp = 0x7FFF;
|
|
|
|
const src_inf = src_inf_exp << src_sig_bits;
|
|
const src_sign_mask = 1 << (src_sig_bits + src_exp_bits);
|
|
const src_abs_mask = src_sign_mask - 1;
|
|
const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1;
|
|
const halfway = 1 << (src_sig_bits - dst_sig_bits - 1);
|
|
|
|
// Break a into a sign and representation of the absolute value
|
|
const a_rep = @bitCast(u128, a);
|
|
const a_abs = a_rep & src_abs_mask;
|
|
const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0;
|
|
const integer_bit = 1 << 63;
|
|
|
|
var res: math.F80 = undefined;
|
|
|
|
if (a_abs > src_inf) {
|
|
// a is NaN.
|
|
// Conjure the result by beginning with infinity, setting the qNaN
|
|
// bit and inserting the (truncated) trailing NaN field.
|
|
res.exp = 0x7fff;
|
|
res.fraction = 0x8000000000000000;
|
|
res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits));
|
|
} else {
|
|
// The exponent of a is within the range of normal numbers in the
|
|
// destination format. We can convert by simply right-shifting with
|
|
// rounding, adding the explicit integer bit, and adjusting the exponent
|
|
res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit;
|
|
res.exp = @truncate(u16, a_abs >> src_sig_bits);
|
|
|
|
const round_bits = a_abs & round_mask;
|
|
if (round_bits > halfway) {
|
|
// Round to nearest
|
|
const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction));
|
|
res.exp += carry;
|
|
res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
|
|
} else if (round_bits == halfway) {
|
|
// Ties to even
|
|
const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction));
|
|
res.exp += carry;
|
|
res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
|
|
}
|
|
if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
|
|
}
|
|
|
|
res.exp |= sign;
|
|
return math.make_f80(res);
|
|
}
|