strings.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2000 by Jonas Maebe, member of the
  5. Free Pascal development team
  6. Processor dependent part of strings.pp, that can be shared with
  7. sysutils unit.
  8. See the file COPYING.FPC, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************}
  14. { Note: the implementation of these routines is for BIG ENDIAN only!! (JM) }
  15. function strcopy(dest,source : pchar) : pchar;assembler;
  16. { in: dest in r3, source in r4 }
  17. { out: result (dest) in r3 }
  18. asm
  19. { empty/invalid string? }
  20. cmpli r3,0
  21. { if yes, do nothing }
  22. beq .LStrCopyDone
  23. { clear two lowest bits of source address }
  24. rlwminm r28,r4,0,0,31-2
  25. { get # of misaligned bytes }
  26. sub. r28,r28,r4
  27. { since we have to return dest intact, use another register for }
  28. { dest in the copy loop }
  29. mr r29,r3
  30. beq .LStrCopyAligned
  31. .LStrCopyAlignLoop:
  32. { decrease misaligned bytes counter (do it here already to improve }
  33. { jump prediction) }
  34. subic. r28,1
  35. { load next byte }
  36. lbz r27,(r4)
  37. { end of string? }
  38. cmpli cr1,r27,0
  39. { point to next source byte }
  40. addi r4,r4,1
  41. { store byte }
  42. stb r27,(r29)
  43. { point to next dest address }
  44. addi r29,r29,1
  45. { stop if end of string }
  46. beq cr1,.LStrCopyDone
  47. bne .LStrCopyAlignLoop
  48. .balign 16
  49. .LStrCopyAligned:
  50. { load next 4 bytes }
  51. lwz r27,(r4)
  52. { first/highest byte zero? (big endian!) }
  53. andis. r28,r27,0x0ff00
  54. addi r4,r4,4
  55. beq .LStrCopyByte
  56. { second byte zero? }
  57. andis. r28,r27,0x00ff
  58. beq .LStrCopyWord
  59. { third byte zero? }
  60. andi. r28,r27,0xff00
  61. beq .LStrCopy3Bytes
  62. { fourth byte zero? }
  63. andi. r28,r27,0x00ff
  64. { store next 4 bytes }
  65. stw r27,(r29)
  66. { increase dest address }
  67. addi r29,r29,4
  68. beq .LStrCopyDone
  69. b .LStrCopyAligned
  70. { store left-overs }
  71. .LStrCopy3Bytes:
  72. sth r27,(r29)
  73. li r27,0
  74. stb r27,2(r29)
  75. b .LStrCopyDone
  76. .LStrCopyWord:
  77. sth r27,(r29)
  78. b .LStrCopyDone
  79. .LStrCopyByte:
  80. stb r27,(r29)
  81. .LStrCopyDone:
  82. { r3 still contains dest here }
  83. end ['r4','r27','r28','r29','cr0','cr1'];
  84. function strecopy(dest,source : pchar) : pchar;assembler;
  85. { in: dest in r3, source in r4 }
  86. { out: result (end of new dest) in r3 }
  87. asm
  88. { empty/invalid string? }
  89. cmpli r3,0
  90. { if yes, do nothing }
  91. beq .LStreCopyDone
  92. { clear two lowest bits of source address }
  93. rlwminm r28,r4,0,0,31-2
  94. { get # of misaligned bytes }
  95. sub. r28,r28,r4
  96. beq .LStreCopyAligned
  97. .LStreCopyAlignLoop:
  98. { decrease misaligned bytes counter (do it here already to improve }
  99. { jump prediction) }
  100. subic. r28,1
  101. { load next byte }
  102. lbz r27,(r4)
  103. { end of string? }
  104. cmpli cr1,r27,0
  105. { point to next source byte }
  106. addi r4,r4,1
  107. { store byte }
  108. stb r27,(r3)
  109. { stop if end of string }
  110. beq cr1,.LStreCopyDone
  111. { point to next dest address }
  112. addi r3,r3,1
  113. { loop if misaligned bytes left }
  114. bne .LStreCopyAlignLoop
  115. .balign 16
  116. .LStreCopyAligned:
  117. { load next 4 bytes }
  118. lwz r27,(r4)
  119. { first/highest byte zero? (big endian!) }
  120. andis. r28,r27,0x0ff00
  121. addi r4,r4,4
  122. beq .LStreCopyByte
  123. { second byte zero? }
  124. andis. r28,r27,0x00ff
  125. beq .LStreCopyWord
  126. { third byte zero? }
  127. andi. r28,r27,0xff00
  128. beq .LStreCopy3Bytes
  129. { fourth byte zero? }
  130. andi. r28,r27,0x00ff
  131. { store next 4 bytes }
  132. stw r27,(r3)
  133. { increase dest address }
  134. { the result must point to the terminating #0, so only add 3 }
  135. addi r3,r3,3
  136. beq .LStreCopyDone
  137. { add another 1 for next char }
  138. addi r3,r3,1
  139. b .LStreCopyAligned
  140. { store left-overs }
  141. .LStreCopy3Bytes:
  142. sth r27,(r3)
  143. li r27,0
  144. stbu r27,2(r3)
  145. b .LStrCopyDone
  146. .LStreCopyWord:
  147. sth r27,(r3)
  148. addi r3,r3,1
  149. b .LStrCopyDone
  150. .LStreCopyByte:
  151. stb r27,(r3)
  152. .LStreCopyDone:
  153. { r3 contains end of new string now }
  154. end ['r3','r4','r27','r28','cr0','cr1'];
  155. function strlcopy(dest,source : pchar;maxlen : longint) : pchar;assembler;
  156. asm
  157. { in: dest in r3, source in r4, maxlen in r5 }
  158. { out: result (dest) in r3 }
  159. asm
  160. { empty/invalid string? }
  161. cmpli r3,0
  162. { if yes, do nothing }
  163. beq .LStrlCopyDone
  164. { maxlen in counter }
  165. mtctr r5
  166. { clear two lowest bits of source address }
  167. rlwminm r28,r4,0,0,31-2
  168. { get # of misaligned bytes }
  169. sub. r28,r28,r4
  170. { since we have to return dest intact, use another register for }
  171. { dest in the copy loop }
  172. mr r29,r3
  173. beq .LStrlCopyAligned
  174. .LStrlCopyAlignLoop:
  175. { if decreased maxlen counter = 0 (dz), stop }
  176. bdz .LStrlCopyByte
  177. { decrease misaligned bytes counter (do it here already to improve }
  178. { jump prediction) }
  179. subic. r28,1
  180. { load next byte }
  181. lbz r27,(r4)
  182. { end of string? }
  183. cmpli cr1,r27,0
  184. { point to next source byte }
  185. addi r4,r4,1
  186. { store byte }
  187. stb r27,(r29)
  188. { point to next dest address }
  189. addi r29,r29,1
  190. { stop if end of string }
  191. beq cr1,.LStrlCopyDone
  192. { loop while unaligned byte counter <> 0 }
  193. bne .LStrlCopyAlignLoop
  194. .balign 16
  195. .LStrlCopyAligned:
  196. { load next 4 bytes }
  197. lwz r27,(r4)
  198. { first/highest byte zero? (big endian!) }
  199. andis. r28,r27,0x0ff00
  200. addi r4,r4,4
  201. { if decremented maxlen counter not zero (dnz) and no #0 (ne), }
  202. { continue (and hint that the most likely case is jump taken) }
  203. bdnzne+ .LNoStrlCopyByte
  204. b .LStrlCopyByte
  205. .LNoStrlCopyByte:
  206. { second byte zero? }
  207. andis. r28,r27,0x00ff
  208. bdnzne+ .LNoStrlCopyWord
  209. b .LStrlCopyWord
  210. .LNoStrlCopyWord:
  211. { third byte zero? }
  212. andi. r28,r27,0xff00
  213. bdnzne+ .LNoStrlCopy3Bytes
  214. b .LStrlCopy3Bytes
  215. .LNoStrlCopy3Bytes:
  216. { fourth byte zero? }
  217. andi. r28,r27,0x00ff
  218. { store next 4 bytes }
  219. stw r27,(r29)
  220. { increase dest address }
  221. addi r29,r29,4
  222. bdnzne .LStrlCopyAligned
  223. { replace last char with a #0 in case we stopped because the maxlen }
  224. { was reached }
  225. li r27,0
  226. stb r27,-1(r29)
  227. b .LStrlCopyDone
  228. { store left-overs }
  229. .LStrlCopy3Bytes:
  230. { big endian! So move upper 16bits to lower 16bits}
  231. srwi r27,r27,16
  232. sth r27,(r29)
  233. li r27,0
  234. stb r27,2(r29)
  235. b .LStrlCopyDone
  236. .LStrlCopyWord:
  237. { clear lower 8 bits of low 16 bits }
  238. andi r27,r27,0x0ff00
  239. sth r27,(r29)
  240. b .LStrlCopyDone
  241. .LStrlCopyByte:
  242. li r27,0
  243. stb r27,(r29)
  244. .LStrlCopyDone:
  245. { r3 still contains dest here }
  246. end ['r4','r27','r28','r29','cr0','cr1','ctr'];
  247. function strlen(p : pchar) : longint;assembler;
  248. { in: p in r3 }
  249. { out: result (length) in r3 }
  250. { WARNING: if the used registers change here, also change strend!! (JM) }
  251. asm
  252. { empty/invalid string? }
  253. cmpli r3,0
  254. { if yes, do nothing }
  255. beq .LStrLenNil
  256. { clear two lowest bits of source address }
  257. rlwminm r28,r3,0,0,31-2
  258. { get # of misaligned bytes }
  259. sub. r28,r28,r3
  260. { at the end, we substract r29 from r3 to get the length }
  261. mr r29,r3
  262. beq .LStrLenAligned
  263. .LStrLenAlignLoop:
  264. { decrease misaligned bytes counter (do it here already to improve }
  265. { jump prediction) }
  266. subic. r28,1
  267. { load next byte }
  268. lbz r27,(r3)
  269. { end of string? }
  270. cmpli cr1,r27,0
  271. { stop if end of string }
  272. beq cr1,.LStrLenDone
  273. { point to next source byte }
  274. addi r3,r3,1
  275. bne .LStrLenAlignLoop
  276. .balign 16
  277. .LStrLenAligned:
  278. { load next 4 bytes }
  279. lwz r27,(r3)
  280. { first/highest byte zero? (big endian!) }
  281. andis. r28,r27,0x0ff00
  282. beq .LStrLenDone
  283. { second byte zero? }
  284. andis. r28,r27,0x00ff
  285. { increase length }
  286. addi r3,r3,1
  287. beq .LStrLenDone
  288. { third byte zero? }
  289. andi. r28,r27,0xff00
  290. addi r3,r3,1
  291. beq .LStrLenDone
  292. { fourth byte zero? }
  293. andi. r28,r27,0x00ff
  294. addi r3,r3,1
  295. beq .LStrLenDone
  296. addi r3,r3,1
  297. b .LStrLenAligned
  298. .LStrLenDone:
  299. sub r3,r29,r3
  300. .LStrLenNil:
  301. end ['r3','r27','r28','r29','cr0','cr1'];
  302. function strend(p : pchar) : pchar;assembler;
  303. asm
  304. mr r26,r3
  305. mflr r25
  306. bl strlen
  307. mtlr r25
  308. add r3,r26,r3
  309. end ['r3','r25','r26','r27','r28','r29','cr0','cr1'];
  310. function strcomp(str1,str2 : pchar) : longint;assembler;
  311. { in: str1 in r3, str2 in r4 }
  312. { out: result (= 0 if strings equal, < 0 if str1 < str2, > 0 if str1 > str2 }
  313. { in r3 }
  314. asm
  315. { !!! }
  316. end;
  317. function strlcomp(str1,str2 : pchar;l : longint) : longint;assembler;
  318. { (same as strcomp, but maximally compare until l'th character) }
  319. { in: str1 in r3, str2 in r4, l in r5 }
  320. { out: result (= 0 if strings equal, < 0 if str1 < str2, > 0 if str1 > str2 }
  321. { in r3 }
  322. asm
  323. { !!! }
  324. end;
  325. function stricomp(str1,str2 : pchar) : longint;assembler;
  326. { in: str1 in r3, str2 in r4 }
  327. { out: result (= index of first differing character) in r3 }
  328. asm
  329. { !!! }
  330. end;
  331. function strlicomp(str1,str2 : pchar;l : longint) : longint;assembler;
  332. { (same as stricomp, but maximally compare until l'th character) }
  333. { in: str1 in r3, str2 in r4, l in r5 }
  334. { out: result (= index of first differing character) in r3 }
  335. asm
  336. { !!! }
  337. end;
  338. function strscan(p : pchar;c : char) : pchar;assembler;
  339. asm
  340. movl p,%eax
  341. xorl %ecx,%ecx
  342. testl %eax,%eax
  343. jz .LSTRSCAN
  344. // align
  345. movb c,%cl
  346. movl %eax,%esi
  347. andl $0xfffffff8,%eax
  348. movl $0xff,%edx
  349. movl p,%edi
  350. subl %eax,%esi
  351. jz .LSTRSCANLOOP
  352. xorl %eax,%eax
  353. .LSTRSCANALIGNLOOP:
  354. movb (%edi),%al
  355. // at .LSTRSCANFOUND, one is substracted from edi to calculate the position,
  356. // so add 1 here already (not after .LSTRSCAN, because then the test/jz and
  357. // cmp/je can't be paired)
  358. incl %edi
  359. testb %al,%al
  360. jz .LSTRSCAN
  361. cmpb %cl,%al
  362. je .LSTRSCANFOUND
  363. decl %esi
  364. jnz .LSTRSCANALIGNLOOP
  365. jmp .LSTRSCANLOOP
  366. .balign 16
  367. .LSTRSCANLOOP:
  368. movl (%edi),%eax
  369. movl %eax,%esi
  370. // first char
  371. andl %edx,%eax
  372. // end of string -> stop
  373. jz .LSTRSCAN
  374. shrl $8,%esi
  375. cmpl %ecx,%eax
  376. movl %esi,%eax
  377. je .LSTRSCANFOUND1
  378. // second char
  379. andl %edx,%eax
  380. jz .LSTRSCAN
  381. shrl $8,%esi
  382. cmpl %ecx,%eax
  383. movl %esi,%eax
  384. je .LSTRSCANFOUND2
  385. // third char
  386. andl %edx,%eax
  387. jz .LSTRSCAN
  388. shrl $8,%esi
  389. cmpl %ecx,%eax
  390. movl %esi,%eax
  391. je .LSTRSCANFOUND3
  392. // fourth char
  393. // all upper bits have already been cleared
  394. testl %eax,%eax
  395. jz .LSTRSCAN
  396. addl $4,%edi
  397. cmpl %ecx,%eax
  398. je .LSTRSCANFOUND
  399. jmp .LSTRSCANLOOP
  400. .LSTRSCANFOUND3:
  401. leal 2(%edi),%eax
  402. jmp .LSTRSCAN
  403. .LSTRSCANFOUND2:
  404. leal 1(%edi),%eax
  405. jmp .LSTRSCAN
  406. .LSTRSCANFOUND1:
  407. movl %edi,%eax
  408. jmp .LSTRSCAN
  409. .LSTRSCANFOUND:
  410. leal -1(%edi),%eax
  411. .LSTRSCAN:
  412. end ['EAX','ECX','ESI','EDI','EDX'];
  413. function strrscan(p : pchar;c : char) : pchar;assembler;
  414. asm
  415. xorl %eax,%eax
  416. movl p,%edi
  417. orl %edi,%edi
  418. jz .LSTRRSCAN
  419. movl $0xffffffff,%ecx
  420. cld
  421. xorb %al,%al
  422. repne
  423. scasb
  424. not %ecx
  425. movb c,%al
  426. movl p,%edi
  427. addl %ecx,%edi
  428. decl %edi
  429. std
  430. repne
  431. scasb
  432. cld
  433. movl $0,%eax
  434. jnz .LSTRRSCAN
  435. movl %edi,%eax
  436. incl %eax
  437. .LSTRRSCAN:
  438. end ['EAX','ECX','EDI'];
  439. function strupper(p : pchar) : pchar;assembler;
  440. asm
  441. movl p,%esi
  442. orl %esi,%esi
  443. jz .LStrUpperNil
  444. movl %esi,%edi
  445. .LSTRUPPER1:
  446. lodsb
  447. cmpb $97,%al
  448. jb .LSTRUPPER3
  449. cmpb $122,%al
  450. ja .LSTRUPPER3
  451. subb $0x20,%al
  452. .LSTRUPPER3:
  453. stosb
  454. orb %al,%al
  455. jnz .LSTRUPPER1
  456. .LStrUpperNil:
  457. movl p,%eax
  458. end ['EAX','ESI','EDI'];
  459. function strlower(p : pchar) : pchar;assembler;
  460. asm
  461. movl p,%esi
  462. orl %esi,%esi
  463. jz .LStrLowerNil
  464. movl %esi,%edi
  465. .LSTRLOWER1:
  466. lodsb
  467. cmpb $65,%al
  468. jb .LSTRLOWER3
  469. cmpb $90,%al
  470. ja .LSTRLOWER3
  471. addb $0x20,%al
  472. .LSTRLOWER3:
  473. stosb
  474. orb %al,%al
  475. jnz .LSTRLOWER1
  476. .LStrLowerNil:
  477. movl p,%eax
  478. end ['EAX','ESI','EDI'];
  479. {
  480. $Log$
  481. Revision 1.1 2000-11-05 17:17:08 jonas
  482. + first implementation, not yet finished
  483. }