Skip to content

Commit 96126e7

Browse files
committed
optimized float to integer routines
1 parent 5e5478c commit 96126e7

File tree

11 files changed

+557
-648
lines changed

11 files changed

+557
-648
lines changed

src/crt/dtol.src

+4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
section .text
44

55
public __dtol
6+
public __dtoul
67

8+
; __dtol_c correctly handles all non-UB cases for both
9+
; (long)long double and (unsigned long)long double
710
__dtol:
11+
__dtoul:
812
; f64_ret_i32
913
push af, iy
1014
ld a, b

src/crt/dtoll.src

+4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
section .text
44

55
public __dtoll
6+
public __dtoull
67

8+
; __dtoll_c correctly handles all non-UB cases for both
9+
; (long long)long double and (unsigned long long)long double
710
__dtoll:
11+
__dtoull:
812
; f64_ret_i64
913
push af, iy
1014
ld a, b

src/crt/dtoul.src

-18
This file was deleted.

src/crt/dtoull.src

-14
This file was deleted.

src/crt/float64_to_int.c

+12-46
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,6 @@ uint64_t _dtoull_c(long double x) {
6464
}
6565
#endif
6666

67-
/**
68-
* @brief set to 0 or 1
69-
* If set to 1, values that truncate to `INT32_MIN`/`INT64_MIN` will be
70-
* handled correctly.
71-
* If set to 0, it can save a little bit of space by removing a comparison from
72-
* `_dtol_c` and `_dtoll_c`. However this will cause values that would truncate
73-
* to `INT32_MIN`/`INT64_MIN` to have an undefined result.
74-
*/
75-
#define HANDLE_INT_MIN 1
76-
7767
typedef struct f64_sign {
7868
long double flt;
7969
bool sign;
@@ -106,41 +96,18 @@ static uint64_t f64_to_unsigned(F64_pun val) {
10696
return val.bin;
10797
}
10898

109-
uint64_t _dtoull_c(long double x) {
110-
F64_pun val;
111-
val.flt = x;
112-
/* overflow || signbit(x) || isinf(x) || isnan(x) */
113-
if (val.reg.BC >= ((Float64_bias + Float64_u64_max_exp) << Float64_exp_BC_shift)) {
114-
/* undefined return value for negative/overflow/inf/NaN of x */
115-
return 0;
116-
}
117-
return f64_to_unsigned(val);
118-
}
119-
120-
uint32_t _dtoul_c(long double x) {
121-
F64_pun val;
122-
val.flt = x;
123-
/* overflow || signbit(x) || isinf(x) || isnan(x) */
124-
if (val.reg.BC >= ((Float64_bias + Float64_u32_max_exp) << Float64_exp_BC_shift)) {
125-
/* undefined return value for negative/overflow/inf/NaN values of x */
126-
return 0;
127-
}
128-
return (uint32_t)f64_to_unsigned(val);
129-
}
130-
99+
/**
100+
* @brief the exact same routine is used for (long long)long double and
101+
* (unsigned long long)long double. If the input long double is out of range,
102+
* then the conversion is UB anyways.
103+
*/
131104
int64_t _dtoll_c(f64_sign arg) {
132105
F64_pun val;
133106
bool x_sign = arg.sign;
134107
val.flt = arg.flt;
135108

136109
/* overflow || isinf(x) || isnan(x) */
137-
if (val.reg.BC >= ((Float64_bias + Float64_i64_max_exp) << Float64_exp_BC_shift)) {
138-
#if HANDLE_INT_MIN != 0
139-
/* if the value truncates to INT64_MIN */
140-
if (x_sign && val.bin == UINT64_C(0x43E0000000000000)) {
141-
return INT64_MIN;
142-
}
143-
#endif
110+
if (val.reg.BC >= ((Float64_bias + Float64_u64_max_exp) << Float64_exp_BC_shift)) {
144111
/* undefined return value for underflow/overflow/inf/NaN values of x */
145112
return 0;
146113
}
@@ -150,19 +117,18 @@ int64_t _dtoll_c(f64_sign arg) {
150117
return ret;
151118
}
152119

120+
/**
121+
* @brief the exact same routine is used for (long)long double and
122+
* (unsigned long)long double. If the input long double is out of range,
123+
* then the conversion is UB anyways.
124+
*/
153125
int32_t _dtol_c(f64_sign arg) {
154126
F64_pun val;
155127
bool x_sign = arg.sign;
156128
val.flt = arg.flt;
157129

158130
/* overflow || isinf(x) || isnan(x) */
159-
if (val.reg.BC >= ((Float64_bias + Float64_i32_max_exp) << Float64_exp_BC_shift)) {
160-
#if HANDLE_INT_MIN != 0
161-
/* if the value truncates to INT32_MIN */
162-
if (x_sign && val.bin <= UINT64_C(0x41E00000001FFFFF)) {
163-
return INT32_MIN;
164-
}
165-
#endif
131+
if (val.reg.BC >= ((Float64_bias + Float64_u32_max_exp) << Float64_exp_BC_shift)) {
166132
/* undefined return value for underflow/overflow/inf/NaN values of x */
167133
return 0;
168134
}

src/crt/ftoll.c

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#include <math.h>
33
#include <stdint.h>
44

5+
/**
6+
* @brief the exact same routine is used for (long long)float and
7+
* (unsigned long long)float. If the input float is out of range,
8+
* then the conversion is UB anyways.
9+
*/
510
long long _ftoll_c(float x)
611
{
712
const union { float f; uint32_t u; struct { uint32_t mantissa: FLT_MANT_DIG - 1, exponent: 8, sign: 1; }; } parts = { .f = x };

src/crt/ftoll.src

+5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
section .text
44

55
public __ftoll
6+
public __ftoull
7+
8+
; __ftoll_c correctly handles all non-UB cases for both
9+
; (long long)float and (unsigned long long)float
610
__ftoll:
11+
__ftoull:
712
ld d, a
813
push iy, de, hl
914
call __ftoll_c

src/crt/ftoull.c

-43
This file was deleted.

src/crt/ftoull.src

-13
This file was deleted.

0 commit comments

Comments
 (0)