authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-08 13:06:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-08 13:06:21-07:00
logcd019ee502d6792c1615b0fab10827db419beab4
tree4141ab72f3721b7625d888b202a774ba58d2a5e0
parent6fde2fcd519cacdc44871fc1035b05afee072f44

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.

20 files changed, 235 insertions(+), 23 deletions(-)

lib/compiler_rt.zig+26-23
......@@ -724,25 +724,25 @@ comptime {
724724 @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
725725 }
726726
727 mathExport("ceil", @import("./compiler_rt/ceil.zig"), false);
728 mathExport("cos", @import("./compiler_rt/cos.zig"), true);
729 mathExport("exp", @import("./compiler_rt/exp.zig"), true);
730 mathExport("exp2", @import("./compiler_rt/exp2.zig"), true);
731 mathExport("fabs", @import("./compiler_rt/fabs.zig"), true);
732 mathExport("floor", @import("./compiler_rt/floor.zig"), false);
733 mathExport("fma", @import("./compiler_rt/fma.zig"), true);
734 mathExport("fmax", @import("./compiler_rt/fmax.zig"), true);
735 mathExport("fmin", @import("./compiler_rt/fmin.zig"), true);
736 mathExport("fmod", @import("./compiler_rt/fmod.zig"), true);
737 mathExport("log", @import("./compiler_rt/log.zig"), true);
738 mathExport("log10", @import("./compiler_rt/log10.zig"), false);
739 mathExport("log2", @import("./compiler_rt/log2.zig"), true);
740 mathExport("round", @import("./compiler_rt/round.zig"), true);
741 mathExport("sin", @import("./compiler_rt/sin.zig"), true);
742 mathExport("sincos", @import("./compiler_rt/sincos.zig"), true);
743 mathExport("sqrt", @import("./compiler_rt/sqrt.zig"), true);
744 mathExport("tan", @import("./compiler_rt/tan.zig"), true);
745 mathExport("trunc", @import("./compiler_rt/trunc.zig"), true);
727 mathExport("ceil", @import("./compiler_rt/ceil.zig"));
728 mathExport("cos", @import("./compiler_rt/cos.zig"));
729 mathExport("exp", @import("./compiler_rt/exp.zig"));
730 mathExport("exp2", @import("./compiler_rt/exp2.zig"));
731 mathExport("fabs", @import("./compiler_rt/fabs.zig"));
732 mathExport("floor", @import("./compiler_rt/floor.zig"));
733 mathExport("fma", @import("./compiler_rt/fma.zig"));
734 mathExport("fmax", @import("./compiler_rt/fmax.zig"));
735 mathExport("fmin", @import("./compiler_rt/fmin.zig"));
736 mathExport("fmod", @import("./compiler_rt/fmod.zig"));
737 mathExport("log", @import("./compiler_rt/log.zig"));
738 mathExport("log10", @import("./compiler_rt/log10.zig"));
739 mathExport("log2", @import("./compiler_rt/log2.zig"));
740 mathExport("round", @import("./compiler_rt/round.zig"));
741 mathExport("sin", @import("./compiler_rt/sin.zig"));
742 mathExport("sincos", @import("./compiler_rt/sincos.zig"));
743 mathExport("sqrt", @import("./compiler_rt/sqrt.zig"));
744 mathExport("tan", @import("./compiler_rt/tan.zig"));
745 mathExport("trunc", @import("./compiler_rt/trunc.zig"));
746746
747747 if (arch.isSPARC()) {
748748 // SPARC systems use a different naming scheme
......@@ -825,7 +825,7 @@ comptime {
825825 }
826826}
827827
828inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_has_it: bool) void {
828inline fn mathExport(double_name: []const u8, comptime import: type) void {
829829 const half_name = "__" ++ double_name ++ "h";
830830 const half_fn = @field(import, half_name);
831831 const float_name = double_name ++ "f";
......@@ -853,9 +853,12 @@ inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_ha
853853 .{ f128, quad_fn },
854854 };
855855
856 // Weak aliases don't work on Windows, so we avoid exporting the `l` alias
857 // on this platform for functions we know will collide.
858 if (builtin.os.tag != .windows or !builtin.link_libc or !win_libc_has_it) {
856 if (builtin.os.tag == .windows) {
857 // Weak aliases don't work on Windows, so we have to provide the 'l' variants
858 // as additional function definitions that jump to the real definition.
859 const long_double_fn = @field(import, long_double_name);
860 @export(long_double_fn, .{ .name = long_double_name, .linkage = linkage });
861 } else {
859862 inline for (pairs) |pair| {
860863 const F = pair[0];
861864 const func = pair[1];
lib/compiler_rt/ceil.zig+11
......@@ -111,6 +111,17 @@ pub fn ceilq(x: f128) callconv(.C) f128 {
111111 }
112112}
113113
114pub fn ceill(x: c_longdouble) callconv(.C) c_longdouble {
115 switch (@typeInfo(c_longdouble).Float.bits) {
116 16 => return __ceilh(x),
117 32 => return ceilf(x),
118 64 => return ceil(x),
119 80 => return __ceilx(x),
120 128 => return ceilq(x),
121 else => @compileError("unreachable"),
122 }
123}
124
114125test "ceil32" {
115126 try expect(ceilf(1.3) == 2.0);
116127 try expect(ceilf(-1.3) == -1.0);
lib/compiler_rt/cos.zig+11
......@@ -107,6 +107,17 @@ pub fn cosq(a: f128) callconv(.C) f128 {
107107 return cos(@floatCast(f64, a));
108108}
109109
110pub fn cosl(x: c_longdouble) callconv(.C) c_longdouble {
111 switch (@typeInfo(c_longdouble).Float.bits) {
112 16 => return __cosh(x),
113 32 => return cosf(x),
114 64 => return cos(x),
115 80 => return __cosx(x),
116 128 => return cosq(x),
117 else => @compileError("unreachable"),
118 }
119}
120
110121test "cos32" {
111122 const epsilon = 0.00001;
112123
lib/compiler_rt/exp.zig+11
......@@ -182,6 +182,17 @@ pub fn expq(a: f128) callconv(.C) f128 {
182182 return exp(@floatCast(f64, a));
183183}
184184
185pub fn expl(x: c_longdouble) callconv(.C) c_longdouble {
186 switch (@typeInfo(c_longdouble).Float.bits) {
187 16 => return __exph(x),
188 32 => return expf(x),
189 64 => return exp(x),
190 80 => return __expx(x),
191 128 => return expq(x),
192 else => @compileError("unreachable"),
193 }
194}
195
185196test "exp32" {
186197 const epsilon = 0.000001;
187198
lib/compiler_rt/exp2.zig+11
......@@ -149,6 +149,17 @@ pub fn exp2q(x: f128) callconv(.C) f128 {
149149 return exp2(@floatCast(f64, x));
150150}
151151
152pub fn exp2l(x: c_longdouble) callconv(.C) c_longdouble {
153 switch (@typeInfo(c_longdouble).Float.bits) {
154 16 => return __exp2h(x),
155 32 => return exp2f(x),
156 64 => return exp2(x),
157 80 => return __exp2x(x),
158 128 => return exp2q(x),
159 else => @compileError("unreachable"),
160 }
161}
162
152163const exp2ft = [_]f64{
153164 0x1.6a09e667f3bcdp-1,
154165 0x1.7a11473eb0187p-1,
lib/compiler_rt/fabs.zig+11
......@@ -20,6 +20,17 @@ pub fn fabsq(a: f128) callconv(.C) f128 {
2020 return generic_fabs(a);
2121}
2222
23pub fn fabsl(x: c_longdouble) callconv(.C) c_longdouble {
24 switch (@typeInfo(c_longdouble).Float.bits) {
25 16 => return __fabsh(x),
26 32 => return fabsf(x),
27 64 => return fabs(x),
28 80 => return __fabsx(x),
29 128 => return fabsq(x),
30 else => @compileError("unreachable"),
31 }
32}
33
2334inline fn generic_fabs(x: anytype) @TypeOf(x) {
2435 const T = @TypeOf(x);
2536 const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
lib/compiler_rt/floor.zig+11
......@@ -141,6 +141,17 @@ pub fn floorq(x: f128) callconv(.C) f128 {
141141 }
142142}
143143
144pub fn floorl(x: c_longdouble) callconv(.C) c_longdouble {
145 switch (@typeInfo(c_longdouble).Float.bits) {
146 16 => return __floorh(x),
147 32 => return floorf(x),
148 64 => return floor(x),
149 80 => return __floorx(x),
150 128 => return floorq(x),
151 else => @compileError("unreachable"),
152 }
153}
154
144155test "floor16" {
145156 try expect(__floorh(1.3) == 1.0);
146157 try expect(__floorh(-1.3) == -2.0);
lib/compiler_rt/fma.zig+11
......@@ -135,6 +135,17 @@ pub fn fmaq(x: f128, y: f128, z: f128) callconv(.C) f128 {
135135 }
136136}
137137
138pub fn fmal(x: c_longdouble, y: c_longdouble, z: c_longdouble) callconv(.C) c_longdouble {
139 switch (@typeInfo(c_longdouble).Float.bits) {
140 16 => return __fmah(x, y, z),
141 32 => return fmaf(x, y, z),
142 64 => return fma(x, y, z),
143 80 => return __fmax(x, y, z),
144 128 => return fmaq(x, y, z),
145 else => @compileError("unreachable"),
146 }
147}
148
138149const dd = struct {
139150 hi: f64,
140151 lo: f64,
lib/compiler_rt/fmax.zig+11
......@@ -21,6 +21,17 @@ pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 {
2121 return generic_fmax(f128, x, y);
2222}
2323
24pub fn fmaxl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble {
25 switch (@typeInfo(c_longdouble).Float.bits) {
26 16 => return __fmaxh(x, y),
27 32 => return fmaxf(x, y),
28 64 => return fmax(x, y),
29 80 => return __fmaxx(x, y),
30 128 => return fmaxq(x, y),
31 else => @compileError("unreachable"),
32 }
33}
34
2435inline fn generic_fmax(comptime T: type, x: T, y: T) T {
2536 if (math.isNan(x))
2637 return y;
lib/compiler_rt/fmin.zig+11
......@@ -21,6 +21,17 @@ pub fn fminq(x: f128, y: f128) callconv(.C) f128 {
2121 return generic_fmin(f128, x, y);
2222}
2323
24pub fn fminl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble {
25 switch (@typeInfo(c_longdouble).Float.bits) {
26 16 => return __fminh(x, y),
27 32 => return fminf(x, y),
28 64 => return fmin(x, y),
29 80 => return __fminx(x, y),
30 128 => return fminq(x, y),
31 else => @compileError("unreachable"),
32 }
33}
34
2435inline fn generic_fmin(comptime T: type, x: T, y: T) T {
2536 if (math.isNan(x))
2637 return y;
lib/compiler_rt/fmod.zig+11
......@@ -237,6 +237,17 @@ pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {
237237 return amod;
238238}
239239
240pub fn fmodl(a: c_longdouble, b: c_longdouble) callconv(.C) c_longdouble {
241 switch (@typeInfo(c_longdouble).Float.bits) {
242 16 => return __fmodh(a, b),
243 32 => return fmodf(a, b),
244 64 => return fmod(a, b),
245 80 => return __fmodx(a, b),
246 128 => return fmodq(a, b),
247 else => @compileError("unreachable"),
248 }
249}
250
240251inline fn generic_fmod(comptime T: type, x: T, y: T) T {
241252 @setRuntimeSafety(false);
242253
lib/compiler_rt/log.zig+11
......@@ -131,6 +131,17 @@ pub fn logq(a: f128) callconv(.C) f128 {
131131 return log(@floatCast(f64, a));
132132}
133133
134pub fn logl(x: c_longdouble) callconv(.C) c_longdouble {
135 switch (@typeInfo(c_longdouble).Float.bits) {
136 16 => return __logh(x),
137 32 => return logf(x),
138 64 => return log(x),
139 80 => return __logx(x),
140 128 => return logq(x),
141 else => @compileError("unreachable"),
142 }
143}
144
134145test "ln32" {
135146 const epsilon = 0.000001;
136147
lib/compiler_rt/log10.zig+11
......@@ -159,6 +159,17 @@ pub fn log10q(a: f128) callconv(.C) f128 {
159159 return log10(@floatCast(f64, a));
160160}
161161
162pub fn log10l(x: c_longdouble) callconv(.C) c_longdouble {
163 switch (@typeInfo(c_longdouble).Float.bits) {
164 16 => return __log10h(x),
165 32 => return log10f(x),
166 64 => return log10(x),
167 80 => return __log10x(x),
168 128 => return log10q(x),
169 else => @compileError("unreachable"),
170 }
171}
172
162173test "log10_32" {
163174 const epsilon = 0.000001;
164175
lib/compiler_rt/log2.zig+11
......@@ -150,6 +150,17 @@ pub fn log2q(a: f128) callconv(.C) f128 {
150150 return math.log2(a);
151151}
152152
153pub fn log2l(x: c_longdouble) callconv(.C) c_longdouble {
154 switch (@typeInfo(c_longdouble).Float.bits) {
155 16 => return __log2h(x),
156 32 => return log2f(x),
157 64 => return log2(x),
158 80 => return __log2x(x),
159 128 => return log2q(x),
160 else => @compileError("unreachable"),
161 }
162}
163
153164test "log2_32" {
154165 const epsilon = 0.000001;
155166
lib/compiler_rt/round.zig+11
......@@ -123,6 +123,17 @@ pub fn roundq(x_: f128) callconv(.C) f128 {
123123 }
124124}
125125
126pub fn roundl(x: c_longdouble) callconv(.C) c_longdouble {
127 switch (@typeInfo(c_longdouble).Float.bits) {
128 16 => return __roundh(x),
129 32 => return roundf(x),
130 64 => return round(x),
131 80 => return __roundx(x),
132 128 => return roundq(x),
133 else => @compileError("unreachable"),
134 }
135}
136
126137test "round32" {
127138 try expect(roundf(1.3) == 1.0);
128139 try expect(roundf(-1.3) == -1.0);
lib/compiler_rt/sin.zig+11
......@@ -111,6 +111,17 @@ pub fn sinq(x: f128) callconv(.C) f128 {
111111 return sin(@floatCast(f64, x));
112112}
113113
114pub fn sinl(x: c_longdouble) callconv(.C) c_longdouble {
115 switch (@typeInfo(c_longdouble).Float.bits) {
116 16 => return __sinh(x),
117 32 => return sinf(x),
118 64 => return sin(x),
119 80 => return __sinx(x),
120 128 => return sinq(x),
121 else => @compileError("unreachable"),
122 }
123}
124
114125test "sin32" {
115126 const epsilon = 0.00001;
116127
lib/compiler_rt/sincos.zig+11
......@@ -181,6 +181,17 @@ pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.C) void {
181181 r_cos.* = small_cos;
182182}
183183
184pub fn sincosl(x: c_longdouble, r_sin: *c_longdouble, r_cos: *c_longdouble) callconv(.C) void {
185 switch (@typeInfo(c_longdouble).Float.bits) {
186 16 => return __sincosh(x, r_sin, r_cos),
187 32 => return sincosf(x, r_sin, r_cos),
188 64 => return sincos(x, r_sin, r_cos),
189 80 => return __sincosx(x, r_sin, r_cos),
190 128 => return sincosq(x, r_sin, r_cos),
191 else => @compileError("unreachable"),
192 }
193}
194
184195const rem_pio2_generic = @compileError("TODO");
185196
186197/// Ported from musl sincosl.c. Needs the following dependencies to be complete:
lib/compiler_rt/sqrt.zig+11
......@@ -225,6 +225,17 @@ pub fn sqrtq(x: f128) callconv(.C) f128 {
225225 return sqrt(@floatCast(f64, x));
226226}
227227
228pub fn sqrtl(x: c_longdouble) callconv(.C) c_longdouble {
229 switch (@typeInfo(c_longdouble).Float.bits) {
230 16 => return __sqrth(x),
231 32 => return sqrtf(x),
232 64 => return sqrt(x),
233 80 => return __sqrtx(x),
234 128 => return sqrtq(x),
235 else => @compileError("unreachable"),
236 }
237}
238
228239test "sqrtf" {
229240 const V = [_]f32{
230241 0.0,
lib/compiler_rt/tan.zig+11
......@@ -96,6 +96,17 @@ pub fn tanq(x: f128) callconv(.C) f128 {
9696 return tan(@floatCast(f64, x));
9797}
9898
99pub fn tanl(x: c_longdouble) callconv(.C) c_longdouble {
100 switch (@typeInfo(c_longdouble).Float.bits) {
101 16 => return __tanh(x),
102 32 => return tanf(x),
103 64 => return tan(x),
104 80 => return __tanx(x),
105 128 => return tanq(x),
106 else => @compileError("unreachable"),
107 }
108}
109
99110test "tan" {
100111 try expect(tan(@as(f32, 0.0)) == tanf(0.0));
101112 try expect(tan(@as(f64, 0.0)) == tan(0.0));
lib/compiler_rt/trunc.zig+11
......@@ -81,6 +81,17 @@ pub fn truncq(x: f128) callconv(.C) f128 {
8181 }
8282}
8383
84pub fn truncl(x: c_longdouble) callconv(.C) c_longdouble {
85 switch (@typeInfo(c_longdouble).Float.bits) {
86 16 => return __trunch(x),
87 32 => return truncf(x),
88 64 => return trunc(x),
89 80 => return __truncx(x),
90 128 => return truncq(x),
91 else => @compileError("unreachable"),
92 }
93}
94
8495test "trunc32" {
8596 try expect(truncf(1.3) == 1.0);
8697 try expect(truncf(-1.3) == -1.0);