123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- {
- 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) }
- {$ifndef FPC_UNIT_HAS_STRCOPY}
- {$define FPC_UNIT_HAS_STRCOPY}
- function strcopy(dest,source : pchar) : pchar;assembler;
- { in: dest in r3, source in r4 }
- { out: result (dest) in r3 }
- asm
- { in: dest in r3, source in r4 }
- { out: result (dest) in r3 }
- { load the begin of the source string in the data cache }
- dcbt 0,r4
- { get # of misaligned bytes }
- rlwinm. r10,r4,0,31-2+1,31
- subfic r10,r10,4
- mtctr r10
- { since we have to return dest intact, use another register for }
- { dest in the copy loop }
- subi r9,r3,1
- subi r4,r4,1
- beq .LStrCopyAligned
- .LStrCopyAlignLoop:
- { load next byte }
- lbzu r0,1(r4)
- { end of string? }
- cmplwi cr0,r0,0
- { store byte }
- stbu r0,1(r9)
- { loop if misaligned bytes left and not end of string found }
- bdnzf cr0*4+eq,.LStrCopyAlignLoop
- beq .LStrCopyDone
- .LStrCopyAligned:
- subi r4,r4,3
- subi r9,r9,3
- { setup magic constants }
- {$ifdef macos}
- { load constant 0xfefefeff }
- lis r8,0xfefe
- ori r8,r8,0xfeff
- { load constant 0x80808080}
- lis r7,0x8080
- ori r7,r7,0x8080
- {$else}
- lis r8,(0xfefefeff)@ha
- addi r8,r8,(0xfefefeff)@l
- lis r7,(0x80808080)@ha
- addi r7,r7,(0x80808080)@l
- {$endif}
- { load first 4 bytes }
- lwzu r0,4(r4)
- .LStrCopyAlignedLoop:
- { test for zero byte }
- add r10,r0,r8
- andc r10,r10,r0
- and. r10,r10,r7
- bne .LStrCopyEndFound
- stwu r0,4(r9)
- { load next 4 bytes (do it here so the load can begin while the }
- { the branch is processed) }
- lwzu r0,4(r4)
- b .LStrCopyAlignedLoop
- .LStrCopyEndFound:
- { adjust for possible $01 bytes coming before the terminating 0 byte }
- rlwinm r8,r0,7,0,31
- andc r10,r10,r8
- { result is either 0, 8, 16 or 24 depending on which byte is zero }
- cntlzw r10,r10
- addi r9,r9,3
- .LStrCopyWrapUpLoop:
- subic. r10,r10,8
- rlwinm r0,r0,8,0,31
- stbu r0,1(r9)
- bge .LStrCopyWrapUpLoop
- .LStrCopyDone:
- { r3 still contains dest here }
- end;
- {$endif FPC_UNIT_HAS_STRCOPY}
- {$ifndef FPC_UNIT_HAS_STRECOPY}
- {$define FPC_UNIT_HAS_STRECOPY}
- function strecopy(dest,source : pchar) : pchar;assembler;
- { in: dest in r3, source in r4 }
- { out: result (end of new dest) in r3 }
- asm
- { load the begin of the source string in the data cache }
- dcbt 0,r4
- { get # of misaligned bytes }
- rlwinm. r10,r4,0,31-2+1,31
- subfic r10,r10,4
- mtctr r10
- subi r3,r3,1
- subi r4,r4,1
- beq .LStrECopyAligned
- .LStrECopyAlignLoop:
- { load next byte }
- lbzu r0,1(r4)
- { end of string? }
- cmplwi cr0,r0,0
- { store byte }
- stbu r0,1(r3)
- { loop if misaligned bytes left and not end of string found }
- bdnzf cr0*4+eq,.LStrECopyAlignLoop
- beq .LStrECopyDone
- .LStrECopyAligned:
- subi r4,r4,3
- subi r3,r3,3
- { setup magic constants }
- {$ifdef macos}
- { load constant 0xfefefeff }
- lis r8,0xfefe
- ori r8,r8,0xfeff
- { load constant 0x80808080}
- lis r7,0x8080
- ori r7,r7,0x8080
- {$else}
- lis r8,(0xfefefeff)@ha
- addi r8,r8,(0xfefefeff)@l
- lis r7,(0x80808080)@ha
- addi r7,r7,(0x80808080)@l
- {$endif}
- .LStrECopyAlignedLoop:
- { load next 4 bytes }
- lwzu r0,4(r4)
- { test for zero byte }
- add r10,r0,r8
- andc r10,r10,r0
- and. r10,r10,r7
- bne .LStrECopyEndFound
- stwu r0,4(r3)
- b .LStrECopyAlignedLoop
- .LStrECopyEndFound:
- { adjust for possible $01 bytes coming before the terminating 0 byte }
- rlwinm r8,r0,7,0,31
- andc r10,r10,r8
- { result is either 0, 8, 16 or 24 depending on which byte is zero }
- cntlzw r10,r10
- addi r3,r3,3
- .LStrECopyWrapUpLoop:
- subic. r10,r10,8
- rlwinm r0,r0,8,0,31
- stbu r0,1(r3)
- bge .LStrECopyWrapUpLoop
- .LStrECopyDone:
- { r3 contains new dest here }
- end;
- {$endif FPC_UNIT_HAS_STRECOPY}
- {$ifndef FPC_UNIT_HAS_STRLCOPY}
- {$define FPC_UNIT_HAS_STRLCOPY}
- function strlcopy(dest,source : pchar;maxlen : longint) : pchar;assembler;
- { in: dest in r3, source in r4, maxlen in r5 }
- { out: result (dest) in r3 }
- asm
- { load the begin of the source string in the data cache }
- dcbt 0,r4
- mtctr r5
- subi r4,r4,1
- subi r10,r3,1
- .LStrlCopyLoop:
- lbzu r0,1(r4)
- cmplwi r0,0
- stbu r0,1(r10)
- bdnzf cr0*4+eq, .LStrlCopyLoop
- { if we stopped because we copied a #0, we're done }
- beq .LStrlCopyDone
- { otherwise add the #0 }
- li r0,0
- stb r0,1(r10)
- .LStrlCopyDone:
- end;
- {$endif FPC_UNIT_HAS_STRLCOPY}
- {$ifndef FPC_UNIT_HAS_STREND}
- {$define FPC_UNIT_HAS_STREND}
- function strend(p : pchar) : pchar;assembler;
- { in: p in r3 }
- { out: result (end of p) in r3 }
- asm
- { load the begin of the string in the data cache }
- dcbt 0,r3
- { empty/invalid string? }
- cmplwi r3,0
- { if yes, do nothing }
- beq .LStrEndDone
- subi r3,r3,1
- .LStrEndLoop:
- lbzu r0,1(r3)
- cmplwi r0,0
- bne .LStrEndLoop
- .LStrEndDone:
- end;
- {$endif FPC_UNIT_HAS_STREND}
- {$ifndef FPC_UNIT_HAS_STRCOMP}
- {$define FPC_UNIT_HAS_STRCOMP}
- 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
- { use r0 instead of r3 for str1 since r3 contains result }
- subi r9,r3,1
- subi r4,r4,1
- .LStrCompLoop:
- { load next chars }
- lbzu r0,1(r9)
- { check if one is zero }
- cmplwi cr1,r0,0
- lbzu r10,1(r4)
- { calculate difference }
- sub. r3,r0,r10
- { if chars not equal, we're ready }
- bne .LStrCompDone
- { if they are equal and one is zero, then the other one is zero too }
- { and we're done as well (r3 also contains 0 then) }
- { otherwise loop }
- bne cr1,.LStrCompLoop
- .LStrCompDone:
- end;
- {$endif FPC_UNIT_HAS_STRCOMP}
- {$ifndef FPC_UNIT_HAS_STRLCOMP}
- {$define FPC_UNIT_HAS_STRLCOMP}
- 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
- { load the begin of one of the strings in the data cache }
- dcbt 0,r3
- { use r0 instead of r3 for str1 since r3 contains result }
- cmplwi r5,0
- subi r9,r3,1
- li r3,0
- beq .LStrlCompDone
- mtctr r5
- subi r4,r4,1
- .LStrlCompLoop:
- { load next chars }
- lbzu r0,1(r9)
- { check if one is zero }
- cmplwi cr1,r0,0
- lbzu r10,1(r4)
- { calculate difference }
- sub. r3,r0,r10
- { if chars not equal, we're ready }
- bne .LStrlCompDone
- { if they are equal and one is zero, then the other one is zero too }
- { and we're done as well (r3 also contains 0 then) }
- { otherwise loop (if ctr <> 0) }
- bdnzf cr1*4+eq,.LStrlCompLoop
- .LStrlCompDone:
- end;
- {$endif FPC_UNIT_HAS_STRLCOMP}
- {$ifndef FPC_UNIT_HAS_STRICOMP}
- {$define FPC_UNIT_HAS_STRICOMP}
- function stricomp(str1,str2 : pchar) : longint;assembler;
- { in: str1 in r3, str2 in r4 }
- { out: result of case insensitive comparison (< 0, = 0, > 0) }
- asm
- { use r5 instead of r3 for str1 since r3 contains result }
- subi r5,r3,1
- subi r4,r4,1
- .LStriCompLoop:
- { load next chars }
- lbzu r6,1(r5)
- { check if one is zero }
- cmplwi cr1,r6,0
- lbzu r7,1(r4)
- { calculate difference }
- sub. r3,r6,r7
- { if chars are equal, no further test is necessary }
- beq+ .LStriCompEqual
- { make both lowercase, no branches }
- { r3 := pred('A') - r6 }
- subfic r3,r6,64
- { if r6 < 'A' then r8 := 0 else r8 := $ffffffff }
- subfe r8,r8,r8
- { same for r7 }
- subfic r3,r7,64
- subfe r9,r9,r9
- { r3 := r6 - succ('Z') }
- subic r3,r6,91
- { if r6 < 'A' then r8 := 0 else r8 := $20 }
- andi. r8,r8,0x020
- { if r6 > Z then r10 := 0 else r10 := $ffffffff }
- subfe r10,r10,r10
- { same for r7 }
- subic r3,r7,91
- andi. r9,r9,0x020
- subfe r11,r11,r11
- { if (r6 in ['A'..'Z'] then r8 := $20 else r8 := 0 }
- and r8,r8,r10
- { same for r7 }
- and r9,r9,r11
- { make lowercase }
- add r6,r6,r8
- { same for r7 }
- add r7,r7,r9
- { compare again }
- sub. r3,r6,r7
- bne- .LStriCompDone
- .LStriCompEqual:
- { if they are equal and one is zero, then the other one is zero too }
- { and we're done as well (r3 also contains 0 then) }
- { otherwise loop }
- bne cr1,.LStriCompLoop
- .LStriCompDone:
- end;
- {$endif FPC_UNIT_HAS_STRICOMP}
- {$ifndef FPC_UNIT_HAS_STRLICOMP}
- {$define FPC_UNIT_HAS_STRLICOMP}
- 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 of case insensitive comparison (< 0, = 0, > 0) }
- asm
- { load the begin of one of the string in the data cache }
- dcbt 0,r3
- { use r0 instead of r3 for str1 since r3 contains result }
- cmplwi r5,0
- subi r9,r3,1
- li r3,0
- beq- .LStrliCompDone
- mtctr r5
- subi r4,r4,1
- .LStrliCompLoop:
- { load next chars }
- lbzu r0,1(r9)
- { check if one is zero }
- cmplwi cr1,r0,0
- lbzu r10,1(r4)
- { calculate difference }
- sub. r3,r0,r10
- { if chars are equal, no further test is necessary }
- beq .LStrliCompEqual
- { see stricomp for explanation }
- subfic r3,r0,64
- subfe r8,r8,r8
- subfic r3,r10,64
- subfe r5,r5,r5
- subic r3,r0,91
- andi. r8,r8,0x020
- subfe r7,r7,r7
- subic r3,r10,91
- andi. r5,r5,0x020
- subfe r11,r11,r11
- and r8,r8,r7
- and r5,r5,r11
- add r0,r0,r8
- add r10,r10,r5
- { compare again }
- sub. r3,r0,r10
- bne .LStrliCompDone
- .LStrliCompEqual:
- { if they are equal and one is zero, then the other one is zero too }
- { and we're done as well (r3 also contains 0 then) }
- { otherwise loop (if ctr <> 0) }
- bdnzf cr1*4+eq,.LStrliCompLoop
- .LStrliCompDone:
- end;
- {$endif FPC_UNIT_HAS_STRLICOMP}
- {$ifndef FPC_UNIT_HAS_STRSCAN}
- {$define FPC_UNIT_HAS_STRSCAN}
- function strscan(p : pchar;c : char) : pchar;assembler;
- asm
- { empty/invalid string? }
- cmplwi r3,0
- { if yes, do nothing }
- beq .LStrScanDone
- subi r3,r3,1
- .LStrScanLoop:
- lbzu r0,1(r3)
- cmplw cr1,r0,r4
- cmplwi r0,0
- beq cr1,.LStrScanDone
- bne .LStrScanLoop
- li r3, 0
- .LStrScanDone:
- end;
- {$endif FPC_UNIT_HAS_STRSCAN}
- {$ifndef FPC_UNIT_HAS_STRRSCAN}
- {$define FPC_UNIT_HAS_STRRSCAN}
- function strrscan(p : pchar;c : char) : pchar;assembler;
- asm
- { empty/invalid string? }
- cmplwi r3,0
- { if yes, do nothing }
- beq .LStrrScanDone
- { make r5 will be walking through the string }
- subi r5,r3,1
- { assume not found }
- li r3,0
- .LStrrScanLoop:
- lbzu r10,1(r5)
- cmplw cr1,r10,r4
- cmplwi cr0,r10,0
- bne+ cr1,.LStrrScanNotFound
- { store address of found position }
- mr r3,r5
- .LStrrScanNotFound:
- bne .LStrrScanLoop
- .LStrrScanDone:
- end;
- {$endif FPC_UNIT_HAS_STRRSCAN}
- {$ifndef FPC_UNIT_HAS_STRUPPER}
- {$define FPC_UNIT_HAS_STRUPPER}
- function strupper(p : pchar) : pchar;assembler;
- asm
- cmplwi r3,0
- beq .LStrUpperNil
- subi r9,r3,1
- .LStrUpperLoop:
- lbzu r10,1(r9)
- { a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
- subi r0,r10,97
- cmplwi r0,122-97
- cmplwi cr1,r10,0
- subi r10,r10,0x20
- bgt .LStrUpper1
- stb r10,0(r9)
- .LStrUpper1:
- bne cr1,.LStrUpperLoop
- .LStrUpperNil:
- end;
- {$endif FPC_UNIT_HAS_STRUPPER}
- {$ifndef FPC_UNIT_HAS_STRLOWER}
- {$define FPC_UNIT_HAS_STRLOWER}
- function strlower(p : pchar) : pchar;assembler;
- asm
- cmplwi r3,0
- beq .LStrLowerNil
- subi r9,r3,1
- .LStrLowerLoop:
- lbzu r10,1(r9)
- { a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
- subi r0,r10,65
- cmplwi r0,90-65
- cmplwi cr1,r10,0
- addi r10,r10,0x20
- bgt .LStrLower1
- stb r10,0(r9)
- .LStrLower1:
- bne cr1,.LStrLowerLoop
- .LStrLowerNil:
- end;
- {$endif FPC_UNIT_HAS_STRLOWER}
|