From caa84d70021b34ac32dc86a35f3486347cbd3467 Mon Sep 17 00:00:00 2001 From: angie Date: Tue, 14 Nov 2023 23:01:36 -0300 Subject: [PATCH] Implement __fixtfsi --- README.md | 1 + include/gcc_vr4300/types.h | 20 +++- src/soft_float/int_from_float/__fixtfsi.c | 131 ++++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/soft_float/int_from_float/__fixtfsi.c diff --git a/README.md b/README.md index ab153ba..3c8e892 100644 --- a/README.md +++ b/README.md @@ -122,3 +122,4 @@ the ABI passed to the `make` command. - - - +- diff --git a/include/gcc_vr4300/types.h b/include/gcc_vr4300/types.h index 33b851b..eb00df4 100644 --- a/include/gcc_vr4300/types.h +++ b/include/gcc_vr4300/types.h @@ -4,11 +4,20 @@ #include "macro.h" #include "abi.h" +#if __STDC_VERSION__ >= 202311L +// do nothing +#else +typedef _Bool bool; +#endif + typedef __SIZE_TYPE__ size_t; typedef __INT32_TYPE__ int32_t; STATIC_ASSERT(sizeof(int32_t) == 4, "int32_t type's size is not 4"); +typedef __UINT32_TYPE__ uint32_t; +STATIC_ASSERT(sizeof(uint32_t) == 4, "uint32_t type's size is not 4"); + typedef __INT64_TYPE__ int64_t; STATIC_ASSERT(sizeof(int64_t) == 8, "int64_t type's size is not 8"); @@ -29,6 +38,11 @@ STATIC_ASSERT(sizeof(float128) == 16, "float128 type's size is not 16"); typedef int fcmp __attribute__ ((mode (__libgcc_cmp_return__))); + +#define INT32_MAX ((int32_t)0x7FFFFFFF) +#define INT32_MIN ((int32_t)0x80000000) + + typedef union Float64Union { float64 d; int64_t ll; @@ -38,8 +52,12 @@ typedef union Float64Union { #if ABI_N32 || ABI_N64 typedef union Float128Union { float128 ld; - uint64_t hex[2]; + struct { + uint64_t upper; + uint64_t lower; + } hex; } Float128Union; +STATIC_ASSERT(sizeof(Float128Union) == 16, "Float128Union type's size is not 16"); #endif #endif diff --git a/src/soft_float/int_from_float/__fixtfsi.c b/src/soft_float/int_from_float/__fixtfsi.c new file mode 100644 index 0000000..db2ca47 --- /dev/null +++ b/src/soft_float/int_from_float/__fixtfsi.c @@ -0,0 +1,131 @@ +/* SPDX-FileCopyrightText: © 2023 Decompollaborate */ +/* SPDX-License-Identifier: MIT */ + +#include "gcc_vr4300/types.h" +#include "gcc_vr4300/export.h" + +#if ABI_N32 || ABI_N64 +EXPORT(__fixtfsi); + +/** + * Gets int32_t from float128. + * + * https://gcc.gnu.org/onlinedocs/gccint/the-gcc-low-level-runtime-library/routines-for-floating-point-emulation.html#c.__fixtfsi + */ +int32_t __fixtfsi(float128 a) { + // IEEE754 128-bit floats are encoded in 128 bits as follows: + // Sign bit: 1 bit (bit 127) + // Encoded exponent: 15 bits (bits 112 ~ 126) + // Fraction/Mantissa: 112 bits (bits 0 ~ 111) + + Float128Union flt; + int32_t sign; + int32_t encodedExponent; + int32_t realExponent; + bool mantissaIsZero; + int32_t computedValue; + + uint32_t truncantedMantissa; + + flt.ld = a; + + // If parameter is zero (or negative zero), then return zero + if (flt.hex.lower == 0) { + if ((flt.hex.upper == 0) || (flt.hex.upper & (1ULL << 63))) { + return 0; + } + } + + sign = flt.hex.upper >> 63; + // Clear up the sign + flt.hex.upper &= ~(1ULL << 63); + + encodedExponent = flt.hex.upper >> 48; + // Clear up the encoded exponent + flt.hex.upper &= ~0x7FFF000000000000ULL; + + // Exponent bias: 0x3FFF + realExponent = encodedExponent - 0x3FFF; + + mantissaIsZero = (flt.hex.upper == 0) && (flt.hex.lower == 0); + + if (encodedExponent == 0) { + // subnormals + return 0; + } + + if (encodedExponent == 0x7FFF) { + // Infinity and NaN + + if (mantissaIsZero) { + // Infinity, return max int + + // TODO: should this be handled in any other way? + + if (sign) { + return INT32_MIN; + } else { + return INT32_MAX; + } + } + + // NaN + return 0; // ? + } + + // TODO: Figure out proper way to handle values outside of the int32_t range + + if (realExponent < 0) { + // Value smaller than 1, truncate to zero (?) + return 0; + } + + if (realExponent > 31) { + // Value is larger than int32_t, return int max + + // TODO: should this be handled in any other way? + + if (sign) { + return INT32_MIN; + } else { + return INT32_MAX; + } + } + + if (mantissaIsZero) { + // If the mantissa is zero, just shift 1 by the exponent to get the value + computedValue = 1 << realExponent; + + if (sign) { + computedValue *= -1; + } + + return computedValue; + } + + // We truncate the mantissa from 112 bits to 32 bits because an `int32_t` can't fit more than that + truncantedMantissa = flt.hex.upper >> 16; + + // Manually compute the value + // The following algorithm only works for converting a float that is greater or equal than 1 but smaller than INT_MAX + + // The implicit leading bit + computedValue = 1; + + while (realExponent-- > 0) { + computedValue *= 2; + + // Iterate the mantissa, from the upper bits to the lowest ones + if (truncantedMantissa & 0x80000000) { + computedValue += 1; + } + truncantedMantissa <<= 1; + } + + if (sign) { + computedValue *= -1; + } + + return computedValue; +} +#endif