Skip to content

Commit 8daffcb

Browse files
committed
lltod can now raise FE_INEXACT. Removed utod/itod for now
1 parent 192d97f commit 8daffcb

File tree

3 files changed

+138
-75
lines changed

3 files changed

+138
-75
lines changed

src/crt/ltod.src

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
assume adl=1
22

3+
__lltod_signal_FE_INEXACT := 1
4+
35
;-------------------------------------------------------------------------------
46

57
section .text
@@ -49,54 +51,74 @@ __lltod_common:
4951
push hl
5052
push bc
5153
ld b, a
52-
ld c, 1
54+
ld c, a
55+
xor a, a
5356
.shift_loop:
54-
jr nc, .no_carry
55-
inc c
56-
.no_carry:
57+
adc a, 0
5758
srl h
5859
rr l
5960
djnz .shift_loop
60-
; test round bit
61+
; round upwards to even if (round && (guard || sticky))
6162
jr nc, .no_round
62-
; test sticky bits
63-
dec c
63+
; we must ensure that FE_INEXACT is raised since rounding has occured
64+
or a, a ; test sticky bits
6465
jr nz, .round_up
65-
; test guard bit
66-
bit 0, l
67-
jr nc, .no_round
66+
inc a ; ld a, 1
67+
and a, l ; test guard bit
68+
jr z, .no_round_inexact
6869
.round_up:
6970
inc b ; round up after shifting
7071
.no_round:
72+
if __lltod_signal_FE_INEXACT
73+
adc a, a ; test sticky and round bits
74+
jr z, .result_is_exact
75+
.no_round_inexact:
76+
ld hl, ___fe_cur_env
77+
set 5, (hl) ; FE_INEXACT
78+
.result_is_exact:
79+
else
80+
.no_round_inexact:
81+
end if
7182
ld h, b
83+
ld a, c
84+
ld l, c
7285
pop bc
7386

74-
ld l, a
7587
ex (sp), hl ; (SP) = shift
7688
call __llshru
7789
ex (sp), hl ; (SP) = shifted HL, H = rounding, L = shift
7890
add a, 51
7991

8092
dec h
81-
push af
82-
; exponent = ($400 + (base2_logarithm - 1)) << 4
83-
; BC = $4EEM
84-
ld l, a
85-
ld h, $04
86-
; clear the implicit mantissa bit
87-
res 4, c ; 52 % 8 == 4
88-
add hl, hl
89-
add hl, hl
90-
add hl, hl
91-
add hl, hl
92-
ld a, l
93-
or a, c
93+
jr nz, __int_to_f64_shl.no_rounding
94+
95+
dec a ; compensate for the implicit mantissa bit
96+
; BC/exponent = [$434*, $43E*]
97+
add a, a
98+
add a, a
99+
add a, a
100+
add a, a
101+
add a, c
94102
ld c, a
95-
ld b, h
96-
pop af
97103
pop hl ; restore shifted HL
98-
call z, __lladd_1 ; round up to even
104+
ld b, $43
105+
if 0
106+
; inlined __lladd_1
107+
inc hl
108+
add hl, de
109+
or a, a
110+
sbc hl, de
111+
jr nz, __int_to_f64_shl.finish
112+
inc de
113+
sbc hl, de
114+
add hl, de
115+
jr nz, __int_to_f64_shl.finish
116+
inc bc
99117
jr __int_to_f64_shl.finish
118+
else
119+
call __lladd_1 ; round up to even
120+
jr __int_to_f64_shl.finish
121+
end if
100122

101123
;-------------------------------------------------------------------------------
102124

@@ -116,31 +138,6 @@ __int_to_f64_zero_or_one:
116138
sbc hl, hl
117139
jr __int_to_f64_shl.finish
118140

119-
;-------------------------------------------------------------------------------
120-
121-
section .text
122-
123-
public __itod
124-
; (long double)int
125-
__itod:
126-
push hl
127-
add hl, hl ; extract signbit
128-
sbc hl, hl ; set Z flag
129-
ld e, l ; sign extend UHL to E:UHL
130-
pop hl
131-
jq __ltod
132-
133-
;-------------------------------------------------------------------------------
134-
135-
section .text
136-
137-
public __utod
138-
; (long double)unsigned int
139-
__utod:
140-
ld e, 0
141-
142-
require __ultod
143-
144141
;-------------------------------------------------------------------------------
145142

146143
section .text
@@ -160,16 +157,6 @@ __ultod:
160157
; (long double)long
161158
__ltod:
162159
bit 7, e
163-
164-
require __ltod.hijack_itod
165-
166-
;-------------------------------------------------------------------------------
167-
168-
section .text
169-
170-
private __ltod.hijack_itod
171-
__ltod.hijack_itod:
172-
173160
push af
174161
call nz, __lneg ; abs(E:UHL)
175162

@@ -211,17 +198,18 @@ __int_to_f64_shl:
211198
ld a, 51
212199
sub a, l
213200

201+
.no_rounding:
214202
; exponent = ($400 + (base2_logarithm - 1)) << 4
215203
; BC = $4EEM
216204
ld l, a
217205
ld h, $04
218206
; clear the implicit mantissa bit
219-
res 4, c ; 52 % 8 == 4
220207
add hl, hl
221208
add hl, hl
222209
add hl, hl
223210
add hl, hl
224211
ld a, l
212+
res 4, c ; 52 % 8 == 4
225213
or a, c
226214
ld c, a
227215
ld b, h
@@ -234,11 +222,11 @@ __int_to_f64_shl:
234222

235223
;-------------------------------------------------------------------------------
236224

237-
extern __ineg
238225
extern __lneg
239226
extern __lctlz
240227
extern __llctlz
241228
extern __llshl
242229
extern __llshru
243230
extern __llneg
244231
extern __lladd_1
232+
extern ___fe_cur_env

test/floating_point/float64_from_integer/src/crt_wrap.asm

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22

33
section .text
44

5+
public _clear_fe_cur_env
6+
_clear_fe_cur_env:
7+
ld a, (___fe_cur_env)
8+
and a, -125 ; feclearexcept(FE_ALL_EXCEPT)
9+
ld (___fe_cur_env), a
10+
ret
11+
12+
public _get_fe_cur_env
13+
_get_fe_cur_env:
14+
ld a, (___fe_cur_env)
15+
ret
16+
517
public _CRT_utod, _CRT_itod
18+
if 0
619

720
_CRT_utod:
821
ld hl, 3
@@ -16,5 +29,29 @@ _CRT_itod:
1629
ld hl, (hl)
1730
jp __itod
1831

32+
else
33+
34+
_CRT_utod:
35+
ld hl, 3
36+
add hl, sp
37+
ld hl, (hl)
38+
ld e, 0
39+
jp __ultod
40+
41+
_CRT_itod:
42+
ld hl, 3
43+
add hl, sp
44+
ld hl, (hl)
45+
push hl
46+
add hl, hl
47+
sbc hl, hl
48+
ld e, l ; sign extend UHL to E:UHL
49+
pop hl
50+
jp __ltod
51+
end if
52+
1953
extern __utod
2054
extern __itod
55+
extern __ultod
56+
extern __ltod
57+
extern ___fe_cur_env

test/floating_point/float64_from_integer/src/main.c

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <stdint.h>
44
#include <stdio.h>
55
#include <math.h>
6+
#include <fenv.h>
67
#include <assert.h>
78
#include <ti/screen.h>
89
#include <ti/getcsc.h>
@@ -32,13 +33,18 @@ void print_failed(uint64_t input, uint64_t guess, uint64_t truth) {
3233
input, guess, truth
3334
);
3435
}
36+
#define test_printf printf
3537
#else
3638
#define print_failed(...)
39+
#define test_printf(...)
3740
#endif
3841

3942
long double CRT_utod(unsigned int);
4043
long double CRT_itod(signed int);
4144

45+
void clear_fe_cur_env(void);
46+
unsigned char get_fe_cur_env(void);
47+
4248
size_t run_test(const char** failed_func) {
4349
typedef struct { uint32_t u32; uint64_t u64; } input_t;
4450
typedef struct { F64_pun fu32; F64_pun fi32; F64_pun fu64; F64_pun fi64; } output_t;
@@ -82,19 +88,51 @@ size_t run_test(const char** failed_func) {
8288
}
8389
}
8490

85-
result.flt = (long double)((uint64_t)input[i].u64);
86-
if (result.bin != output[i].fu64.bin) {
87-
print_failed((uint64_t)input[i].u64, result.bin, output[i].fu64.bin);
88-
*failed_func = "ulltod";
89-
return i;
91+
{
92+
clear_fe_cur_env();
93+
result.flt = (long double)((uint64_t)input[i].u64);
94+
if (result.bin != output[i].fu64.bin) {
95+
print_failed((uint64_t)input[i].u64, result.bin, output[i].fu64.bin);
96+
*failed_func = "ulltod";
97+
return i;
98+
}
99+
unsigned char fe_env = get_fe_cur_env();
100+
bool rounding_occured = ((uint64_t)output[i].fu64.flt != (uint64_t)input[i].u64);
101+
bool inexact_raised = (fe_env & FE_INEXACT);
102+
if (rounding_occured != inexact_raised) {
103+
test_printf(
104+
"%zu: FE: %02X\nI: %016llX\nO: %016llX\n",
105+
i, fe_env,
106+
input[i].u64, output[i].fu64.bin
107+
);
108+
*failed_func = "ulltod";
109+
fputs("fenv\n", stdout);
110+
return i;
111+
}
90112
}
91113

92-
result.flt = (long double)((int64_t)input[i].u64);
93-
if (result.bin != output[i].fi64.bin) {
94-
print_failed((uint64_t)input[i].u64, result.bin, output[i].fi64.bin);
95-
*failed_func = "lltod";
96-
return i;
97-
}
114+
{
115+
clear_fe_cur_env();
116+
result.flt = (long double)((int64_t)input[i].u64);
117+
if (result.bin != output[i].fi64.bin) {
118+
print_failed((uint64_t)input[i].u64, result.bin, output[i].fi64.bin);
119+
*failed_func = "lltod";
120+
return i;
121+
}
122+
unsigned char fe_env = get_fe_cur_env();
123+
bool rounding_occured = ((int64_t)output[i].fi64.flt != (int64_t)input[i].u64);
124+
bool inexact_raised = (fe_env & FE_INEXACT);
125+
if (rounding_occured != inexact_raised) {
126+
test_printf(
127+
"%zu: FE: %02X\nI: %016llX\nO: %016llX\n",
128+
i, fe_env,
129+
input[i].u64, output[i].fu64.bin
130+
);
131+
*failed_func = "lltod";
132+
fputs("fenv\n", stdout);
133+
return i;
134+
}
135+
}
98136
}
99137

100138
/* passed all */

0 commit comments

Comments
 (0)