From 0106e838579d2a8a9a8598de44bb3d9a07c3dcbe Mon Sep 17 00:00:00 2001 From: unknown <71151164+ZERICO2005@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:52:18 -0600 Subject: [PATCH] implemented logbf in asm and optimized ilogbf and copysignl --- src/libc/copysignl.src | 3 +- src/libc/ilogbf.src | 30 ++++----- src/libc/logbf.src | 68 ++++++++++++++++++++ src/libc/{logb.c => logbl.c} | 16 +---- test/floating_point/float32_ilogb/src/main.c | 51 ++++++++++++++- test/floating_point/float64_ilogb/src/main.c | 51 ++++++++++++++- 6 files changed, 179 insertions(+), 40 deletions(-) create mode 100644 src/libc/logbf.src rename src/libc/{logb.c => logbl.c} (50%) diff --git a/src/libc/copysignl.src b/src/libc/copysignl.src index b6b8277e2..41eb2e695 100644 --- a/src/libc/copysignl.src +++ b/src/libc/copysignl.src @@ -6,7 +6,8 @@ _copysignl: ld hl, 19 ; upper 8 bits of y add hl, sp - rl (hl) ; extract the signbit of y + ld a, (hl) ; extract the signbit of y + rlca pop iy, hl, de, bc push bc, de, hl rl b ; clear the signbit of x, signbit of y is in the LSB diff --git a/src/libc/ilogbf.src b/src/libc/ilogbf.src index 97d48bb1f..505591976 100644 --- a/src/libc/ilogbf.src +++ b/src/libc/ilogbf.src @@ -13,48 +13,40 @@ _ilogbf: dec hl dec hl dec hl - ld de, (hl) - sbc hl, hl - ex de, hl - ; DE is zero + ld hl, (hl) add hl, hl - adc a, a jr z, .maybe_subnormal inc a - scf jr z, .inf_nan - rr e ; E = 128 or float32_bias + 1 + sub a, 128 ; float32_bias + 1 sbc hl, hl ld l, a - sbc hl, de ret .maybe_subnormal: - ; DE is zero, Carry unknown add hl, de + or a, a sbc hl, de jr z, .ret_zero call __ictlz - ex de, hl - ; DE was zero, so HL is now zero - dec hl cpl add a, 130 + sbc hl, hl ld l, a ret -.ret_zero: .inf_nan: - ld hl, $800000 ; FP_ILOGB0 - sbc hl, de ; FP_ILOGBNAN or INT_MAX when carry is set - ex de, hl - ; DE was zero, so HL is now zero - ld l, 4 ; EDOM + scf +.ret_zero: + ld hl, 4 ; EDOM ld (_errno), hl ld hl, ___fe_cur_env set 4, (hl) ; FE_INVALID - ex de, hl + ld hl, $800000 ; FP_ILOGB0 + ret nc + ; FP_ILOGBNAN or INT_MAX when carry is set + dec hl ret extern _errno diff --git a/src/libc/logbf.src b/src/libc/logbf.src new file mode 100644 index 000000000..5a5dc8b34 --- /dev/null +++ b/src/libc/logbf.src @@ -0,0 +1,68 @@ + assume adl=1 + + section .text + + public _logbf, _logb + +; float logbf(float) +_logb: +_logbf: + ld hl, 6 + ld bc, -3 + add hl, sp + ld a, (hl) + add hl, bc + ld c, b ; ld bc, -1 + ld hl, (hl) + add hl, hl + adc a, a + jr z, .maybe_subnormal + inc a + jr z, .inf_nan + sub a, 128 ; float32_bias + 1 + jr c, .negative_exponent + inc bc ; ld bc, 0 +.negative_exponent: +.int_to_float: + ; exponent is [-149, 127] + ld c, a + ld a, b ; sign extend + call __ltof + push bc + pop hl + ld e, a + ret + +.inf_nan: + ; return fabsf(x) + pop bc + ex (sp), hl + push bc + ld e, $7F + ret + +.ret_zero: + ; HL is zero here + ld l, 4 ; EDOM + ld (_errno), hl + ; FE_DIVBYZERO + ld hl, ___fe_cur_env + set 6, (hl) + ; -HUGE_VALF + ld hl, $800000 + ld e, b ; ld e, $FF + ret + +.maybe_subnormal: + add hl, bc + inc hl ; restore HL + jr nc, .ret_zero + call __ictlz + cpl + add a, 130 + jr .int_to_float + + extern __ltof + extern __ictlz + extern ___fe_cur_env + extern _errno diff --git a/src/libc/logb.c b/src/libc/logbl.c similarity index 50% rename from src/libc/logb.c rename to src/libc/logbl.c index 96d07789e..2b1431f2a 100644 --- a/src/libc/logb.c +++ b/src/libc/logbl.c @@ -1,23 +1,11 @@ +#include #include #include -float logbf(float x) { - if (isfinite(x)) { - if (iszero(x)) { - feraiseexcept(FE_DIVBYZERO); - return -HUGE_VALF; - } - return (float)ilogbf(x); - } - // infinity and NaN - return fabsf(x); -} - -double logb(double) __attribute__((alias("logbf"))); - long double logbl(long double x) { if (isfinite(x)) { if (iszero(x)) { + errno = EDOM; feraiseexcept(FE_DIVBYZERO); return -HUGE_VALL; } diff --git a/test/floating_point/float32_ilogb/src/main.c b/test/floating_point/float32_ilogb/src/main.c index acaec86fa..4b54a0617 100644 --- a/test/floating_point/float32_ilogb/src/main.c +++ b/test/floating_point/float32_ilogb/src/main.c @@ -2,7 +2,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -13,6 +16,25 @@ #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) +#if 0 +#define test_printf printf +#else +#define test_printf(...) +#endif + +float truth_logbf(float x) { + if (isfinite(x)) { + if (iszero(x)) { + errno = EDOM; + feraiseexcept(FE_DIVBYZERO); + return -HUGE_VALF; + } + return (float)ilogbf(x); + } + // infinity and NaN + return fabsf(x); +} + size_t run_test(void) { typedef float input_t; typedef int output_t; @@ -24,9 +46,32 @@ size_t run_test(void) { for (size_t i = 0; i < length; i++) { int result = ilogbf(input[i]); if (result != output[i]) { - #if 0 - printf("%3zu: %08lX\n\t%d != %d\n", i, input[i], result, output[i]); - #endif + test_printf("%3zu: %08lX\n%d != %d\n", i, input[i], result, output[i]); + return i; + } + + errno = 0; + feclearexcept(FE_ALL_EXCEPT); + float f_truth = truth_logbf(input[i]); + unsigned char fe_truth = __fe_cur_env; + int errno_truth = errno; + + errno = 0; + feclearexcept(FE_ALL_EXCEPT); + float f_guess = logbf(input[i]); + unsigned char fe_guess = __fe_cur_env; + int errno_guess = errno; + + if (memcmp(&f_guess, &f_truth, sizeof(float)) != 0) { + test_printf("%3zu: %08lX %d\n%08lX != %08lX\n", i, input[i], output[i], f_guess, f_truth); + return i; + } + if (fe_guess != fe_truth) { + fputs("fenv fail\n", stdout); + return i; + } + if (errno_guess != errno_truth) { + fputs("errno fail\n", stdout); return i; } } diff --git a/test/floating_point/float64_ilogb/src/main.c b/test/floating_point/float64_ilogb/src/main.c index e97f1568c..03bc34d77 100644 --- a/test/floating_point/float64_ilogb/src/main.c +++ b/test/floating_point/float64_ilogb/src/main.c @@ -2,7 +2,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -13,6 +16,25 @@ #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) +#if 0 +#define test_printf printf +#else +#define test_printf(...) +#endif + +long double truth_logbl(long double x) { + if (isfinite(x)) { + if (iszero(x)) { + errno = EDOM; + feraiseexcept(FE_DIVBYZERO); + return -HUGE_VALL; + } + return (long double)ilogbl(x); + } + // infinity and NaN + return fabsl(x); +} + size_t run_test(void) { typedef long double input_t; typedef int output_t; @@ -24,9 +46,32 @@ size_t run_test(void) { for (size_t i = 0; i < length; i++) { int result = ilogbl(input[i]); if (result != output[i]) { - #if 0 - printf("%4zu: %016llX\n %d != %d\n", i, input[i], result, output[i]); - #endif + test_printf("%4zu: %016llX\n%d != %d\n", i, input[i], result, output[i]); + return i; + } + + errno = 0; + feclearexcept(FE_ALL_EXCEPT); + long double f_truth = truth_logbl(input[i]); + unsigned char fe_truth = __fe_cur_env; + int errno_truth = errno; + + errno = 0; + feclearexcept(FE_ALL_EXCEPT); + long double f_guess = logbl(input[i]); + unsigned char fe_guess = __fe_cur_env; + int errno_guess = errno; + + if (memcmp(&f_guess, &f_truth, sizeof(long double)) != 0) { + test_printf("%4zu:\n%016llX %d\n%016llX !=\n%016llX\n", i, input[i], output[i], f_guess, f_truth); + return i; + } + if (fe_guess != fe_truth) { + fputs("fenv fail\n", stdout); + return i; + } + if (errno_guess != errno_truth) { + fputs("errno fail\n", stdout); return i; } }