authorgravatar for hi@mihaelm.commihael <hi@mihaelm.com> 2026-03-27 22:45:56+01:00
committergravatar for hi@mihaelm.commihael <hi@mihaelm.com> 2026-04-02 23:54:20+02:00
log61161132b63d641657df3f099511e2fa5062d0d1
tree61053d284233594caffbc28c3aa9621d1b82ea64
parentf6ac1a6e05cbd46f646cf09e036921ca282694cf
signaturebadge-check Signed by SSH key SHA256:aoFoShdYLdrqMichqKXSSieTKUfACUIDJHsKc4V2tQg

`compiler_rt`: Dissolve `math_utils.zig` into `long_double.zig` & `trig.zig`

The closest namespace the pi/4 constant could belong to is `trig.zig` since it's used across trig function implementations. On the other hand, chucking `long double` bit slicing functions into `trig.zig` seems a little more awkward, so they're put into their own namespace.

8 files changed, 60 insertions(+), 57 deletions(-)

lib/compiler_rt/cos.zig+3-3
...@@ -17,7 +17,7 @@ const trig = @import("trig.zig");...@@ -17,7 +17,7 @@ const trig = @import("trig.zig");
17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;
20const utils = @import("math_utils.zig");20const ld = @import("long_double.zig");
2121
22comptime {22comptime {
23 symbol(&__cosh, "__cosh");23 symbol(&__cosh, "__cosh");
...@@ -124,12 +124,12 @@ pub fn cos(x: f64) callconv(.c) f64 {...@@ -124,12 +124,12 @@ pub fn cos(x: f64) callconv(.c) f64 {
124}124}
125125
126fn coslGeneric(comptime T: type, x: T) T {126fn coslGeneric(comptime T: type, x: T) T {
127 const se = utils.ldSignExponent(x) & 0x7fff;127 const se = ld.signExponent(x) & 0x7fff;
128 if (se == 0x7fff) {128 if (se == 0x7fff) {
129 return x - x;129 return x - x;
130 }130 }
131131
132 if (@abs(x) < utils.pi_4) {132 if (@abs(x) < trig.pi_4) {
133 if (se < 0x3fff - math.floatMantissaBits(T)) {133 if (se < 0x3fff - math.floatMantissaBits(T)) {
134 // raise inexact if x!=0134 // raise inexact if x!=0
135 return 1.0 + x;135 return 1.0 + x;
lib/compiler_rt/long_double.zig created+37
...@@ -0,0 +1,37 @@
1//! Utilities for dealing with the `long double` type (`f80` or `f128`)
2
3const std = @import("std");
4
5pub const U80 = std.meta.Int(.unsigned, 80);
6
7/// Returns the sign + exponent bits of a `long double`
8pub fn signExponent(x: anytype) u16 {
9 const T = @TypeOf(x);
10 switch (T) {
11 f80 => {
12 const bits: U80 = @bitCast(x);
13 return @intCast(bits >> 64);
14 },
15 f128 => {
16 const bits: u128 = @bitCast(x);
17 return @intCast(bits >> 112);
18 },
19 else => @compileError("`signExponent` supports only `f80` and `f128`, got: " ++ @typeName(T)),
20 }
21}
22
23/// Takes the top 16 bits of a `long double`'s mantissa
24pub fn mantissaTop(x: anytype) u16 {
25 const T = @TypeOf(x);
26 switch (T) {
27 f80 => {
28 const bits: U80 = @bitCast(x);
29 return @intCast((bits >> 48) & 0xFFFF);
30 },
31 f128 => {
32 const bits: u128 = @bitCast(x);
33 return @intCast((bits >> 96) & 0xFFFF);
34 },
35 else => @compileError("`mantissaTop` supports only `f80` and `f128`, got: " ++ @typeName(T)),
36 }
37}
lib/compiler_rt/math_utils.zig deleted-37
...@@ -1,37 +0,0 @@
1const std = @import("std");
2
3pub const U80 = std.meta.Int(.unsigned, 80);
4/// pi divided by 4
5pub const pi_4 = 0.78539816339744830962;
6
7/// Returns the sign + exponent bits of a `long double`
8pub fn ldSignExponent(x: anytype) u16 {
9 const T = @TypeOf(x);
10 switch (T) {
11 f80 => {
12 const bits: U80 = @bitCast(x);
13 return @intCast(bits >> 64);
14 },
15 f128 => {
16 const bits: u128 = @bitCast(x);
17 return @intCast(bits >> 112);
18 },
19 else => @compileError("`ldSignExponent` supports only `f80` and `f128`, got: " ++ @typeName(T)),
20 }
21}
22
23/// Takes the top 16 bits of a `long double`'s mantissa
24pub fn ldMantissaTop(x: anytype) u16 {
25 const T = @TypeOf(x);
26 switch (T) {
27 f80 => {
28 const bits: U80 = @bitCast(x);
29 return @intCast((bits >> 48) & 0xFFFF);
30 },
31 f128 => {
32 const bits: u128 = @bitCast(x);
33 return @intCast((bits >> 96) & 0xFFFF);
34 },
35 else => @compileError("`ldMantissaTop` supports only `f80` and `f128`, got: " ++ @typeName(T)),
36 }
37}
lib/compiler_rt/rem_pio2l.zig+8-8
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6const std = @import("std");6const std = @import("std");
7const math = std.math;7const math = std.math;
88
9const utils = @import("math_utils.zig");9const ld = @import("long_double.zig");
10const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large;10const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large;
1111
12pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {12pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
...@@ -34,8 +34,8 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {...@@ -34,8 +34,8 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
34 const pio2_3: f64 = 6.36831716351370313614e-25; // 0x18a2e037074000.0p-13334 const pio2_3: f64 = 6.36831716351370313614e-25; // 0x18a2e037074000.0p-133
3535
36 fn small(x_val: T) bool {36 fn small(x_val: T) bool {
37 const se = utils.ldSignExponent(x_val);37 const se = ld.signExponent(x_val);
38 const top = utils.ldMantissaTop(x_val);38 const top = ld.mantissaTop(x_val);
39 const lhs = (@as(u32, se & 0x7fff) << 16) | top;39 const lhs = (@as(u32, se & 0x7fff) << 16) | top;
40 const rhs: u32 = ((0x3fff + 25) << 16) | 0x921f >> 1 | 0x8000;40 const rhs: u32 = ((0x3fff + 25) << 16) | 0x921f >> 1 | 0x8000;
41 return lhs < rhs;41 return lhs < rhs;
...@@ -62,8 +62,8 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {...@@ -62,8 +62,8 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
62 const pio2_3t: T = -2.5650587247459238361625433492959285e-65;62 const pio2_3t: T = -2.5650587247459238361625433492959285e-65;
6363
64 fn small(x_val: T) bool {64 fn small(x_val: T) bool {
65 const se = utils.ldSignExponent(x_val);65 const se = ld.signExponent(x_val);
66 const top = utils.ldMantissaTop(x_val);66 const top = ld.mantissaTop(x_val);
67 const lhs = (@as(u32, se & 0x7fff) << 16) | top;67 const lhs = (@as(u32, se & 0x7fff) << 16) | top;
68 const rhs: u32 = ((0x3fff + 45) << 16) | 0x921f;68 const rhs: u32 = ((0x3fff + 45) << 16) | 0x921f;
69 return lhs < rhs;69 return lhs < rhs;
...@@ -77,7 +77,7 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {...@@ -77,7 +77,7 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
77 else => @compileError("rem_pio2l supports only f80 and f128, got: " ++ @typeName(T)),77 else => @compileError("rem_pio2l supports only f80 and f128, got: " ++ @typeName(T)),
78 };78 };
7979
80 const x_se = utils.ldSignExponent(x);80 const x_se = ld.signExponent(x);
81 const ex: i32 = @intCast(x_se & 0x7fff);81 const ex: i32 = @intCast(x_se & 0x7fff);
8282
83 if (impl.small(x)) {83 if (impl.small(x)) {
...@@ -105,14 +105,14 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {...@@ -105,14 +105,14 @@ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
105105
106 y[0] = r - w;106 y[0] = r - w;
107107
108 const ey: i32 = @intCast(utils.ldSignExponent(y[0]) & 0x7fff);108 const ey: i32 = @intCast(ld.signExponent(y[0]) & 0x7fff);
109 if (ex - ey > impl.round1) {109 if (ex - ey > impl.round1) {
110 var t = r;110 var t = r;
111 w = fn_ * impl.pio2_2;111 w = fn_ * impl.pio2_2;
112 r = t - w;112 r = t - w;
113 w = fn_ * impl.pio2_2t - ((t - r) - w);113 w = fn_ * impl.pio2_2t - ((t - r) - w);
114 y[0] = r - w;114 y[0] = r - w;
115 const ey2: i32 = @intCast(utils.ldSignExponent(y[0]) & 0x7fff);115 const ey2: i32 = @intCast(ld.signExponent(y[0]) & 0x7fff);
116 if (ex - ey2 > impl.round2) {116 if (ex - ey2 > impl.round2) {
117 t = r;117 t = r;
118 w = fn_ * impl.pio2_3;118 w = fn_ * impl.pio2_3;
lib/compiler_rt/sin.zig+3-3
...@@ -17,7 +17,7 @@ const trig = @import("trig.zig");...@@ -17,7 +17,7 @@ const trig = @import("trig.zig");
17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;
20const utils = @import("math_utils.zig");20const ld = @import("long_double.zig");
2121
22comptime {22comptime {
23 symbol(&__sinh, "__sinh");23 symbol(&__sinh, "__sinh");
...@@ -134,12 +134,12 @@ pub fn sin(x: f64) callconv(.c) f64 {...@@ -134,12 +134,12 @@ pub fn sin(x: f64) callconv(.c) f64 {
134}134}
135135
136fn sinlGeneric(comptime T: type, x: T) T {136fn sinlGeneric(comptime T: type, x: T) T {
137 const se = utils.ldSignExponent(x) & 0x7fff;137 const se = ld.signExponent(x) & 0x7fff;
138 if (se == 0x7fff) {138 if (se == 0x7fff) {
139 return x - x;139 return x - x;
140 }140 }
141141
142 if (@abs(x) < utils.pi_4) {142 if (@abs(x) < trig.pi_4) {
143 if (se < 0x3fff - (math.floatMantissaBits(T) / 2)) {143 if (se < 0x3fff - (math.floatMantissaBits(T) / 2)) {
144 // raise inexact if x!=0 and underflow if subnormal144 // raise inexact if x!=0 and underflow if subnormal
145 if (compiler_rt.want_float_exceptions) {145 if (compiler_rt.want_float_exceptions) {
lib/compiler_rt/sincos.zig+3-3
...@@ -9,7 +9,7 @@ const trig = @import("trig.zig");...@@ -9,7 +9,7 @@ const trig = @import("trig.zig");
9const rem_pio2 = @import("rem_pio2.zig").rem_pio2;9const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
10const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;10const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
11const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;11const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;
12const utils = @import("math_utils.zig");12const ld = @import("long_double.zig");
13const compiler_rt = @import("../compiler_rt.zig");13const compiler_rt = @import("../compiler_rt.zig");
14const symbol = compiler_rt.symbol;14const symbol = compiler_rt.symbol;
1515
...@@ -197,7 +197,7 @@ fn sincoslGeneric(comptime T: type, x: T, r_sin: *T, r_cos: *T) void {...@@ -197,7 +197,7 @@ fn sincoslGeneric(comptime T: type, x: T, r_sin: *T, r_cos: *T) void {
197 @compileError("`sincoslGeneric` implemented only for `f80` and `f128`, got: " ++ @typeName(T));197 @compileError("`sincoslGeneric` implemented only for `f80` and `f128`, got: " ++ @typeName(T));
198 }198 }
199199
200 const se = utils.ldSignExponent(x) & 0x7fff;200 const se = ld.signExponent(x) & 0x7fff;
201 if (se == 0x7fff) {201 if (se == 0x7fff) {
202 const result = x - x;202 const result = x - x;
203 r_sin.* = result;203 r_sin.* = result;
...@@ -205,7 +205,7 @@ fn sincoslGeneric(comptime T: type, x: T, r_sin: *T, r_cos: *T) void {...@@ -205,7 +205,7 @@ fn sincoslGeneric(comptime T: type, x: T, r_sin: *T, r_cos: *T) void {
205 return;205 return;
206 }206 }
207207
208 if (@abs(x) < utils.pi_4) {208 if (@abs(x) < trig.pi_4) {
209 if (se < 0x3fff - math.floatMantissaBits(T)) {209 if (se < 0x3fff - math.floatMantissaBits(T)) {
210 // raise underflow if subnormal210 // raise underflow if subnormal
211 if (compiler_rt.want_float_exceptions and se == 0) {211 if (compiler_rt.want_float_exceptions and se == 0) {
lib/compiler_rt/tan.zig+3-3
...@@ -17,7 +17,7 @@ const kernel = @import("trig.zig");...@@ -17,7 +17,7 @@ const kernel = @import("trig.zig");
17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;17const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;18const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;19const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;
20const utils = @import("math_utils.zig");20const ld = @import("long_double.zig");
2121
22const arch = builtin.cpu.arch;22const arch = builtin.cpu.arch;
23const compiler_rt = @import("../compiler_rt.zig");23const compiler_rt = @import("../compiler_rt.zig");
...@@ -125,12 +125,12 @@ fn tanlGeneric(comptime T: type, x: T) T {...@@ -125,12 +125,12 @@ fn tanlGeneric(comptime T: type, x: T) T {
125 @compileError("`tanlGeneric` implemented only for `f80` and `f128`, got: " ++ T);125 @compileError("`tanlGeneric` implemented only for `f80` and `f128`, got: " ++ T);
126 }126 }
127127
128 const se = utils.ldSignExponent(x) & 0x7fff;128 const se = ld.signExponent(x) & 0x7fff;
129 if (se == 0x7fff) {129 if (se == 0x7fff) {
130 return x - x;130 return x - x;
131 }131 }
132132
133 if (@abs(x) < utils.pi_4) {133 if (@abs(x) < kernel.pi_4) {
134 if (se < 0x3fff - math.floatMantissaBits(T) / 2) {134 if (se < 0x3fff - math.floatMantissaBits(T) / 2) {
135 if (compiler_rt.want_float_exceptions) {135 if (compiler_rt.want_float_exceptions) {
136 mem.doNotOptimizeAway(if (se == 0) x * 0x1p-120 else x + 0x1p120);136 mem.doNotOptimizeAway(if (se == 0) x * 0x1p-120 else x + 0x1p120);
lib/compiler_rt/trig.zig+3
...@@ -11,6 +11,9 @@...@@ -11,6 +11,9 @@
11// https://git.musl-libc.org/cgit/musl/tree/src/math/__cosl.c11// https://git.musl-libc.org/cgit/musl/tree/src/math/__cosl.c
12// https://git.musl-libc.org/cgit/musl/tree/src/math/__tanl.c12// https://git.musl-libc.org/cgit/musl/tree/src/math/__tanl.c
1313
14/// pi divided by 4
15pub const pi_4 = 0.78539816339744830962;
16
14/// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.78539816417/// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
15/// Input x is assumed to be bounded by ~pi/4 in magnitude.18/// Input x is assumed to be bounded by ~pi/4 in magnitude.
16/// Input y is the tail of x.19/// Input y is the tail of x.