Skip to content

Commit a6df1cd

Browse files
committed
inlined __llmul_add_b_overflow (and updated strtoll clock cycle count)
1 parent d5e8abf commit a6df1cd

File tree

2 files changed

+104
-109
lines changed

2 files changed

+104
-109
lines changed

src/libc/strtoll.src

Lines changed: 103 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ _strtoull:
8080

8181
private __strtoll_common
8282

83+
__strtoll_common.invalid_base:
84+
xor a, a
85+
ld c, a
86+
; Setting C (base) to zero ensures that cp a, c will never set carry.
87+
; forcing the function to return.
88+
push af
89+
; sets BC:UDE:UHL to zero
90+
jr __strtoll_common.invalid_base_hijack
91+
8392
__strtoll_common:
8493
; output: BC:UDE:UHL
8594
; NC = no overflow for strtoull
@@ -93,9 +102,8 @@ __strtoll_common:
93102

94103
ld bc, (ix + 15) ; base
95104
add hl, bc
96-
jr c, .invalid_base
105+
jr c, __strtoll_common.invalid_base
97106
; UBC is zero here
98-
ld b, c ; store the base in B to allow for djnz hax
99107
ld hl, (ix + 9) ; nptr
100108
;-------------------------------------------------------------------------------
101109
; consume whitespace (inlinsed isspace)
@@ -122,7 +130,7 @@ __strtoll_common:
122130
; A = 0, (HL) = start of number
123131
;-------------------------------------------------------------------------------
124132
; update the base if needed
125-
or a, b ; base
133+
or a, c ; base
126134
jr z, .auto_base
127135
xor a, 16
128136
jr z, .hex_base
@@ -131,7 +139,7 @@ __strtoll_common:
131139
.auto_base: ; test for 0* 0x* 0X* 0b* 0B*
132140
.bin_base: ; test for 0x* 0X*
133141
.hex_base: ; test for 0b* 0B*
134-
inc b ; djnz hax
142+
inc c
135143
ld a, (hl)
136144
xor a, '0'
137145
jr nz, .maybe_decimal
@@ -143,34 +151,36 @@ __strtoll_common:
143151
xor a, 'B' xor 'X'
144152
jr z, .maybe_bin
145153
dec hl
146-
djnz .other_base
147-
ld b, 8 ; octal
154+
dec c
155+
jr nz, .other_base
156+
ld c, 8 ; octal
148157
jr .save_new_base
149158

150159
.maybe_bin:
151-
bit 4, b
160+
bit 4, c
152161
jr nz, .undo_inc ; hexadecimal
153162
; base is 0 or 2
154163
inc hl
155-
ld b, 2
164+
ld c, 2
156165
jr .save_new_base
157166

158167
.maybe_hex:
159-
bit 1, b
168+
bit 1, c
160169
jr nz, .undo_inc ; binary
161170
; base is 0 or 16
162171
inc hl
163-
ld b, 16
172+
ld c, 16
164173
jr .save_new_base
165174

166175
.undo_inc:
167176
dec hl
168-
; dec b
177+
; dec c
169178
; jr .other_base
170179
.maybe_decimal:
171180
; set to decimal if base is not zero
172-
djnz .other_base
173-
ld b, 10 ; decimal
181+
dec c
182+
jr nz, .other_base
183+
ld c, 10 ; decimal
174184
.save_new_base:
175185
;-------------------------------------------------------------------------------
176186
.other_base:
@@ -180,12 +190,10 @@ __strtoll_common:
180190
.invalid_base_hijack:
181191
; or a, a ; carry is cleared here
182192
sbc hl, hl
183-
ex de, hl
184-
sbc hl, hl
185-
ld c, l
186193
; A = first digit of the number
187-
; BC:UDE:UHL = 0
188-
; (ix - 1) = base
194+
; HL = 0
195+
; B = 0
196+
; C = base
189197
; (ix - 2) = (first-non-whitespace) XOR '-'
190198
; 6, (ix - 3) = Z if result should be negative, NZ for positive
191199
; 0, (ix - 3) = overflow bit
@@ -203,146 +211,133 @@ __strtoll_common:
203211
add a, 10
204212
.check_digit:
205213
; End the loop when the digit is out of range for the base
206-
cp a, b
207-
ld (ix - 1), b ; store base
208-
ld b, l ; now BC:UDE:UHL is zero
214+
cp a, c
215+
push hl ; (ix - 6) = $000000
216+
push hl ; (ix - 9) = $000000
209217
jr c, .loop
210218
;-------------------------------------------------------------------------------
211219
; no digit found or invalid base
212220
; set *endptr to nptr and return 0
213221
ld iy, (ix + 9) ; nptr
214222
jr .write_endptr
215-
.invalid_base:
216-
xor a, a
217-
ld b, a
218-
; Setting B (base) to zero ensures that cp a, b will never set carry.
219-
; forcing the function to return.
220-
push af
221-
; sets BC:UDE:UHL to zero
222-
jr .invalid_base_hijack
223+
223224
;-------------------------------------------------------------------------------
224225
; CC per non-decimal digit:
225-
; minimum : 100F + 20R + 18W + 35
226-
; low average : 102F + 20R + 18W + 36
227-
; high average : 112F + 20R + 18W + 37 ; an over-estimate of the average CC
228-
; maximum : 127F + 20R + 18W + 40
229-
; overflow max : 133F + 24R + 22W + 42
226+
; no overflow : 109F + 10R + 9W + 33
227+
; overflow : 117F + 11R + 10W + 35
230228
.check_decimal:
231-
cp a, (ix - 1)
229+
cp a, c
232230
jr nc, .end_loop
233231
.loop:
234-
call __llmul_add_b_overflow
235-
.next_digit:
236-
; IY = str, BC:UDE:UHL = accumulator, 0, (ix - 3) = overflow bit
237-
inc iy
238-
; Convert a numerical digit
239-
ld a, (iy)
240-
sub a, 48
241-
cp a, 10
242-
jr c, .check_decimal
243-
; Convert an alphabetic digit, case-insensitive
244-
sub a, 65 - 48
245-
res 5, a
246-
add a, 10
247-
; End the loop when the digit is out of range for the base
248-
cp a, (ix - 1)
249-
jr c, .loop
250-
.end_loop:
251-
;-------------------------------------------------------------------------------
252-
.write_endptr:
253-
push hl
254-
ld hl, (ix + 12) ; endptr
255-
add hl, de
256-
or a, a
257-
sbc hl, de
258-
jr z, .endptr_null
259-
ld (hl), iy
260-
.endptr_null:
261-
pop hl
262-
pop af ; overflow and sign flags
263-
pop ix
264-
ret
265-
266-
;-------------------------------------------------------------------------------
267-
268-
private __llmul_add_b_overflow
269-
__llmul_add_b_overflow:
270-
; BC:UDE:UHL = (BC:UDE:UHL * (ix - 1)) + A
232+
.__llmul_add_b_overflow:
233+
; value = (value * C) + A
271234
; bit 0, (ix - 3) is set if overflow has occured
272-
.__llmulu_b_overflow:
273-
; inlined/modified __llmulu_b
274-
; CC no overflow : 69F + 16R + 15W + 33
275-
; CC overflow max : 73F + 17R + 16W + 34
276-
push hl ; (ix - 9)
277-
push de ; (ix - 12)
278-
push bc ; (ix - 15)
279-
ld b, (ix - 1)
280-
ld c, e ; ld c, (ix - 12)
281-
ld e, h ; ld e, (ix - 8)
282-
ld h, b
235+
; (ix - 6) --> HL
236+
; (ix - 9) --> DE
237+
; HL --> BC
238+
push hl ; (ix - 12)
239+
ld h, c
240+
ld l, (ix - 6) ; L
283241
mlt hl
284242

285243
; (255 * 255) + 255 < 65535 so no 16bit carry can occur
286244
add a, l
287-
ld (ix - 9), a ; L
288-
ld d, b
289-
; ld e, (ix - 8) ; H
245+
ld (ix - 6), a ; L
246+
ld d, c
247+
ld e, (ix - 5) ; H
290248
mlt de
291249
ld l, h
292-
ld h, 0
250+
ld h, b ; B is guaranteed to be zero if overflow has not occured
293251
adc hl, de ; handles carry from adding A
294252
xor a, a
295253

296-
ld (ix - 8), l ; H
297-
ld d, b
298-
ld e, (ix - 7) ; UHL
254+
ld (ix - 5), l ; H
255+
ld d, c
256+
ld e, (ix - 4) ; UHL
299257
mlt de
300258
ld l, h
301259
ld h, a
302260
add hl, de
303-
ld (ix - 7), l ; UHL
304-
ld d, b
305-
ld e, c ; ld e, (ix - 12) ; E
261+
ld (ix - 4), l ; UHL
262+
ld d, c
263+
ld e, (ix - 9) ; E
306264
mlt de
307265
ld l, h
308266
ld h, a
309267
add hl, de
310-
ld (ix - 12), l ; E
311-
ld d, b
312-
ld e, (ix - 11) ; D
268+
ld (ix - 9), l ; E
269+
ld d, c
270+
ld e, (ix - 8) ; D
313271
mlt de
314272
ld l, h
315273
ld h, a
316274
add hl, de
317-
ld (ix - 11), l ; D
318-
ld d, b
319-
ld e, (ix - 10) ; UDE
275+
ld (ix - 8), l ; D
276+
ld d, c
277+
ld e, (ix - 7) ; UDE
320278
mlt de
321279
ld l, h
322280
ld h, a
323281
add hl, de
324-
ld (ix - 10), l ; UDE
282+
ld (ix - 7), l ; UDE
325283

326284
pop de
327285
ld l, h
328-
ld c, d
329-
ld d, b
286+
ld b, d
287+
ld d, c ; D = base
330288
mlt bc
331289
ld h, c
290+
ld c, d ; C = base
332291
mlt de
333292

334293
add.s hl, de
335-
pop de
294+
sbc a, b ; set carry if B is non-zero or if there was carry previously
336295
jr c, .set_overflow_bit
337-
sub a, b ; set carry if B is non-zero
338-
ld b, h
296+
.next_digit:
297+
; (ix - 6) --> HL
298+
; (ix - 9) --> DE
299+
; HL --> BC
300+
; C = base
301+
; IY = str
302+
; 0, (ix - 3) = overflow bit
303+
inc iy
304+
; Convert a numerical digit
305+
ld a, (iy)
306+
sub a, 48
307+
cp a, 10
308+
jr c, .check_decimal
309+
; Convert an alphabetic digit, case-insensitive
310+
sub a, 65 - 48
311+
res 5, a
312+
add a, 10
313+
; End the loop when the digit is out of range for the base
314+
cp a, c
315+
jr c, .loop
316+
.end_loop:
317+
;-------------------------------------------------------------------------------
318+
.write_endptr:
339319
ld c, l
340-
.set_overflow_bit:
320+
ld b, h
321+
ld hl, (ix + 12) ; endptr
322+
add hl, de
323+
or a, a
324+
sbc hl, de
325+
jr z, .endptr_null
326+
ld (hl), iy
327+
.endptr_null:
328+
pop de
341329
pop hl
342-
ret nc
343-
set 0, (ix - 3) ; set carry
330+
pop af ; overflow and sign flags
331+
pop ix
344332
ret
345333

334+
;-------------------------------------------------------------------------------
335+
.set_overflow_bit:
336+
set 0, (ix - 3) ; set carry
337+
jr .next_digit
338+
339+
;-------------------------------------------------------------------------------
340+
346341
extern _errno
347342
extern __llneg
348343
extern __llcmpzero

test/standalone/strtol/src/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
//------------------------------------------------------------------------------
1919

2020
// define to 0 or 1
21-
#define DEBUG_DIAGNOSTICS 0
21+
#define DEBUG_DIAGNOSTICS 1
2222

2323
//------------------------------------------------------------------------------
2424
// Utility

0 commit comments

Comments
 (0)