Skip to content

Commit b5e7c2a

Browse files
committed
Optimized f64 comparisons and integer conversions
1 parent 079f70b commit b5e7c2a

File tree

10 files changed

+137
-33
lines changed

10 files changed

+137
-33
lines changed

src/crt/dcmp.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,31 @@ typedef union F64_pun {
1212
#define F64_CMP_GREATER 1 /* doesn't trigger flags */
1313
#define F64_CMP_UNORDERED 1 /* doesn't trigger flags */
1414

15+
typedef struct f64_cmp_arg {
16+
long double x;
17+
bool x_sign; /* <-- unimplemented */
18+
unsigned int const return_address;
19+
long double y;
20+
bool y_sign; /* <-- unimplemented */
21+
} f64_cmp_arg;
22+
1523
// assumes no NaN
16-
int _dcmp_c(const long double *__restrict x, const long double *__restrict y) {
17-
F64_pun arg_x, arg_y;
18-
arg_x.flt = *x;
19-
arg_y.flt = *y;
24+
int _dcmp_c(f64_cmp_arg *__restrict const arg) {
25+
F64_pun x, y;
26+
x.flt = arg->x;
27+
y.flt = arg->y;
2028

21-
bool x_sign = signbit(arg_x.flt);
22-
bool y_sign = signbit(arg_y.flt);
29+
bool x_sign = signbit(x.flt);
30+
bool y_sign = signbit(y.flt);
2331
if (x_sign != y_sign) {
24-
if (iszero(arg_x.flt) && iszero(arg_y.flt)) {
32+
if (iszero(x.flt) && iszero(y.flt)) {
2533
return F64_CMP_EQUAL;
2634
}
2735
return (x_sign ? F64_CMP_LESS : F64_CMP_GREATER);
2836
}
2937

30-
if (arg_x.bin == arg_y.bin) {
38+
if (x.bin == y.bin) {
3139
return F64_CMP_EQUAL;
3240
}
33-
return ((arg_x.bin < arg_y.bin) != x_sign) ? F64_CMP_LESS : F64_CMP_GREATER;
41+
return ((x.bin < y.bin) != x_sign) ? F64_CMP_LESS : F64_CMP_GREATER;
3442
}

src/crt/dcmp.src

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@
44

55
public __dcmp
66

7-
; int _dcmp_c(const long double *__restrict x, const long double *__restrict y)
7+
; int _dcmp_c(f64_cmp_arg const *__restrict const arg)
88
__dcmp:
9-
; f64*_f64*_ret_i24
10-
push bc, de, hl, af, iy
11-
ld iy, 6
12-
add iy, sp
13-
pea iy + 12
14-
push iy
9+
; f64_cmp_arg*_ret_i24
10+
push bc, de, hl
11+
or a, a
12+
sbc hl, hl
13+
add hl, sp
14+
push iy, af
15+
push hl ; f64_cmp_arg*
1516
call __dcmp_c
16-
pop af, af, iy, af
17+
pop af
18+
pop af, iy
1719
; Set the comparison flags
1820
add hl, de
1921
or a, a

src/crt/dtol.src

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@
66

77
__dtol:
88
; f64_ret_i32
9-
push af, iy, bc, de, hl
9+
push af, iy
10+
ld a, b
11+
push bc, de, hl
12+
ld hl, 7
13+
add hl, sp
14+
res 7, (hl) ; fabsl(x)
15+
inc hl
16+
rlca
17+
ld (hl), a ; store the sign of x in the padding byte
1018
call __dtol_c
11-
pop af, af, af, iy, af
19+
pop af, af, bc, iy, af
1220
ret
1321

1422
extern __dtol_c

src/crt/dtoll.src

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66

77
__dtoll:
88
; f64_ret_i64
9-
push af, iy, bc, de, hl
9+
push af, iy
10+
ld a, b
11+
res 7, b ; fabsl(x)
12+
push bc, de, hl
13+
ld hl, 8
14+
add hl, sp
15+
rlca
16+
ld (hl), a ; store the sign of x in the padding byte
1017
call __dtoll_c
1118
pop af, af, af, iy, af
1219
ret

src/crt/dtoul.src

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ __dtoul:
88
; f64_ret_u32
99
push af, iy, bc, de, hl
1010
call __dtoul_c
11-
pop af, af, af, iy, af
11+
pop af, af, bc, iy, af
1212
ret
1313

1414
extern __dtoul_c

src/crt/float64_to_int.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ uint64_t _dtoull_c(long double x) {
7474
*/
7575
#define HANDLE_INT_MIN 1
7676

77+
typedef struct f64_sign {
78+
long double flt;
79+
bool sign;
80+
} f64_sign;
81+
7782
/**
7883
* @note val must have the signbit cleared
7984
*/
@@ -123,10 +128,10 @@ uint32_t _dtoul_c(long double x) {
123128
return (uint32_t)f64_to_unsigned(val);
124129
}
125130

126-
int64_t _dtoll_c(long double x) {
131+
int64_t _dtoll_c(f64_sign arg) {
127132
F64_pun val;
128-
bool x_sign = signbit(x);
129-
val.flt = fabsl(x);
133+
bool x_sign = arg.sign;
134+
val.flt = arg.flt;
130135

131136
/* overflow || isinf(x) || isnan(x) */
132137
if (val.reg.BC >= ((Float64_bias + Float64_i64_max_exp) << Float64_exp_BC_shift)) {
@@ -145,10 +150,10 @@ int64_t _dtoll_c(long double x) {
145150
return ret;
146151
}
147152

148-
int32_t _dtol_c(long double x) {
153+
int32_t _dtol_c(f64_sign arg) {
149154
F64_pun val;
150-
bool x_sign = signbit(x);
151-
val.flt = fabsl(x);
155+
bool x_sign = arg.sign;
156+
val.flt = arg.flt;
152157

153158
/* overflow || isinf(x) || isnan(x) */
154159
if (val.reg.BC >= ((Float64_bias + Float64_i32_max_exp) << Float64_exp_BC_shift)) {

src/softfloat/include/softfloat.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,13 @@ enum {
116116
/*----------------------------------------------------------------------------
117117
| Routine to raise any or all of the software floating-point exception flags.
118118
*----------------------------------------------------------------------------*/
119+
#if 0
119120
void softfloat_raiseFlags( uint_fast8_t );
121+
#else
122+
inline void softfloat_raiseFlags( uint_fast8_t flags ) {
123+
softfloat_exceptionFlags |= flags;
124+
}
125+
#endif
120126

121127
/*----------------------------------------------------------------------------
122128
| Integer-to-floating-point conversion routines.

src/softfloat/softfloat_raiseFlags.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3434
3535
=============================================================================*/
3636

37+
#if 0
38+
3739
#include "platform.h"
3840
#include "softfloat.h"
3941
#include <fenv.h>
@@ -49,3 +51,4 @@ void softfloat_raiseFlags( uint_fast8_t flags )
4951
softfloat_exceptionFlags |= flags;
5052
}
5153

54+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
assume adl=1
2+
3+
section .text
4+
5+
public _f64_pos_zero
6+
_f64_pos_zero:
7+
db $00, $00, $00, $00, $00, $00, $00, $00
8+
9+
public _f64_neg_zero
10+
_f64_neg_zero:
11+
db $00, $00, $00, $00, $00, $00, $00, $80
12+
13+
public _f64_pos_one
14+
_f64_pos_one:
15+
db $00, $00, $00, $00, $00, $00, $F0, $3F
16+
17+
public _f64_neg_one
18+
_f64_neg_one:
19+
db $00, $00, $00, $00, $00, $00, $F0, $BF
20+
21+
public _f64_pos_pi
22+
_f64_pos_pi:
23+
db $18, $2D, $44, $54, $FB, $21, $09, $40
24+
25+
public _f64_neg_pi
26+
_f64_neg_pi:
27+
db $18, $2D, $44, $54, $FB, $21, $09, $C0

test/floating_point/float64_arithmetic/src/main.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,54 @@ static size_t run_test(int64_t* fail_ulp) {
6161
return SIZE_MAX;
6262
}
6363

64+
#define C(expr) if (!(expr)) { return __LINE__; }
65+
66+
extern volatile long double f64_pos_zero;
67+
extern volatile long double f64_neg_zero;
68+
extern volatile long double f64_pos_one;
69+
extern volatile long double f64_neg_one;
70+
extern volatile long double f64_pos_pi;
71+
extern volatile long double f64_neg_pi;
72+
73+
int comparison_test(void) {
74+
C(f64_pos_one == f64_pos_one );
75+
C(f64_neg_one < f64_pos_one );
76+
C(f64_pos_one >= f64_neg_one );
77+
C(f64_pos_one != f64_neg_one );
78+
C(f64_pos_zero < f64_pos_one );
79+
C(f64_neg_zero > f64_neg_one );
80+
81+
C(f64_pos_zero == f64_pos_zero);
82+
C(f64_neg_zero == f64_neg_zero);
83+
C(f64_pos_zero >= f64_neg_zero);
84+
C(f64_neg_zero == f64_pos_zero);
85+
86+
C(f64_pos_pi == f64_pos_pi );
87+
C(f64_pos_pi > f64_pos_one );
88+
C(f64_neg_pi < f64_neg_one );
89+
C(f64_pos_pi > f64_pos_zero);
90+
C(f64_neg_pi <= f64_neg_zero);
91+
C(f64_neg_pi != f64_neg_zero);
92+
C(f64_pos_pi != f64_neg_pi );
93+
C(f64_pos_pi >= f64_neg_pi );
94+
95+
return 0;
96+
}
97+
6498
int main(void) {
6599
os_ClrHome();
66-
int64_t fail_ulp = 0;
67-
size_t fail_index = run_test(&fail_ulp);
68-
if (fail_index == SIZE_MAX) {
69-
printf("All tests passed");
100+
int comparison_result = comparison_test();
101+
if (comparison_result != 0) {
102+
printf("Failed test L%d\n", comparison_result);
70103
} else {
71-
printf("Failed test: %zu\nULP: %lld", fail_index, fail_ulp);
104+
int64_t fail_ulp = 0;
105+
size_t fail_index = run_test(&fail_ulp);
106+
if (fail_index == SIZE_MAX) {
107+
printf("All tests passed");
108+
} else {
109+
printf("Failed test: %zu\nULP: %lld", fail_index, fail_ulp);
110+
}
72111
}
73-
74112
while (!os_GetCSC());
75113

76114
return 0;

0 commit comments

Comments
 (0)