123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- {
- $Id$
- This file is part of the Free Pascal run time library.
- Copyright (c) 2000 by Jonas Maebe, member of the
- Free Pascal development team
- Processor dependent part of strings.pp, that can be shared with
- sysutils unit.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- { Note: the implementation of these routines is for BIG ENDIAN only!! (JM) }
- function strcopy(dest,source : pchar) : pchar;assembler;
- { in: dest in r3, source in r4 }
- { out: result (dest) in r3 }
- asm
- { empty/invalid string? }
- cmpli r3,0
- { if yes, do nothing }
- beq .LStrCopyDone
- { clear two lowest bits of source address }
- rlwminm r28,r4,0,0,31-2
- { get # of misaligned bytes }
- sub. r28,r28,r4
- { since we have to return dest intact, use another register for }
- { dest in the copy loop }
- mr r29,r3
- beq .LStrCopyAligned
- .LStrCopyAlignLoop:
- { decrease misaligned bytes counter (do it here already to improve }
- { jump prediction) }
- subic. r28,1
- { load next byte }
- lbz r27,(r4)
- { end of string? }
- cmpli cr1,r27,0
- { point to next source byte }
- addi r4,r4,1
- { store byte }
- stb r27,(r29)
- { point to next dest address }
- addi r29,r29,1
- { stop if end of string }
- beq cr1,.LStrCopyDone
- bne .LStrCopyAlignLoop
- .balign 16
- .LStrCopyAligned:
- { load next 4 bytes }
- lwz r27,(r4)
- { first/highest byte zero? (big endian!) }
- andis. r28,r27,0x0ff00
- addi r4,r4,4
- beq .LStrCopyByte
- { second byte zero? }
- andis. r28,r27,0x00ff
- beq .LStrCopyWord
- { third byte zero? }
- andi. r28,r27,0xff00
- beq .LStrCopy3Bytes
- { fourth byte zero? }
- andi. r28,r27,0x00ff
- { store next 4 bytes }
- stw r27,(r29)
- { increase dest address }
- addi r29,r29,4
- beq .LStrCopyDone
- b .LStrCopyAligned
- { store left-overs }
- .LStrCopy3Bytes:
- sth r27,(r29)
- li r27,0
- stb r27,2(r29)
- b .LStrCopyDone
- .LStrCopyWord:
- sth r27,(r29)
- b .LStrCopyDone
- .LStrCopyByte:
- stb r27,(r29)
- .LStrCopyDone:
- { r3 still contains dest here }
- end ['r4','r27','r28','r29','cr0','cr1'];
- function strecopy(dest,source : pchar) : pchar;assembler;
- { in: dest in r3, source in r4 }
- { out: result (end of new dest) in r3 }
- asm
- { empty/invalid string? }
- cmpli r3,0
- { if yes, do nothing }
- beq .LStreCopyDone
- { clear two lowest bits of source address }
- rlwminm r28,r4,0,0,31-2
- { get # of misaligned bytes }
- sub. r28,r28,r4
- beq .LStreCopyAligned
- .LStreCopyAlignLoop:
- { decrease misaligned bytes counter (do it here already to improve }
- { jump prediction) }
- subic. r28,1
- { load next byte }
- lbz r27,(r4)
- { end of string? }
- cmpli cr1,r27,0
- { point to next source byte }
- addi r4,r4,1
- { store byte }
- stb r27,(r3)
- { stop if end of string }
- beq cr1,.LStreCopyDone
- { point to next dest address }
- addi r3,r3,1
- { loop if misaligned bytes left }
- bne .LStreCopyAlignLoop
- .balign 16
- .LStreCopyAligned:
- { load next 4 bytes }
- lwz r27,(r4)
- { first/highest byte zero? (big endian!) }
- andis. r28,r27,0x0ff00
- addi r4,r4,4
- beq .LStreCopyByte
- { second byte zero? }
- andis. r28,r27,0x00ff
- beq .LStreCopyWord
- { third byte zero? }
- andi. r28,r27,0xff00
- beq .LStreCopy3Bytes
- { fourth byte zero? }
- andi. r28,r27,0x00ff
- { store next 4 bytes }
- stw r27,(r3)
- { increase dest address }
- { the result must point to the terminating #0, so only add 3 }
- addi r3,r3,3
- beq .LStreCopyDone
- { add another 1 for next char }
- addi r3,r3,1
- b .LStreCopyAligned
- { store left-overs }
- .LStreCopy3Bytes:
- sth r27,(r3)
- li r27,0
- stbu r27,2(r3)
- b .LStrCopyDone
- .LStreCopyWord:
- sth r27,(r3)
- addi r3,r3,1
- b .LStrCopyDone
- .LStreCopyByte:
- stb r27,(r3)
- .LStreCopyDone:
- { r3 contains end of new string now }
- end ['r3','r4','r27','r28','cr0','cr1'];
- function strlcopy(dest,source : pchar;maxlen : longint) : pchar;assembler;
- asm
- { in: dest in r3, source in r4, maxlen in r5 }
- { out: result (dest) in r3 }
- asm
- { empty/invalid string? }
- cmpli r3,0
- { if yes, do nothing }
- beq .LStrlCopyDone
- { maxlen in counter }
- mtctr r5
- { clear two lowest bits of source address }
- rlwminm r28,r4,0,0,31-2
- { get # of misaligned bytes }
- sub. r28,r28,r4
- { since we have to return dest intact, use another register for }
- { dest in the copy loop }
- mr r29,r3
- beq .LStrlCopyAligned
- .LStrlCopyAlignLoop:
- { if decreased maxlen counter = 0 (dz), stop }
- bdz .LStrlCopyByte
- { decrease misaligned bytes counter (do it here already to improve }
- { jump prediction) }
- subic. r28,1
- { load next byte }
- lbz r27,(r4)
- { end of string? }
- cmpli cr1,r27,0
- { point to next source byte }
- addi r4,r4,1
- { store byte }
- stb r27,(r29)
- { point to next dest address }
- addi r29,r29,1
- { stop if end of string }
- beq cr1,.LStrlCopyDone
- { loop while unaligned byte counter <> 0 }
- bne .LStrlCopyAlignLoop
- .balign 16
- .LStrlCopyAligned:
- { load next 4 bytes }
- lwz r27,(r4)
- { first/highest byte zero? (big endian!) }
- andis. r28,r27,0x0ff00
- addi r4,r4,4
- { if decremented maxlen counter not zero (dnz) and no #0 (ne), }
- { continue (and hint that the most likely case is jump taken) }
- bdnzne+ .LNoStrlCopyByte
- b .LStrlCopyByte
- .LNoStrlCopyByte:
- { second byte zero? }
- andis. r28,r27,0x00ff
- bdnzne+ .LNoStrlCopyWord
- b .LStrlCopyWord
- .LNoStrlCopyWord:
- { third byte zero? }
- andi. r28,r27,0xff00
- bdnzne+ .LNoStrlCopy3Bytes
- b .LStrlCopy3Bytes
- .LNoStrlCopy3Bytes:
- { fourth byte zero? }
- andi. r28,r27,0x00ff
- { store next 4 bytes }
- stw r27,(r29)
- { increase dest address }
- addi r29,r29,4
- bdnzne .LStrlCopyAligned
- { replace last char with a #0 in case we stopped because the maxlen }
- { was reached }
- li r27,0
- stb r27,-1(r29)
- b .LStrlCopyDone
- { store left-overs }
- .LStrlCopy3Bytes:
- { big endian! So move upper 16bits to lower 16bits}
- srwi r27,r27,16
- sth r27,(r29)
- li r27,0
- stb r27,2(r29)
- b .LStrlCopyDone
- .LStrlCopyWord:
- { clear lower 8 bits of low 16 bits }
- andi r27,r27,0x0ff00
- sth r27,(r29)
- b .LStrlCopyDone
- .LStrlCopyByte:
- li r27,0
- stb r27,(r29)
- .LStrlCopyDone:
- { r3 still contains dest here }
- end ['r4','r27','r28','r29','cr0','cr1','ctr'];
- function strlen(p : pchar) : longint;assembler;
- { in: p in r3 }
- { out: result (length) in r3 }
- { WARNING: if the used registers change here, also change strend!! (JM) }
- asm
- { empty/invalid string? }
- cmpli r3,0
- { if yes, do nothing }
- beq .LStrLenNil
- { clear two lowest bits of source address }
- rlwminm r28,r3,0,0,31-2
- { get # of misaligned bytes }
- sub. r28,r28,r3
- { at the end, we substract r29 from r3 to get the length }
- mr r29,r3
- beq .LStrLenAligned
- .LStrLenAlignLoop:
- { decrease misaligned bytes counter (do it here already to improve }
- { jump prediction) }
- subic. r28,1
- { load next byte }
- lbz r27,(r3)
- { end of string? }
- cmpli cr1,r27,0
- { stop if end of string }
- beq cr1,.LStrLenDone
- { point to next source byte }
- addi r3,r3,1
- bne .LStrLenAlignLoop
- .balign 16
- .LStrLenAligned:
- { load next 4 bytes }
- lwz r27,(r3)
- { first/highest byte zero? (big endian!) }
- andis. r28,r27,0x0ff00
- beq .LStrLenDone
- { second byte zero? }
- andis. r28,r27,0x00ff
- { increase length }
- addi r3,r3,1
- beq .LStrLenDone
- { third byte zero? }
- andi. r28,r27,0xff00
- addi r3,r3,1
- beq .LStrLenDone
- { fourth byte zero? }
- andi. r28,r27,0x00ff
- addi r3,r3,1
- beq .LStrLenDone
- addi r3,r3,1
- b .LStrLenAligned
- .LStrLenDone:
- sub r3,r29,r3
- .LStrLenNil:
- end ['r3','r27','r28','r29','cr0','cr1'];
- function strend(p : pchar) : pchar;assembler;
- asm
- mr r26,r3
- mflr r25
- bl strlen
- mtlr r25
- add r3,r26,r3
- end ['r3','r25','r26','r27','r28','r29','cr0','cr1'];
- function strcomp(str1,str2 : pchar) : longint;assembler;
- { in: str1 in r3, str2 in r4 }
- { out: result (= 0 if strings equal, < 0 if str1 < str2, > 0 if str1 > str2 }
- { in r3 }
- asm
- { !!! }
- end;
- function strlcomp(str1,str2 : pchar;l : longint) : longint;assembler;
- { (same as strcomp, but maximally compare until l'th character) }
- { in: str1 in r3, str2 in r4, l in r5 }
- { out: result (= 0 if strings equal, < 0 if str1 < str2, > 0 if str1 > str2 }
- { in r3 }
- asm
- { !!! }
- end;
- function stricomp(str1,str2 : pchar) : longint;assembler;
- { in: str1 in r3, str2 in r4 }
- { out: result (= index of first differing character) in r3 }
- asm
- { !!! }
- end;
- function strlicomp(str1,str2 : pchar;l : longint) : longint;assembler;
- { (same as stricomp, but maximally compare until l'th character) }
- { in: str1 in r3, str2 in r4, l in r5 }
- { out: result (= index of first differing character) in r3 }
- asm
- { !!! }
- end;
- function strscan(p : pchar;c : char) : pchar;assembler;
- asm
- movl p,%eax
- xorl %ecx,%ecx
- testl %eax,%eax
- jz .LSTRSCAN
- // align
- movb c,%cl
- movl %eax,%esi
- andl $0xfffffff8,%eax
- movl $0xff,%edx
- movl p,%edi
- subl %eax,%esi
- jz .LSTRSCANLOOP
- xorl %eax,%eax
- .LSTRSCANALIGNLOOP:
- movb (%edi),%al
- // at .LSTRSCANFOUND, one is substracted from edi to calculate the position,
- // so add 1 here already (not after .LSTRSCAN, because then the test/jz and
- // cmp/je can't be paired)
- incl %edi
- testb %al,%al
- jz .LSTRSCAN
- cmpb %cl,%al
- je .LSTRSCANFOUND
- decl %esi
- jnz .LSTRSCANALIGNLOOP
- jmp .LSTRSCANLOOP
- .balign 16
- .LSTRSCANLOOP:
- movl (%edi),%eax
- movl %eax,%esi
- // first char
- andl %edx,%eax
- // end of string -> stop
- jz .LSTRSCAN
- shrl $8,%esi
- cmpl %ecx,%eax
- movl %esi,%eax
- je .LSTRSCANFOUND1
- // second char
- andl %edx,%eax
- jz .LSTRSCAN
- shrl $8,%esi
- cmpl %ecx,%eax
- movl %esi,%eax
- je .LSTRSCANFOUND2
- // third char
- andl %edx,%eax
- jz .LSTRSCAN
- shrl $8,%esi
- cmpl %ecx,%eax
- movl %esi,%eax
- je .LSTRSCANFOUND3
- // fourth char
- // all upper bits have already been cleared
- testl %eax,%eax
- jz .LSTRSCAN
- addl $4,%edi
- cmpl %ecx,%eax
- je .LSTRSCANFOUND
- jmp .LSTRSCANLOOP
- .LSTRSCANFOUND3:
- leal 2(%edi),%eax
- jmp .LSTRSCAN
- .LSTRSCANFOUND2:
- leal 1(%edi),%eax
- jmp .LSTRSCAN
- .LSTRSCANFOUND1:
- movl %edi,%eax
- jmp .LSTRSCAN
- .LSTRSCANFOUND:
- leal -1(%edi),%eax
- .LSTRSCAN:
- end ['EAX','ECX','ESI','EDI','EDX'];
- function strrscan(p : pchar;c : char) : pchar;assembler;
- asm
- xorl %eax,%eax
- movl p,%edi
- orl %edi,%edi
- jz .LSTRRSCAN
- movl $0xffffffff,%ecx
- cld
- xorb %al,%al
- repne
- scasb
- not %ecx
- movb c,%al
- movl p,%edi
- addl %ecx,%edi
- decl %edi
- std
- repne
- scasb
- cld
- movl $0,%eax
- jnz .LSTRRSCAN
- movl %edi,%eax
- incl %eax
- .LSTRRSCAN:
- end ['EAX','ECX','EDI'];
- function strupper(p : pchar) : pchar;assembler;
- asm
- movl p,%esi
- orl %esi,%esi
- jz .LStrUpperNil
- movl %esi,%edi
- .LSTRUPPER1:
- lodsb
- cmpb $97,%al
- jb .LSTRUPPER3
- cmpb $122,%al
- ja .LSTRUPPER3
- subb $0x20,%al
- .LSTRUPPER3:
- stosb
- orb %al,%al
- jnz .LSTRUPPER1
- .LStrUpperNil:
- movl p,%eax
- end ['EAX','ESI','EDI'];
- function strlower(p : pchar) : pchar;assembler;
- asm
- movl p,%esi
- orl %esi,%esi
- jz .LStrLowerNil
- movl %esi,%edi
- .LSTRLOWER1:
- lodsb
- cmpb $65,%al
- jb .LSTRLOWER3
- cmpb $90,%al
- ja .LSTRLOWER3
- addb $0x20,%al
- .LSTRLOWER3:
- stosb
- orb %al,%al
- jnz .LSTRLOWER1
- .LStrLowerNil:
- movl p,%eax
- end ['EAX','ESI','EDI'];
- {
- $Log$
- Revision 1.1 2000-11-05 17:17:08 jonas
- + first implementation, not yet finished
- }
|