aboutsummaryrefslogtreecommitdiff
path: root/lib/std/special/compiler_rt/extendXfYf2.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/special/compiler_rt/extendXfYf2.zig')
-rw-r--r--lib/std/special/compiler_rt/extendXfYf2.zig96
1 files changed, 96 insertions, 0 deletions
diff --git a/lib/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig
new file mode 100644
index 0000000000..e10667843f
--- /dev/null
+++ b/lib/std/special/compiler_rt/extendXfYf2.zig
@@ -0,0 +1,96 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const is_test = builtin.is_test;
+
+pub extern fn __extendsfdf2(a: f32) f64 {
+ return @inlineCall(extendXfYf2, f64, f32, @bitCast(u32, a));
+}
+
+pub extern fn __extenddftf2(a: f64) f128 {
+ return @inlineCall(extendXfYf2, f128, f64, @bitCast(u64, a));
+}
+
+pub extern fn __extendsftf2(a: f32) f128 {
+ return @inlineCall(extendXfYf2, f128, f32, @bitCast(u32, a));
+}
+
+pub extern fn __extendhfsf2(a: u16) f32 {
+ return @inlineCall(extendXfYf2, f32, f16, a);
+}
+
+const CHAR_BIT = 8;
+
+fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: @IntType(false, @typeInfo(src_t).Float.bits)) dst_t {
+ @setRuntimeSafety(builtin.is_test);
+
+ const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
+ const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
+ const srcSigBits = std.math.floatMantissaBits(src_t);
+ const dstSigBits = std.math.floatMantissaBits(dst_t);
+ const SrcShift = std.math.Log2Int(src_rep_t);
+ const DstShift = std.math.Log2Int(dst_rep_t);
+
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const srcBits = @sizeOf(src_t) * CHAR_BIT;
+ const srcExpBits = srcBits - srcSigBits - 1;
+ const srcInfExp = (1 << srcExpBits) - 1;
+ const srcExpBias = srcInfExp >> 1;
+
+ const srcMinNormal = 1 << srcSigBits;
+ const srcInfinity = srcInfExp << srcSigBits;
+ const srcSignMask = 1 << (srcSigBits + srcExpBits);
+ const srcAbsMask = srcSignMask - 1;
+ const srcQNaN = 1 << (srcSigBits - 1);
+ const srcNaNCode = srcQNaN - 1;
+
+ const dstBits = @sizeOf(dst_t) * CHAR_BIT;
+ const dstExpBits = dstBits - dstSigBits - 1;
+ const dstInfExp = (1 << dstExpBits) - 1;
+ const dstExpBias = dstInfExp >> 1;
+
+ const dstMinNormal: dst_rep_t = dst_rep_t(1) << dstSigBits;
+
+ // Break a into a sign and representation of the absolute value
+ const aRep: src_rep_t = @bitCast(src_rep_t, a);
+ const aAbs: src_rep_t = aRep & srcAbsMask;
+ const sign: src_rep_t = aRep & srcSignMask;
+ var absResult: dst_rep_t = undefined;
+
+ if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) {
+ // a is a normal number.
+ // Extend to the destination type by shifting the significand and
+ // exponent into the proper position and rebiasing the exponent.
+ absResult = dst_rep_t(aAbs) << (dstSigBits - srcSigBits);
+ absResult += (dstExpBias - srcExpBias) << dstSigBits;
+ } else if (aAbs >= srcInfinity) {
+ // a is NaN or infinity.
+ // Conjure the result by beginning with infinity, then setting the qNaN
+ // bit (if needed) and right-aligning the rest of the trailing NaN
+ // payload field.
+ absResult = dstInfExp << dstSigBits;
+ absResult |= dst_rep_t(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
+ absResult |= dst_rep_t(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
+ } else if (aAbs != 0) {
+ // a is denormal.
+ // renormalize the significand and clear the leading bit, then insert
+ // the correct adjusted exponent in the destination type.
+ const scale: u32 = @clz(src_rep_t, aAbs) -
+ @clz(src_rep_t, src_rep_t(srcMinNormal));
+ absResult = dst_rep_t(aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
+ absResult ^= dstMinNormal;
+ const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;
+ absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits;
+ } else {
+ // a is zero.
+ absResult = 0;
+ }
+
+ // Apply the signbit to (dst_t)abs(a).
+ const result: dst_rep_t align(@alignOf(dst_t)) = absResult | dst_rep_t(sign) << (dstBits - srcBits);
+ return @bitCast(dst_t, result);
+}
+
+test "import extendXfYf2" {
+ _ = @import("extendXfYf2_test.zig");
+}