Little strdup optimisation

-12 bytes on disk
-20 cycles per strdup
-6 cycles per strlen called from strdup
This commit is contained in:
Colin Leroy-Mira 2024-01-05 19:39:03 +01:00
parent 169c9c0da0
commit 3a439e0e1b
4 changed files with 51 additions and 73 deletions

View File

@ -7,13 +7,13 @@
.export _strcspn
.import popptr1, _strlen
.importzp ptr1, ptr2, tmp1, tmp2
.importzp ptr1, ptr4, tmp1, tmp2
_strcspn:
jsr _strlen ; get length in a/x and transfer s2 to ptr2
jsr _strlen ; get length in a/x and transfer s2 to ptr4
; Note: It does not make sense to
; have more than 255 test chars, so
; we don't support a high byte here! (ptr2+1 is
; we don't support a high byte here! (ptr4+1 is
; also unchanged in strlen then (important!))
; -> the original implementation also
; ignored this case
@ -38,7 +38,7 @@ checkNext:
iny
check: cpy tmp1 ; compare with length of test character string
beq endOfTestChars
cmp (ptr2),y ; found matching char?
cmp (ptr4),y ; found matching char?
bne checkNext
leave: txa ; restore position of finding

View File

@ -1,85 +1,62 @@
;
; Ullrich von Bassewitz, 18.07.2000
; Colin Leroy-Mira, 05.01.2024
;
; char* __fastcall__ strdup (const char* S);
;
; Note: The code knowns which zero page locations are used by malloc.
; Note: The code knowns which zero page locations are used by malloc,
; memcpy and strlen.
;
.importzp sp, tmp1, ptr4
.import pushax, decsp4, incsp4
.import _strlen, _malloc, _memcpy
.importzp ptr2, ptr3, ptr4, tmp1, tmp2, tmp3
.import _strlen_ptr4, _malloc, _memcpy, pushax
.export _strdup
.macpack cpu
.macpack generic
_strdup:
; Get length (and store source in ptr4)
sta ptr4
stx ptr4+1
stx tmp1 ; Backup high byte, which
jsr _strlen_ptr4 ; strlen may increment
; Since we need some place to store the intermediate results, allocate a
; stack frame. To make this somewhat more efficient, create the stackframe
; as needed for the final call to the memcpy function.
pha ; decsp will destroy A (but not X)
jsr decsp4 ; Target/source
; Store the pointer into the source slot
ldy #1
txa
sta (sp),y
pla
.if (.cpu .bitand CPU_ISET_65SC02)
sta (sp)
; Add null byte for terminator
.if (.cpu .bitand ::CPU_ISET_65SC02)
inc a
.else
dey
sta (sp),y
clc
adc #1
.endif
; Get length of S (which is still in a/x)
jsr _strlen
; Calculate strlen(S)+1 (the space needed)
add #1
bcc @L1
bne :+
inx
; Save the space we're about to allocate in ptr4
@L1: sta ptr4
stx ptr4+1
; Allocate memory. _malloc will not use ptr4
; Store length
: sta tmp2
stx tmp3
; Allocate memory
jsr _malloc
; Store the result into the target stack slot
ldy #2
sta (sp),y ; Store low byte
sta tmp1
txa ; Get high byte
iny
sta (sp),y ; Store high byte
; Check for a NULL pointer
ora tmp1
; Check for NULL
bne :+
cpx #$00
beq OutOfMemory
; Copy the string. memcpy will return the target string which is exactly
; what we need here. It will also drop the allocated stack frame.
; Push dest
: jsr pushax
; Push source
lda ptr4
ldx ptr4+1 ; Load size
jmp _memcpy ; Copy string, drop stackframe
ldx tmp1
jsr pushax
; Out of memory, return NULL (A = 0)
; Push length
lda tmp2
ldx tmp3
; Copy and return the dest pointer
jmp _memcpy
OutOfMemory:
tax
jmp incsp4 ; Drop stack frame
rts

View File

@ -2,19 +2,20 @@
; Ullrich von Bassewitz, 31.05.1998
;
; Note: strspn & strcspn call internally this function and rely on
; the usage of only ptr2 here! Keep in mind when appling changes
; the usage of only ptr4 here! Keep in mind when appling changes
; and check the other implementations too!
;
; size_t __fastcall__ strlen (const char* s);
;
.export _strlen
.importzp ptr2
.export _strlen, _strlen_ptr4
.importzp ptr4
.macpack cpu
_strlen:
sta ptr2 ; Save s
stx ptr2+1
sta ptr4 ; Save s
stx ptr4+1
_strlen_ptr4:
.if (.cpu .bitand ::CPU_ISET_HUC6280)
clx
cly
@ -27,11 +28,11 @@ _strlen:
.endif
.endif
L1: lda (ptr2),y
L1: lda (ptr4),y
beq L9
iny
bne L1
inc ptr2+1
inc ptr4+1
inx
bne L1

View File

@ -7,13 +7,13 @@
.export _strspn
.import popptr1, _strlen
.importzp ptr1, ptr2, tmp1, tmp2
.importzp ptr1, ptr4, tmp1, tmp2
_strspn:
jsr _strlen ; get length in a/x and transfer s2 to ptr2
jsr _strlen ; get length in a/x and transfer s2 to ptr4
; Note: It does not make sense to
; have more than 255 test chars, so
; we don't support a high byte here! (ptr2+1 is
; we don't support a high byte here! (ptr4+1 is
; also unchanged in strlen then (important!))
; -> the original implementation also
; ignored this case
@ -38,7 +38,7 @@ checkNext:
iny
check: cpy tmp1 ; compare with length of test character string
beq leave
cmp (ptr2),y ; found matching char?
cmp (ptr4),y ; found matching char?
bne checkNext
foundTestChar: