From cd019ee502d6792c1615b0fab10827db419beab4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 8 May 2022 13:06:21 -0700 Subject: [PATCH] compiler_rt: avoid weak aliases on Windows When exporting math functions for Windows, we provide weak exports of 'l' variants rather than weak aliases. We still use aliases on other operating systems so that the 'l' variants have one less jump instruction in this case. --- lib/compiler_rt.zig | 49 ++++++++++++++++++++------------------ lib/compiler_rt/ceil.zig | 11 +++++++++ lib/compiler_rt/cos.zig | 11 +++++++++ lib/compiler_rt/exp.zig | 11 +++++++++ lib/compiler_rt/exp2.zig | 11 +++++++++ lib/compiler_rt/fabs.zig | 11 +++++++++ lib/compiler_rt/floor.zig | 11 +++++++++ lib/compiler_rt/fma.zig | 11 +++++++++ lib/compiler_rt/fmax.zig | 11 +++++++++ lib/compiler_rt/fmin.zig | 11 +++++++++ lib/compiler_rt/fmod.zig | 11 +++++++++ lib/compiler_rt/log.zig | 11 +++++++++ lib/compiler_rt/log10.zig | 11 +++++++++ lib/compiler_rt/log2.zig | 11 +++++++++ lib/compiler_rt/round.zig | 11 +++++++++ lib/compiler_rt/sin.zig | 11 +++++++++ lib/compiler_rt/sincos.zig | 11 +++++++++ lib/compiler_rt/sqrt.zig | 11 +++++++++ lib/compiler_rt/tan.zig | 11 +++++++++ lib/compiler_rt/trunc.zig | 11 +++++++++ 20 files changed, 235 insertions(+), 23 deletions(-) diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 2ed0bdc5205eb7148142dc2163bb86b80582f6c5..fdf594070246a85bb1838c239c912c3c0a788246 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -724,25 +724,25 @@ comptime { @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage }); } - mathExport("ceil", @import("./compiler_rt/ceil.zig"), false); - mathExport("cos", @import("./compiler_rt/cos.zig"), true); - mathExport("exp", @import("./compiler_rt/exp.zig"), true); - mathExport("exp2", @import("./compiler_rt/exp2.zig"), true); - mathExport("fabs", @import("./compiler_rt/fabs.zig"), true); - mathExport("floor", @import("./compiler_rt/floor.zig"), false); - mathExport("fma", @import("./compiler_rt/fma.zig"), true); - mathExport("fmax", @import("./compiler_rt/fmax.zig"), true); - mathExport("fmin", @import("./compiler_rt/fmin.zig"), true); - mathExport("fmod", @import("./compiler_rt/fmod.zig"), true); - mathExport("log", @import("./compiler_rt/log.zig"), true); - mathExport("log10", @import("./compiler_rt/log10.zig"), false); - mathExport("log2", @import("./compiler_rt/log2.zig"), true); - mathExport("round", @import("./compiler_rt/round.zig"), true); - mathExport("sin", @import("./compiler_rt/sin.zig"), true); - mathExport("sincos", @import("./compiler_rt/sincos.zig"), true); - mathExport("sqrt", @import("./compiler_rt/sqrt.zig"), true); - mathExport("tan", @import("./compiler_rt/tan.zig"), true); - mathExport("trunc", @import("./compiler_rt/trunc.zig"), true); + mathExport("ceil", @import("./compiler_rt/ceil.zig")); + mathExport("cos", @import("./compiler_rt/cos.zig")); + mathExport("exp", @import("./compiler_rt/exp.zig")); + mathExport("exp2", @import("./compiler_rt/exp2.zig")); + mathExport("fabs", @import("./compiler_rt/fabs.zig")); + mathExport("floor", @import("./compiler_rt/floor.zig")); + mathExport("fma", @import("./compiler_rt/fma.zig")); + mathExport("fmax", @import("./compiler_rt/fmax.zig")); + mathExport("fmin", @import("./compiler_rt/fmin.zig")); + mathExport("fmod", @import("./compiler_rt/fmod.zig")); + mathExport("log", @import("./compiler_rt/log.zig")); + mathExport("log10", @import("./compiler_rt/log10.zig")); + mathExport("log2", @import("./compiler_rt/log2.zig")); + mathExport("round", @import("./compiler_rt/round.zig")); + mathExport("sin", @import("./compiler_rt/sin.zig")); + mathExport("sincos", @import("./compiler_rt/sincos.zig")); + mathExport("sqrt", @import("./compiler_rt/sqrt.zig")); + mathExport("tan", @import("./compiler_rt/tan.zig")); + mathExport("trunc", @import("./compiler_rt/trunc.zig")); if (arch.isSPARC()) { // SPARC systems use a different naming scheme @@ -825,7 +825,7 @@ comptime { } } -inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_has_it: bool) void { +inline fn mathExport(double_name: []const u8, comptime import: type) void { const half_name = "__" ++ double_name ++ "h"; const half_fn = @field(import, half_name); const float_name = double_name ++ "f"; @@ -853,9 +853,12 @@ inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_ha .{ f128, quad_fn }, }; - // Weak aliases don't work on Windows, so we avoid exporting the `l` alias - // on this platform for functions we know will collide. - if (builtin.os.tag != .windows or !builtin.link_libc or !win_libc_has_it) { + if (builtin.os.tag == .windows) { + // Weak aliases don't work on Windows, so we have to provide the 'l' variants + // as additional function definitions that jump to the real definition. + const long_double_fn = @field(import, long_double_name); + @export(long_double_fn, .{ .name = long_double_name, .linkage = linkage }); + } else { inline for (pairs) |pair| { const F = pair[0]; const func = pair[1]; diff --git a/lib/compiler_rt/ceil.zig b/lib/compiler_rt/ceil.zig index c7087a2c3a7e200f70ede4bcabfdd2e9853c2b85..06020ea8f8b3c2cffd817058b56b7fded2aad059 100644 --- a/lib/compiler_rt/ceil.zig +++ b/lib/compiler_rt/ceil.zig @@ -111,6 +111,17 @@ pub fn ceilq(x: f128) callconv(.C) f128 { } } +pub fn ceill(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __ceilh(x), + 32 => return ceilf(x), + 64 => return ceil(x), + 80 => return __ceilx(x), + 128 => return ceilq(x), + else => @compileError("unreachable"), + } +} + test "ceil32" { try expect(ceilf(1.3) == 2.0); try expect(ceilf(-1.3) == -1.0); diff --git a/lib/compiler_rt/cos.zig b/lib/compiler_rt/cos.zig index 957e5f9c91be8c4d670c5b6443092a9b8cdb4282..e01f458243b580ede5d0e8ff2dbed23c0515d6f2 100644 --- a/lib/compiler_rt/cos.zig +++ b/lib/compiler_rt/cos.zig @@ -107,6 +107,17 @@ pub fn cosq(a: f128) callconv(.C) f128 { return cos(@floatCast(f64, a)); } +pub fn cosl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __cosh(x), + 32 => return cosf(x), + 64 => return cos(x), + 80 => return __cosx(x), + 128 => return cosq(x), + else => @compileError("unreachable"), + } +} + test "cos32" { const epsilon = 0.00001; diff --git a/lib/compiler_rt/exp.zig b/lib/compiler_rt/exp.zig index 0f129dfd4cf0cc88c5fc53bc10dacbfbab85675d..a2c5d0e5502fbb7eb9cba81a6f96136efc5bfc8b 100644 --- a/lib/compiler_rt/exp.zig +++ b/lib/compiler_rt/exp.zig @@ -182,6 +182,17 @@ pub fn expq(a: f128) callconv(.C) f128 { return exp(@floatCast(f64, a)); } +pub fn expl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __exph(x), + 32 => return expf(x), + 64 => return exp(x), + 80 => return __expx(x), + 128 => return expq(x), + else => @compileError("unreachable"), + } +} + test "exp32" { const epsilon = 0.000001; diff --git a/lib/compiler_rt/exp2.zig b/lib/compiler_rt/exp2.zig index 53432a831d1326ae042082ce55acfb6d703c14c2..cbcb53c99f227fa80b4113cd27aa390ac6e4985d 100644 --- a/lib/compiler_rt/exp2.zig +++ b/lib/compiler_rt/exp2.zig @@ -149,6 +149,17 @@ pub fn exp2q(x: f128) callconv(.C) f128 { return exp2(@floatCast(f64, x)); } +pub fn exp2l(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __exp2h(x), + 32 => return exp2f(x), + 64 => return exp2(x), + 80 => return __exp2x(x), + 128 => return exp2q(x), + else => @compileError("unreachable"), + } +} + const exp2ft = [_]f64{ 0x1.6a09e667f3bcdp-1, 0x1.7a11473eb0187p-1, diff --git a/lib/compiler_rt/fabs.zig b/lib/compiler_rt/fabs.zig index fbef81fc9a4d18bf7b04bbdb8b30545930a7dcdd..396fdd46b7334f95ac9e6fe78b141bb29506a55d 100644 --- a/lib/compiler_rt/fabs.zig +++ b/lib/compiler_rt/fabs.zig @@ -20,6 +20,17 @@ pub fn fabsq(a: f128) callconv(.C) f128 { return generic_fabs(a); } +pub fn fabsl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __fabsh(x), + 32 => return fabsf(x), + 64 => return fabs(x), + 80 => return __fabsx(x), + 128 => return fabsq(x), + else => @compileError("unreachable"), + } +} + inline fn generic_fabs(x: anytype) @TypeOf(x) { const T = @TypeOf(x); const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); diff --git a/lib/compiler_rt/floor.zig b/lib/compiler_rt/floor.zig index f6df164b58cd8d1470cc830f934b864716ac5c10..783898fca7df7eec29c2af99d28a93ba0db8c8d6 100644 --- a/lib/compiler_rt/floor.zig +++ b/lib/compiler_rt/floor.zig @@ -141,6 +141,17 @@ pub fn floorq(x: f128) callconv(.C) f128 { } } +pub fn floorl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __floorh(x), + 32 => return floorf(x), + 64 => return floor(x), + 80 => return __floorx(x), + 128 => return floorq(x), + else => @compileError("unreachable"), + } +} + test "floor16" { try expect(__floorh(1.3) == 1.0); try expect(__floorh(-1.3) == -2.0); diff --git a/lib/compiler_rt/fma.zig b/lib/compiler_rt/fma.zig index 4c603bf09570ce5c89406ccfbad6f3b261274c0d..7a39a4c9a00e28b59ecb9f8a50b8d713950f674c 100644 --- a/lib/compiler_rt/fma.zig +++ b/lib/compiler_rt/fma.zig @@ -135,6 +135,17 @@ pub fn fmaq(x: f128, y: f128, z: f128) callconv(.C) f128 { } } +pub fn fmal(x: c_longdouble, y: c_longdouble, z: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __fmah(x, y, z), + 32 => return fmaf(x, y, z), + 64 => return fma(x, y, z), + 80 => return __fmax(x, y, z), + 128 => return fmaq(x, y, z), + else => @compileError("unreachable"), + } +} + const dd = struct { hi: f64, lo: f64, diff --git a/lib/compiler_rt/fmax.zig b/lib/compiler_rt/fmax.zig index a5bd68cd7428cd175b747a21761e62fc8e69f60b..defc935afcfc2a39bf935ab8c86220f9e8b5984f 100644 --- a/lib/compiler_rt/fmax.zig +++ b/lib/compiler_rt/fmax.zig @@ -21,6 +21,17 @@ pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 { return generic_fmax(f128, x, y); } +pub fn fmaxl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __fmaxh(x, y), + 32 => return fmaxf(x, y), + 64 => return fmax(x, y), + 80 => return __fmaxx(x, y), + 128 => return fmaxq(x, y), + else => @compileError("unreachable"), + } +} + inline fn generic_fmax(comptime T: type, x: T, y: T) T { if (math.isNan(x)) return y; diff --git a/lib/compiler_rt/fmin.zig b/lib/compiler_rt/fmin.zig index cc4dbf082bc7c17d100d4f7ee0d4830c3b8dce9d..e93300bd4b527d0c3437285276fa897c122d9d1d 100644 --- a/lib/compiler_rt/fmin.zig +++ b/lib/compiler_rt/fmin.zig @@ -21,6 +21,17 @@ pub fn fminq(x: f128, y: f128) callconv(.C) f128 { return generic_fmin(f128, x, y); } +pub fn fminl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __fminh(x, y), + 32 => return fminf(x, y), + 64 => return fmin(x, y), + 80 => return __fminx(x, y), + 128 => return fminq(x, y), + else => @compileError("unreachable"), + } +} + inline fn generic_fmin(comptime T: type, x: T, y: T) T { if (math.isNan(x)) return y; diff --git a/lib/compiler_rt/fmod.zig b/lib/compiler_rt/fmod.zig index 28e0df3d6b4301459226b8091e8180e17ed9b666..5d413ca37d8333844267b83bb9d73982d6212fc1 100644 --- a/lib/compiler_rt/fmod.zig +++ b/lib/compiler_rt/fmod.zig @@ -237,6 +237,17 @@ pub fn fmodq(a: f128, b: f128) callconv(.C) f128 { return amod; } +pub fn fmodl(a: c_longdouble, b: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __fmodh(a, b), + 32 => return fmodf(a, b), + 64 => return fmod(a, b), + 80 => return __fmodx(a, b), + 128 => return fmodq(a, b), + else => @compileError("unreachable"), + } +} + inline fn generic_fmod(comptime T: type, x: T, y: T) T { @setRuntimeSafety(false); diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig index 8b09baac2ef6a1ea39455ad5d1c98c9c1b310fe0..6e705dae609bec8d55cf9ea97ce1bcef7a2899d3 100644 --- a/lib/compiler_rt/log.zig +++ b/lib/compiler_rt/log.zig @@ -131,6 +131,17 @@ pub fn logq(a: f128) callconv(.C) f128 { return log(@floatCast(f64, a)); } +pub fn logl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __logh(x), + 32 => return logf(x), + 64 => return log(x), + 80 => return __logx(x), + 128 => return logq(x), + else => @compileError("unreachable"), + } +} + test "ln32" { const epsilon = 0.000001; diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig index ce06d8c6493bf19eaeb5eb8a9e2bef2f865884fe..47499d27398525295351ed9211be56acbe6610c7 100644 --- a/lib/compiler_rt/log10.zig +++ b/lib/compiler_rt/log10.zig @@ -159,6 +159,17 @@ pub fn log10q(a: f128) callconv(.C) f128 { return log10(@floatCast(f64, a)); } +pub fn log10l(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __log10h(x), + 32 => return log10f(x), + 64 => return log10(x), + 80 => return __log10x(x), + 128 => return log10q(x), + else => @compileError("unreachable"), + } +} + test "log10_32" { const epsilon = 0.000001; diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig index 2c2d620c3dafce36bd03d7afc2b907f1b5d73b49..53f35c9a80c4e82aadf9f8232d3d00b384de73e1 100644 --- a/lib/compiler_rt/log2.zig +++ b/lib/compiler_rt/log2.zig @@ -150,6 +150,17 @@ pub fn log2q(a: f128) callconv(.C) f128 { return math.log2(a); } +pub fn log2l(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __log2h(x), + 32 => return log2f(x), + 64 => return log2(x), + 80 => return __log2x(x), + 128 => return log2q(x), + else => @compileError("unreachable"), + } +} + test "log2_32" { const epsilon = 0.000001; diff --git a/lib/compiler_rt/round.zig b/lib/compiler_rt/round.zig index 99201efcf89a9e6025130d75b0659917aea8d5ab..4f3266e00ca575d11646afc65f112baf251c3cff 100644 --- a/lib/compiler_rt/round.zig +++ b/lib/compiler_rt/round.zig @@ -123,6 +123,17 @@ pub fn roundq(x_: f128) callconv(.C) f128 { } } +pub fn roundl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __roundh(x), + 32 => return roundf(x), + 64 => return round(x), + 80 => return __roundx(x), + 128 => return roundq(x), + else => @compileError("unreachable"), + } +} + test "round32" { try expect(roundf(1.3) == 1.0); try expect(roundf(-1.3) == -1.0); diff --git a/lib/compiler_rt/sin.zig b/lib/compiler_rt/sin.zig index 3d5572a59f82e76256b35312238c081414b73300..20259bc309023ef987e581fd443473c4739c206f 100644 --- a/lib/compiler_rt/sin.zig +++ b/lib/compiler_rt/sin.zig @@ -111,6 +111,17 @@ pub fn sinq(x: f128) callconv(.C) f128 { return sin(@floatCast(f64, x)); } +pub fn sinl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __sinh(x), + 32 => return sinf(x), + 64 => return sin(x), + 80 => return __sinx(x), + 128 => return sinq(x), + else => @compileError("unreachable"), + } +} + test "sin32" { const epsilon = 0.00001; diff --git a/lib/compiler_rt/sincos.zig b/lib/compiler_rt/sincos.zig index 31ebd0d1d0a88b81d8759eddfaa67c68ff578557..8bc5b83ee5aa4a1f3cc960073c5051ca31673905 100644 --- a/lib/compiler_rt/sincos.zig +++ b/lib/compiler_rt/sincos.zig @@ -181,6 +181,17 @@ pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.C) void { r_cos.* = small_cos; } +pub fn sincosl(x: c_longdouble, r_sin: *c_longdouble, r_cos: *c_longdouble) callconv(.C) void { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __sincosh(x, r_sin, r_cos), + 32 => return sincosf(x, r_sin, r_cos), + 64 => return sincos(x, r_sin, r_cos), + 80 => return __sincosx(x, r_sin, r_cos), + 128 => return sincosq(x, r_sin, r_cos), + else => @compileError("unreachable"), + } +} + const rem_pio2_generic = @compileError("TODO"); /// Ported from musl sincosl.c. Needs the following dependencies to be complete: diff --git a/lib/compiler_rt/sqrt.zig b/lib/compiler_rt/sqrt.zig index ba07beb86efaa008c7c695eafbaa077a7b8d6601..8d43949f9920e678389d5620fb95dcf11f504c83 100644 --- a/lib/compiler_rt/sqrt.zig +++ b/lib/compiler_rt/sqrt.zig @@ -225,6 +225,17 @@ pub fn sqrtq(x: f128) callconv(.C) f128 { return sqrt(@floatCast(f64, x)); } +pub fn sqrtl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __sqrth(x), + 32 => return sqrtf(x), + 64 => return sqrt(x), + 80 => return __sqrtx(x), + 128 => return sqrtq(x), + else => @compileError("unreachable"), + } +} + test "sqrtf" { const V = [_]f32{ 0.0, diff --git a/lib/compiler_rt/tan.zig b/lib/compiler_rt/tan.zig index d99f00b99e87b9832f0bba4252e484d2cedac6d3..d37022d91804d26b0da12b5a079ecd6fd68e0897 100644 --- a/lib/compiler_rt/tan.zig +++ b/lib/compiler_rt/tan.zig @@ -96,6 +96,17 @@ pub fn tanq(x: f128) callconv(.C) f128 { return tan(@floatCast(f64, x)); } +pub fn tanl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __tanh(x), + 32 => return tanf(x), + 64 => return tan(x), + 80 => return __tanx(x), + 128 => return tanq(x), + else => @compileError("unreachable"), + } +} + test "tan" { try expect(tan(@as(f32, 0.0)) == tanf(0.0)); try expect(tan(@as(f64, 0.0)) == tan(0.0)); diff --git a/lib/compiler_rt/trunc.zig b/lib/compiler_rt/trunc.zig index 5406f9a02d4dafee31eb224aa0bb070d5a9f45dd..d00df60d99d8c7f16a2d99604d80c1de39b0d7e8 100644 --- a/lib/compiler_rt/trunc.zig +++ b/lib/compiler_rt/trunc.zig @@ -81,6 +81,17 @@ pub fn truncq(x: f128) callconv(.C) f128 { } } +pub fn truncl(x: c_longdouble) callconv(.C) c_longdouble { + switch (@typeInfo(c_longdouble).Float.bits) { + 16 => return __trunch(x), + 32 => return truncf(x), + 64 => return trunc(x), + 80 => return __truncx(x), + 128 => return truncq(x), + else => @compileError("unreachable"), + } +} + test "trunc32" { try expect(truncf(1.3) == 1.0); try expect(truncf(-1.3) == -1.0); -- 2.54.0