Skip to content

Add more compiler-rt functions for ARM platform #4073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/std/special/compiler_rt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ comptime {
@export("__floatsisf", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage);
@export("__floatdidf", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage);
@export("__floatsitf", @import("compiler_rt/floatsiXf.zig").__floatsitf, linkage);

@export("__floatunsisf", @import("compiler_rt/floatunsisf.zig").__floatunsisf, linkage);
@export("__floatundisf", @import("compiler_rt/floatundisf.zig").__floatundisf, linkage);
@export("__floatunsidf", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage);
@export("__floatundidf", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage);

Expand Down Expand Up @@ -183,6 +186,8 @@ comptime {
@export("__aeabi_l2d", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage);
@export("__aeabi_ui2d", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage);
@export("__aeabi_ul2d", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage);
@export("__aeabi_ui2f", @import("compiler_rt/floatunsisf.zig").__floatunsisf, linkage);
@export("__aeabi_ul2f", @import("compiler_rt/floatundisf.zig").__floatundisf, linkage);

@export("__aeabi_fneg", @import("compiler_rt/negXf2.zig").__negsf2, linkage);
@export("__aeabi_dneg", @import("compiler_rt/negXf2.zig").__negdf2, linkage);
Expand Down
86 changes: 86 additions & 0 deletions lib/std/special/compiler_rt/floatundisf.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const builtin = @import("builtin");
const std = @import("std");
const maxInt = std.math.maxInt;

const FLT_MANT_DIG = 24;

pub extern fn __floatundisf(arg: u64) f32 {
@setRuntimeSafety(builtin.is_test);

if (arg == 0) return 0;

var a = arg;
const N: usize = @TypeOf(a).bit_count;
// Number of significant digits
const sd = N - @clz(u64, a);
// 8 exponent
var e = @intCast(u32, sd) - 1;

if (sd > FLT_MANT_DIG) {
// start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
// finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
// 12345678901234567890123456
// 1 = msb 1 bit
// P = bit FLT_MANT_DIG-1 bits to the right of 1
// Q = bit FLT_MANT_DIG bits to the right of 1
// R = "or" of all bits to the right of Q
switch (sd) {
FLT_MANT_DIG + 1 => a <<= 1,
FLT_MANT_DIG + 2 => {},
else => {
const shift_amt = @intCast(u6, ((N + FLT_MANT_DIG + 2) - sd));
const all_ones: u64 = maxInt(u64);
a = (a >> @intCast(u6, sd - (FLT_MANT_DIG + 2))) |
@boolToInt(a & (all_ones >> shift_amt) != 0);
},
}
// Or P into R
a |= @boolToInt((a & 4) != 0);
// round - this step may add a significant bit
a += 1;
// dump Q and R
a >>= 2;
// a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
if ((a & (@as(u64, 1) << FLT_MANT_DIG)) != 0) {
a >>= 1;
e += 1;
}
// a is now rounded to FLT_MANT_DIG bits
} else {
a <<= @intCast(u6, FLT_MANT_DIG - sd);
// a is now rounded to FLT_MANT_DIG bits
}

const result: u32 = ((e + 127) << 23) | // exponent
@truncate(u32, a & 0x007FFFFF); // mantissa
return @bitCast(f32, result);
}

fn test__floatundisf(a: u64, expected: f32) void {
std.testing.expectEqual(expected, __floatundisf(a));
}

test "floatundisf" {
test__floatundisf(0, 0.0);
test__floatundisf(1, 1.0);
test__floatundisf(2, 2.0);
test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62F);
test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62F);
test__floatundisf(0x8000008000000000, 0x1p+63F);
test__floatundisf(0x8000010000000000, 0x1.000002p+63F);
test__floatundisf(0x8000000000000000, 0x1p+63F);
test__floatundisf(0x8000000000000001, 0x1p+63F);
test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64F);
test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64F);
test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50F);
test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50F);
test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50F);
}
53 changes: 53 additions & 0 deletions lib/std/special/compiler_rt/floatunsisf.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const builtin = @import("builtin");
const std = @import("std");
const maxInt = std.math.maxInt;

const significandBits = 23;
const exponentBias = 127;
const implicitBit = @as(u32, 1) << significandBits;

pub extern fn __floatunsisf(arg: u32) f32 {
@setRuntimeSafety(builtin.is_test);

if (arg == 0) return 0.0;

// The exponent is the width of abs(a)
const exp = @as(u32, 31) - @clz(u32, arg);

var mantissa: u32 = undefined;
if (exp <= significandBits) {
// Shift a into the significand field and clear the implicit bit
const shift = @intCast(u5, significandBits - exp);
mantissa = @as(u32, arg) << shift ^ implicitBit;
} else {
const shift = @intCast(u5, exp - significandBits);
// Round to the nearest number after truncation
mantissa = @as(u32, arg) >> shift ^ implicitBit;
// Align to the left and check if the truncated part is halfway over
const round = arg << @intCast(u5, 31 - shift);
mantissa += @boolToInt(round > 0x80000000);
// Tie to even
mantissa += mantissa & 1;
}

// Use the addition instead of a or since we may have a carry from the
// mantissa to the exponent
var result = mantissa;
result += (exp + exponentBias) << significandBits;

return @bitCast(f32, result);
}

fn test_one_floatunsisf(a: u32, expected: u32) void {
const r = __floatunsisf(a);
std.testing.expect(@bitCast(u32, r) == expected);
}

test "floatunsisf" {
// Test the produced bit pattern
test_one_floatunsisf(0, 0);
test_one_floatunsisf(1, 0x3f800000);
test_one_floatunsisf(0x7FFFFFFF, 0x4f000000);
test_one_floatunsisf(0x80000000, 0x4f000000);
test_one_floatunsisf(0xFFFFFFFF, 0x4f800000);
}