mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge 19b16ffe8b into 9082b004b6
This commit is contained in:
commit
96d655a1fe
1 changed files with 195 additions and 0 deletions
|
|
@ -3,6 +3,9 @@
|
||||||
const common = @import("./common.zig");
|
const common = @import("./common.zig");
|
||||||
const comparef = @import("./comparef.zig");
|
const comparef = @import("./comparef.zig");
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub const panic = common.panic;
|
pub const panic = common.panic;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
|
|
@ -10,6 +13,10 @@ comptime {
|
||||||
@export(&__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = common.linkage, .visibility = common.visibility });
|
@export(&__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(&__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = common.linkage, .visibility = common.visibility });
|
@export(&__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(&__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = common.linkage, .visibility = common.visibility });
|
@export(&__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
if (builtin.cpu.arch.isArm() and !builtin.cpu.arch.isThumb() and !builtin.cpu.has(.arm, .pacbti)) {
|
||||||
|
@export(&__aeabi_cdcmple, .{ .name = "__aeabi_cdcmple", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(&__aeabi_cdcmpeq, .{ .name = "__aeabi_cdcmpeq", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
@export(&__eqdf2, .{ .name = "__eqdf2", .linkage = common.linkage, .visibility = common.visibility });
|
@export(&__eqdf2, .{ .name = "__eqdf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(&__nedf2, .{ .name = "__nedf2", .linkage = common.linkage, .visibility = common.visibility });
|
@export(&__nedf2, .{ .name = "__nedf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
|
@ -66,3 +73,191 @@ fn __aeabi_dcmplt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 {
|
||||||
fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 {
|
fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 {
|
||||||
return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater);
|
return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn __aeabi_cdcmpeq_check_nan(a: f64, b: f64) callconv(.c) i32 {
|
||||||
|
return @intFromBool(std.math.isNan(a) or std.math.isNan(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function compares two doubles and returns the result in CPSR register.
|
||||||
|
//
|
||||||
|
// C code equivalent:
|
||||||
|
//
|
||||||
|
// void __aeabi_cdcmpeq(double a, double b) {
|
||||||
|
// if (isnan(a) || isnan(b)) {
|
||||||
|
// Z = 0; C = 1;
|
||||||
|
// } else {
|
||||||
|
// __aeabi_cdcmple(a, b);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Code has been taken from LLVM implementation:
|
||||||
|
// https://github.com/llvm/llvm-project/blob/7eee67202378932d03331ad04e7d07ed4d988381/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
|
||||||
|
//
|
||||||
|
fn __aeabi_cdcmpeq(_: f64, _: f64) callconv(.naked) void {
|
||||||
|
const apsr_c = 0x20000000;
|
||||||
|
asm volatile (
|
||||||
|
\\ push {r0-r3, lr}
|
||||||
|
\\ bl %[__aeabi_cdcmpeq_check_nan]
|
||||||
|
\\ cmp r0, #1
|
||||||
|
\\ pop {r0-r3, lr}
|
||||||
|
\\ bne %[__aeabi_cdcmple]
|
||||||
|
\\ msr APSR_nzcvq, %[APSR_C]
|
||||||
|
\\ bx lr
|
||||||
|
:
|
||||||
|
: [__aeabi_cdcmple] "X" (&__aeabi_cdcmple),
|
||||||
|
[__aeabi_cdcmpeq_check_nan] "X" (&__aeabi_cdcmpeq_check_nan),
|
||||||
|
[APSR_C] "i" (apsr_c),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function compares two doubles and returns the result in CPSR register.
|
||||||
|
//
|
||||||
|
// C code equivalent:
|
||||||
|
//
|
||||||
|
// void __aeabi_cdcmple(double a, double b) {
|
||||||
|
// if (__aeabi_dcmplt(a, b)) {
|
||||||
|
// Z = 0; C = 0;
|
||||||
|
// } else if (__aeabi_dcmpeq(a, b)) {
|
||||||
|
// Z = 1; C = 1;
|
||||||
|
// } else {
|
||||||
|
// Z = 0; C = 1;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Code has been taken from LLVM implementation:
|
||||||
|
// https://github.com/llvm/llvm-project/blob/7eee67202378932d03331ad04e7d07ed4d988381/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
|
||||||
|
//
|
||||||
|
fn __aeabi_cdcmple(_: f64, _: f64) callconv(.naked) void {
|
||||||
|
const apsr_c = 0x20000000;
|
||||||
|
const apsr_z = 0x40000000;
|
||||||
|
asm volatile (
|
||||||
|
\\ push {r0-r3, lr}
|
||||||
|
\\ bl %[__aeabi_dcmplt]
|
||||||
|
\\ cmp r0, #1
|
||||||
|
\\ moveq ip, #0
|
||||||
|
\\ beq 1f
|
||||||
|
\\ ldm sp, {r0-r3}
|
||||||
|
\\ bl %[__aeabi_dcmpeq]
|
||||||
|
\\ cmp r0, #1
|
||||||
|
\\ moveq ip, %[APSR_CZ]
|
||||||
|
\\ movne ip, %[APSR_C]
|
||||||
|
\\1:
|
||||||
|
\\ msr APSR_nzcvq, ip
|
||||||
|
\\ pop {r0-r3}
|
||||||
|
\\ pop {pc}
|
||||||
|
:
|
||||||
|
: [__aeabi_dcmplt] "X" (&__aeabi_dcmplt),
|
||||||
|
[__aeabi_dcmpeq] "X" (&__aeabi_dcmpeq),
|
||||||
|
[APSR_C] "i" (apsr_c),
|
||||||
|
[APSR_CZ] "i" (apsr_c | apsr_z),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CPSRFlags = packed struct {
|
||||||
|
filler: u28,
|
||||||
|
v: u1,
|
||||||
|
c: u1,
|
||||||
|
z: u1,
|
||||||
|
n: u1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CPSR = packed union {
|
||||||
|
flags: CPSRFlags,
|
||||||
|
value: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const __aeabi_cdcmpxx = *const fn (f64, f64) callconv(.naked) void;
|
||||||
|
|
||||||
|
fn call__aeabi_cdcmpxx(comptime func: __aeabi_cdcmpxx, a: f64, b: f64) CPSR {
|
||||||
|
const A: u64 = @bitCast(a);
|
||||||
|
const B: u64 = @bitCast(b);
|
||||||
|
|
||||||
|
const le = comptime builtin.cpu.arch.endian() == .little;
|
||||||
|
const a_lo: u32 = if (le) @truncate(A) else @truncate(A >> 32);
|
||||||
|
const a_hi: u32 = if (le) @truncate(A >> 32) else @truncate(A);
|
||||||
|
const b_lo: u32 = if (le) @truncate(B) else @truncate(B >> 32);
|
||||||
|
const b_hi: u32 = if (le) @truncate(B >> 32) else @truncate(B);
|
||||||
|
|
||||||
|
const result = asm volatile (
|
||||||
|
\\ bl %[func]
|
||||||
|
\\ mrs %[out], apsr
|
||||||
|
: [out] "=r" (-> u32),
|
||||||
|
: [r0] "{r0}" (a_lo),
|
||||||
|
[r1] "{r1}" (a_hi),
|
||||||
|
[r2] "{r2}" (b_lo),
|
||||||
|
[r3] "{r3}" (b_hi),
|
||||||
|
[func] "X" (func),
|
||||||
|
);
|
||||||
|
return .{ .value = result };
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test has been copied from LLVM:
|
||||||
|
// https://github.com/llvm/llvm-project/blob/7eee67202378932d03331ad04e7d07ed4d988381/compiler-rt/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c
|
||||||
|
//
|
||||||
|
test "test __aeabi_cdcmpeq" {
|
||||||
|
if (!builtin.cpu.arch.isArm() or builtin.cpu.arch.isThumb() or builtin.cpu.has(.arm, .pacbti)) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const t = std.testing;
|
||||||
|
const nan = std.math.nan(f64);
|
||||||
|
const inf = std.math.inf(f64);
|
||||||
|
|
||||||
|
try t.expectEqual(@as(u1, 1), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 1.0, 1.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 1234.567, 765.4321).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, -123.0, -678.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 0.0, -0.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 1.0, nan).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, nan, 1.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, nan, nan).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, inf, 1.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 0.0, inf).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, -inf, 0.0).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, 0.0, -inf).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, inf, inf).flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), call__aeabi_cdcmpxx(&__aeabi_cdcmpeq, -inf, -inf).flags.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test has been copied from LLVM:
|
||||||
|
// https://github.com/llvm/llvm-project/blob/7eee67202378932d03331ad04e7d07ed4d988381/compiler-rt/test/builtins/Unit/arm/aeabi_cdcmple_test.c
|
||||||
|
//
|
||||||
|
test "test __aeabi_cdcmple" {
|
||||||
|
if (!builtin.cpu.arch.isArm() or builtin.cpu.arch.isThumb() or builtin.cpu.has(.arm, .pacbti)) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const t = std.testing;
|
||||||
|
const nan = std.math.nan(f64);
|
||||||
|
|
||||||
|
var cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, 1.0, 1.0);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, 1234.567, 765.4321);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, 765.4321, 1234.567);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, -123.0, -678.0);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, -678.0, -123.0);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, 0.0, -0.0);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, 1.0, nan);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, nan, 1.0);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
|
||||||
|
cpsr = call__aeabi_cdcmpxx(&__aeabi_cdcmple, nan, nan);
|
||||||
|
try t.expectEqual(@as(u1, 0), cpsr.flags.z);
|
||||||
|
try t.expectEqual(@as(u1, 1), cpsr.flags.c);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue