zig/lib/compiler_rt/float_from_int.zig
mlugg f26dda2117 all: migrate code to new cast builtin syntax
Most of this migration was performed automatically with `zig fmt`. There
were a few exceptions which I had to manually fix:

* `@alignCast` and `@addrSpaceCast` cannot be automatically rewritten
* `@truncate`'s fixup is incorrect for vectors
* Test cases are not formatted, and their error locations change
2023-06-24 16:56:39 -07:00

59 lines
2.3 KiB
Zig

const Int = @import("std").meta.Int;
const math = @import("std").math;
pub fn floatFromInt(comptime T: type, x: anytype) T {
if (x == 0) return 0;
// Various constants whose values follow from the type parameters.
// Any reasonable optimizer will fold and propagate all of these.
const Z = Int(.unsigned, @bitSizeOf(@TypeOf(x)));
const uT = Int(.unsigned, @bitSizeOf(T));
const inf = math.inf(T);
const float_bits = @bitSizeOf(T);
const int_bits = @bitSizeOf(@TypeOf(x));
const exp_bits = math.floatExponentBits(T);
const fractional_bits = math.floatFractionalBits(T);
const exp_bias = math.maxInt(Int(.unsigned, exp_bits - 1));
const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0;
const max_exp = exp_bias;
// Sign
var abs_val = math.absCast(x);
const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
var result: uT = sign_bit;
// Compute significand
var exp = int_bits - @clz(abs_val) - 1;
if (int_bits <= fractional_bits or exp <= fractional_bits) {
const shift_amt = fractional_bits - @as(math.Log2Int(uT), @intCast(exp));
// Shift up result to line up with the significand - no rounding required
result = (@as(uT, @intCast(abs_val)) << shift_amt);
result ^= implicit_bit; // Remove implicit integer bit
} else {
var shift_amt = @as(math.Log2Int(Z), @intCast(exp - fractional_bits));
const exact_tie: bool = @ctz(abs_val) == shift_amt - 1;
// Shift down result and remove implicit integer bit
result = @as(uT, @intCast((abs_val >> (shift_amt - 1)))) ^ (implicit_bit << 1);
// Round result, including round-to-even for exact ties
result = ((result + 1) >> 1) & ~@as(uT, @intFromBool(exact_tie));
}
// Compute exponent
if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity
return @as(T, @bitCast(sign_bit | @as(uT, @bitCast(inf))));
result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T);
// If the result included a carry, we need to restore the explicit integer bit
if (T == f80) result |= 1 << fractional_bits;
return @as(T, @bitCast(sign_bit | result));
}
test {
_ = @import("float_from_int_test.zig");
}