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 {...@@ -724,25 +724,25 @@ comptime {
724 @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });724 @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
725 }725 }
726726
727 mathExport("ceil", @import("./compiler_rt/ceil.zig"), false);727 mathExport("ceil", @import("./compiler_rt/ceil.zig"));
728 mathExport("cos", @import("./compiler_rt/cos.zig"), true);728 mathExport("cos", @import("./compiler_rt/cos.zig"));
729 mathExport("exp", @import("./compiler_rt/exp.zig"), true);729 mathExport("exp", @import("./compiler_rt/exp.zig"));
730 mathExport("exp2", @import("./compiler_rt/exp2.zig"), true);730 mathExport("exp2", @import("./compiler_rt/exp2.zig"));
731 mathExport("fabs", @import("./compiler_rt/fabs.zig"), true);731 mathExport("fabs", @import("./compiler_rt/fabs.zig"));
732 mathExport("floor", @import("./compiler_rt/floor.zig"), false);732 mathExport("floor", @import("./compiler_rt/floor.zig"));
733 mathExport("fma", @import("./compiler_rt/fma.zig"), true);733 mathExport("fma", @import("./compiler_rt/fma.zig"));
734 mathExport("fmax", @import("./compiler_rt/fmax.zig"), true);734 mathExport("fmax", @import("./compiler_rt/fmax.zig"));
735 mathExport("fmin", @import("./compiler_rt/fmin.zig"), true);735 mathExport("fmin", @import("./compiler_rt/fmin.zig"));
736 mathExport("fmod", @import("./compiler_rt/fmod.zig"), true);736 mathExport("fmod", @import("./compiler_rt/fmod.zig"));
737 mathExport("log", @import("./compiler_rt/log.zig"), true);737 mathExport("log", @import("./compiler_rt/log.zig"));
738 mathExport("log10", @import("./compiler_rt/log10.zig"), false);738 mathExport("log10", @import("./compiler_rt/log10.zig"));
739 mathExport("log2", @import("./compiler_rt/log2.zig"), true);739 mathExport("log2", @import("./compiler_rt/log2.zig"));
740 mathExport("round", @import("./compiler_rt/round.zig"), true);740 mathExport("round", @import("./compiler_rt/round.zig"));
741 mathExport("sin", @import("./compiler_rt/sin.zig"), true);741 mathExport("sin", @import("./compiler_rt/sin.zig"));
742 mathExport("sincos", @import("./compiler_rt/sincos.zig"), true);742 mathExport("sincos", @import("./compiler_rt/sincos.zig"));
743 mathExport("sqrt", @import("./compiler_rt/sqrt.zig"), true);743 mathExport("sqrt", @import("./compiler_rt/sqrt.zig"));
744 mathExport("tan", @import("./compiler_rt/tan.zig"), true);744 mathExport("tan", @import("./compiler_rt/tan.zig"));
745 mathExport("trunc", @import("./compiler_rt/trunc.zig"), true);745 mathExport("trunc", @import("./compiler_rt/trunc.zig"));
746746
747 if (arch.isSPARC()) {747 if (arch.isSPARC()) {
748 // SPARC systems use a different naming scheme748 // SPARC systems use a different naming scheme
...@@ -825,7 +825,7 @@ comptime {...@@ -825,7 +825,7 @@ comptime {
825 }825 }
826}826}
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 {
829 const half_name = "__" ++ double_name ++ "h";829 const half_name = "__" ++ double_name ++ "h";
830 const half_fn = @field(import, half_name);830 const half_fn = @field(import, half_name);
831 const float_name = double_name ++ "f";831 const float_name = double_name ++ "f";
...@@ -853,9 +853,12 @@ inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_ha...@@ -853,9 +853,12 @@ inline fn mathExport(double_name: []const u8, comptime import: type, win_libc_ha
853 .{ f128, quad_fn },853 .{ f128, quad_fn },
854 };854 };
855855
856 // Weak aliases don't work on Windows, so we avoid exporting the `l` alias856 if (builtin.os.tag == .windows) {
857 // on this platform for functions we know will collide.857 // Weak aliases don't work on Windows, so we have to provide the 'l' variants
858 if (builtin.os.tag != .windows or !builtin.link_libc or !win_libc_has_it) {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 {
859 inline for (pairs) |pair| {862 inline for (pairs) |pair| {
860 const F = pair[0];863 const F = pair[0];
861 const func = pair[1];864 const func = pair[1];
lib/compiler_rt/ceil.zig+11
...@@ -111,6 +111,17 @@ pub fn ceilq(x: f128) callconv(.C) f128 {...@@ -111,6 +111,17 @@ pub fn ceilq(x: f128) callconv(.C) f128 {
111 }111 }
112}112}
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
114test "ceil32" {125test "ceil32" {
115 try expect(ceilf(1.3) == 2.0);126 try expect(ceilf(1.3) == 2.0);
116 try expect(ceilf(-1.3) == -1.0);127 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 {...@@ -107,6 +107,17 @@ pub fn cosq(a: f128) callconv(.C) f128 {
107 return cos(@floatCast(f64, a));107 return cos(@floatCast(f64, a));
108}108}
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
110test "cos32" {121test "cos32" {
111 const epsilon = 0.00001;122 const epsilon = 0.00001;
112123
lib/compiler_rt/exp.zig+11
...@@ -182,6 +182,17 @@ pub fn expq(a: f128) callconv(.C) f128 {...@@ -182,6 +182,17 @@ pub fn expq(a: f128) callconv(.C) f128 {
182 return exp(@floatCast(f64, a));182 return exp(@floatCast(f64, a));
183}183}
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
185test "exp32" {196test "exp32" {
186 const epsilon = 0.000001;197 const epsilon = 0.000001;
187198
lib/compiler_rt/exp2.zig+11
...@@ -149,6 +149,17 @@ pub fn exp2q(x: f128) callconv(.C) f128 {...@@ -149,6 +149,17 @@ pub fn exp2q(x: f128) callconv(.C) f128 {
149 return exp2(@floatCast(f64, x));149 return exp2(@floatCast(f64, x));
150}150}
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
152const exp2ft = [_]f64{163const exp2ft = [_]f64{
153 0x1.6a09e667f3bcdp-1,164 0x1.6a09e667f3bcdp-1,
154 0x1.7a11473eb0187p-1,165 0x1.7a11473eb0187p-1,
lib/compiler_rt/fabs.zig+11
...@@ -20,6 +20,17 @@ pub fn fabsq(a: f128) callconv(.C) f128 {...@@ -20,6 +20,17 @@ pub fn fabsq(a: f128) callconv(.C) f128 {
20 return generic_fabs(a);20 return generic_fabs(a);
21}21}
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
23inline fn generic_fabs(x: anytype) @TypeOf(x) {34inline fn generic_fabs(x: anytype) @TypeOf(x) {
24 const T = @TypeOf(x);35 const T = @TypeOf(x);
25 const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);36 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 {...@@ -141,6 +141,17 @@ pub fn floorq(x: f128) callconv(.C) f128 {
141 }141 }
142}142}
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
144test "floor16" {155test "floor16" {
145 try expect(__floorh(1.3) == 1.0);156 try expect(__floorh(1.3) == 1.0);
146 try expect(__floorh(-1.3) == -2.0);157 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 {...@@ -135,6 +135,17 @@ pub fn fmaq(x: f128, y: f128, z: f128) callconv(.C) f128 {
135 }135 }
136}136}
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
138const dd = struct {149const dd = struct {
139 hi: f64,150 hi: f64,
140 lo: f64,151 lo: f64,
lib/compiler_rt/fmax.zig+11
...@@ -21,6 +21,17 @@ pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 {...@@ -21,6 +21,17 @@ pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 {
21 return generic_fmax(f128, x, y);21 return generic_fmax(f128, x, y);
22}22}
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
24inline fn generic_fmax(comptime T: type, x: T, y: T) T {35inline fn generic_fmax(comptime T: type, x: T, y: T) T {
25 if (math.isNan(x))36 if (math.isNan(x))
26 return y;37 return y;
lib/compiler_rt/fmin.zig+11
...@@ -21,6 +21,17 @@ pub fn fminq(x: f128, y: f128) callconv(.C) f128 {...@@ -21,6 +21,17 @@ pub fn fminq(x: f128, y: f128) callconv(.C) f128 {
21 return generic_fmin(f128, x, y);21 return generic_fmin(f128, x, y);
22}22}
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
24inline fn generic_fmin(comptime T: type, x: T, y: T) T {35inline fn generic_fmin(comptime T: type, x: T, y: T) T {
25 if (math.isNan(x))36 if (math.isNan(x))
26 return y;37 return y;
lib/compiler_rt/fmod.zig+11
...@@ -237,6 +237,17 @@ pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {...@@ -237,6 +237,17 @@ pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {
237 return amod;237 return amod;
238}238}
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
240inline fn generic_fmod(comptime T: type, x: T, y: T) T {251inline fn generic_fmod(comptime T: type, x: T, y: T) T {
241 @setRuntimeSafety(false);252 @setRuntimeSafety(false);
242253
lib/compiler_rt/log.zig+11
...@@ -131,6 +131,17 @@ pub fn logq(a: f128) callconv(.C) f128 {...@@ -131,6 +131,17 @@ pub fn logq(a: f128) callconv(.C) f128 {
131 return log(@floatCast(f64, a));131 return log(@floatCast(f64, a));
132}132}
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
134test "ln32" {145test "ln32" {
135 const epsilon = 0.000001;146 const epsilon = 0.000001;
136147
lib/compiler_rt/log10.zig+11
...@@ -159,6 +159,17 @@ pub fn log10q(a: f128) callconv(.C) f128 {...@@ -159,6 +159,17 @@ pub fn log10q(a: f128) callconv(.C) f128 {
159 return log10(@floatCast(f64, a));159 return log10(@floatCast(f64, a));
160}160}
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
162test "log10_32" {173test "log10_32" {
163 const epsilon = 0.000001;174 const epsilon = 0.000001;
164175
lib/compiler_rt/log2.zig+11
...@@ -150,6 +150,17 @@ pub fn log2q(a: f128) callconv(.C) f128 {...@@ -150,6 +150,17 @@ pub fn log2q(a: f128) callconv(.C) f128 {
150 return math.log2(a);150 return math.log2(a);
151}151}
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
153test "log2_32" {164test "log2_32" {
154 const epsilon = 0.000001;165 const epsilon = 0.000001;
155166
lib/compiler_rt/round.zig+11
...@@ -123,6 +123,17 @@ pub fn roundq(x_: f128) callconv(.C) f128 {...@@ -123,6 +123,17 @@ pub fn roundq(x_: f128) callconv(.C) f128 {
123 }123 }
124}124}
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
126test "round32" {137test "round32" {
127 try expect(roundf(1.3) == 1.0);138 try expect(roundf(1.3) == 1.0);
128 try expect(roundf(-1.3) == -1.0);139 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 {...@@ -111,6 +111,17 @@ pub fn sinq(x: f128) callconv(.C) f128 {
111 return sin(@floatCast(f64, x));111 return sin(@floatCast(f64, x));
112}112}
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
114test "sin32" {125test "sin32" {
115 const epsilon = 0.00001;126 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 {...@@ -181,6 +181,17 @@ pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.C) void {
181 r_cos.* = small_cos;181 r_cos.* = small_cos;
182}182}
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
184const rem_pio2_generic = @compileError("TODO");195const rem_pio2_generic = @compileError("TODO");
185196
186/// Ported from musl sincosl.c. Needs the following dependencies to be complete:197/// 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 {...@@ -225,6 +225,17 @@ pub fn sqrtq(x: f128) callconv(.C) f128 {
225 return sqrt(@floatCast(f64, x));225 return sqrt(@floatCast(f64, x));
226}226}
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
228test "sqrtf" {239test "sqrtf" {
229 const V = [_]f32{240 const V = [_]f32{
230 0.0,241 0.0,
lib/compiler_rt/tan.zig+11
...@@ -96,6 +96,17 @@ pub fn tanq(x: f128) callconv(.C) f128 {...@@ -96,6 +96,17 @@ pub fn tanq(x: f128) callconv(.C) f128 {
96 return tan(@floatCast(f64, x));96 return tan(@floatCast(f64, x));
97}97}
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
99test "tan" {110test "tan" {
100 try expect(tan(@as(f32, 0.0)) == tanf(0.0));111 try expect(tan(@as(f32, 0.0)) == tanf(0.0));
101 try expect(tan(@as(f64, 0.0)) == tan(0.0));112 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 {...@@ -81,6 +81,17 @@ pub fn truncq(x: f128) callconv(.C) f128 {
81 }81 }
82}82}
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
84test "trunc32" {95test "trunc32" {
85 try expect(truncf(1.3) == 1.0);96 try expect(truncf(1.3) == 1.0);
86 try expect(truncf(-1.3) == -1.0);97 try expect(truncf(-1.3) == -1.0);