Skip to content

Commit 296eff1

Browse files
author
James Cox-Morton
committed
Add the ldexp family of functions, proxy to std.math.ldexp
Addresses ziglang#23358
1 parent 80170d0 commit 296eff1

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed

lib/compiler_rt.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ comptime {
224224
_ = @import("compiler_rt/fmax.zig");
225225
_ = @import("compiler_rt/fmin.zig");
226226
_ = @import("compiler_rt/fmod.zig");
227+
_ = @import("compiler_rt/ldexp.zig");
227228
_ = @import("compiler_rt/log.zig");
228229
_ = @import("compiler_rt/log10.zig");
229230
_ = @import("compiler_rt/log2.zig");

lib/compiler_rt/ldexp.zig

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const std = @import("std");
2+
const expect = std.testing.expect;
3+
const math = std.math;
4+
const common = @import("common.zig");
5+
6+
comptime {
7+
@export(&ldexp, .{ .name = "ldexp", .linkage = common.linkage, .visibility = common.visibility });
8+
@export(&ldexpf, .{ .name = "ldexpf", .linkage = common.linkage, .visibility = common.visibility });
9+
@export(&ldexpl, .{ .name = "ldexpl", .linkage = common.linkage, .visibility = common.visibility });
10+
}
11+
12+
pub fn ldexp(x: f64, n: i32) callconv(.c) f64 {
13+
return math.ldexp(x, n);
14+
}
15+
16+
test "ldexp" {
17+
// Ported from libc-test
18+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/sanity/ldexp.h
19+
try expect(ldexp(-0x1.02239f3c6a8f1p+3, -2) == -0x1.02239f3c6a8f1p+1);
20+
}
21+
22+
test "ldexp.special" {
23+
// Ported from libc-test
24+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/special/ldexp.h
25+
try expect(math.isNan(ldexp(math.nan(f64), 0)));
26+
try expect(math.isPositiveInf(ldexp(math.inf(f64), 0)));
27+
}
28+
29+
pub fn ldexpf(x: f32, n: i32) callconv(.c) f32 {
30+
return math.ldexp(x, n);
31+
}
32+
33+
test "ldexpf" {
34+
// Ported from libc-test
35+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/sanity/ldexpf.h
36+
try expect(ldexpf(-0x1.0223ap+3, -2) == -0x1.0223ap+1);
37+
}
38+
39+
test "ldexpf.special" {
40+
// Ported from libc-test
41+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/special/ldexpf.h
42+
try expect(math.isNan(ldexpf(math.nan(f32), 0)));
43+
try expect(math.isPositiveInf(ldexpf(math.inf(f32), 0)));
44+
}
45+
46+
pub fn ldexpl(x: f128, n: i32) callconv(.c) f128 {
47+
return math.ldexp(x, n);
48+
}
49+
50+
test "ldexpl" {
51+
// Ported from libc-test
52+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/sanity/ldexpl.h
53+
try expect(ldexpl(-0x1.02239f3c6a8f13dep+3, -2) == -0x1.02239f3c6a8f13dep+1);
54+
}
55+
56+
test "ldexpl.special" {
57+
// Ported from libc-test
58+
// https://repo.or.cz/libc-test.git/blob/HEAD:/src/math/special/ldexpl.h
59+
try expect(math.isNan(ldexpl(math.nan(f128), 0)));
60+
try expect(math.isPositiveInf(ldexpl(math.inf(f128), 0)));
61+
}

test/link/build.zig.zon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
.wasm_type = .{
5555
.path = "wasm/type",
5656
},
57+
.wasm_ldexp = .{
58+
.path = "wasm/ldexp",
59+
},
5760
},
5861
.paths = .{
5962
"build.zig",

test/link/wasm/ldexp/build.zig

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const std = @import("std");
2+
3+
pub fn build(b: *std.Build) void {
4+
const test_step = b.step("test", "Test it");
5+
b.default_step = test_step;
6+
7+
// Ensure ldexp symbols are available in Release modes
8+
// Regression test for https://github.com/ziglang/zig/issues/23358
9+
add(b, test_step, .ReleaseSafe);
10+
add(b, test_step, .ReleaseFast);
11+
add(b, test_step, .ReleaseSmall);
12+
// Also verify Debug still works
13+
add(b, test_step, .Debug);
14+
}
15+
16+
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
17+
const exe = b.addExecutable(.{
18+
.name = "ldexp_test",
19+
.root_module = b.createModule(.{
20+
.root_source_file = b.path("lib.zig"),
21+
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
22+
.optimize = optimize,
23+
}),
24+
});
25+
26+
exe.entry = .disabled;
27+
exe.rdynamic = true;
28+
29+
exe.root_module.export_symbol_names = &.{ "use_double", "use_float", "use_long" };
30+
31+
b.installArtifact(exe);
32+
33+
test_step.dependOn(&exe.step);
34+
}

test/link/wasm/ldexp/lib.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Test that LLVM's exp2 optimization requiring ldexp symbols works correctly.
2+
// In Release modes, LLVM's LibCallSimplifier converts exp2 calls to ldexp
3+
// when the input is an integer converted to float.
4+
// See https://github.com/ziglang/zig/issues/23358
5+
6+
export fn use_double(f: i32) f64 {
7+
return @exp2(@as(f64, @floatFromInt(f)));
8+
}
9+
10+
export fn use_float(f: i32) f32 {
11+
return @exp2(@as(f32, @floatFromInt(f)));
12+
}
13+
14+
export fn use_long(f: i32) f128 {
15+
return @exp2(@as(f128, @floatFromInt(f)));
16+
}

0 commit comments

Comments
 (0)