i386.inc 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. Processor dependent implementation for the system unit for
  5. intel i386+
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {****************************************************************************
  13. Primitives
  14. ****************************************************************************}
  15. var
  16. has_sse_support,has_mmx_support : boolean;
  17. {$asmmode intel}
  18. function cpuid_support : boolean;assembler;
  19. {
  20. Check if the ID-flag can be changed, if changed then CpuID is supported.
  21. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  22. }
  23. asm
  24. push ebx
  25. pushf
  26. pushf
  27. pop eax
  28. mov ebx,eax
  29. xor eax,200000h
  30. push eax
  31. popf
  32. pushf
  33. pop eax
  34. popf
  35. and eax,200000h
  36. and ebx,200000h
  37. cmp eax,ebx
  38. setnz al
  39. pop ebx
  40. end;
  41. {$asmmode ATT}
  42. function sse_support : boolean;
  43. var
  44. _edx : longint;
  45. begin
  46. if cpuid_support then
  47. begin
  48. asm
  49. movl $1,%eax
  50. cpuid
  51. movl %edx,_edx
  52. end;
  53. sse_support:=(_edx and $2000000)<>0;
  54. end
  55. else
  56. { a cpu with without cpuid instruction supports never sse }
  57. sse_support:=false;
  58. end;
  59. { returns true, if the processor supports the mmx instructions }
  60. function mmx_support : boolean;
  61. var
  62. _edx : longint;
  63. begin
  64. if cpuid_support then
  65. begin
  66. asm
  67. movl $1,%eax
  68. cpuid
  69. movl %edx,_edx
  70. end;
  71. mmx_support:=(_edx and $800000)<>0;
  72. end
  73. else
  74. { a cpu with without cpuid instruction supports never mmx }
  75. mmx_support:=false;
  76. end;
  77. {$i fastmove.inc}
  78. procedure fpc_cpuinit;
  79. begin
  80. has_sse_support:=sse_support;
  81. has_mmx_support:=mmx_support;
  82. setup_fastmove;
  83. end;
  84. {$ifndef FPC_SYSTEM_HAS_MOVE}
  85. {$define FPC_SYSTEM_HAS_MOVE}
  86. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];assembler;
  87. var
  88. saveesi,saveedi : longint;
  89. asm
  90. movl %edi,saveedi
  91. movl %esi,saveesi
  92. {$ifdef REGCALL}
  93. movl %eax,%esi
  94. movl %edx,%edi
  95. movl %ecx,%edx
  96. {$else}
  97. movl dest,%edi
  98. movl source,%esi
  99. movl count,%edx
  100. {$endif}
  101. movl %edi,%eax
  102. { check for zero or negative count }
  103. cmpl $0,%edx
  104. jle .LMoveEnd
  105. { Check for back or forward }
  106. sub %esi,%eax
  107. jz .LMoveEnd { Do nothing when source=dest }
  108. jc .LFMove { Do forward, dest<source }
  109. cmp %edx,%eax
  110. jb .LBMove { Dest is in range of move, do backward }
  111. { Forward Copy }
  112. .LFMove:
  113. cld
  114. cmpl $15,%edx
  115. jl .LFMove1
  116. movl %edi,%ecx { Align on 32bits }
  117. negl %ecx
  118. andl $3,%ecx
  119. subl %ecx,%edx
  120. rep
  121. movsb
  122. movl %edx,%ecx
  123. andl $3,%edx
  124. shrl $2,%ecx
  125. rep
  126. movsl
  127. .LFMove1:
  128. movl %edx,%ecx
  129. rep
  130. movsb
  131. jmp .LMoveEnd
  132. { Backward Copy }
  133. .LBMove:
  134. std
  135. addl %edx,%esi
  136. addl %edx,%edi
  137. movl %edi,%ecx
  138. decl %esi
  139. decl %edi
  140. cmpl $15,%edx
  141. jl .LBMove1
  142. negl %ecx { Align on 32bits }
  143. andl $3,%ecx
  144. subl %ecx,%edx
  145. rep
  146. movsb
  147. movl %edx,%ecx
  148. andl $3,%edx
  149. shrl $2,%ecx
  150. subl $3,%esi
  151. subl $3,%edi
  152. rep
  153. movsl
  154. addl $3,%esi
  155. addl $3,%edi
  156. .LBMove1:
  157. movl %edx,%ecx
  158. rep
  159. movsb
  160. cld
  161. .LMoveEnd:
  162. movl saveedi,%edi
  163. movl saveesi,%esi
  164. end;
  165. {$endif FPC_SYSTEM_HAS_MOVE}
  166. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  167. {$define FPC_SYSTEM_HAS_FILLCHAR}
  168. Procedure FillChar(var x;count:SizeInt;value:byte);assembler;
  169. asm
  170. {A push is prefered over a local variable because a local
  171. variable causes the compiler to generate a stackframe.}
  172. cld
  173. {$ifdef REGCALL}
  174. push %edi
  175. movl %eax,%edi
  176. movzbl %cl,%eax
  177. movl %edx,%ecx
  178. {$else}
  179. movl x,%edi
  180. movl count,%ecx
  181. movzbl value,%eax
  182. movl %ecx,%edx
  183. {$endif}
  184. { check for zero or negative count }
  185. or %ecx,%ecx
  186. jle .LFillEnd
  187. cmpl $7,%ecx
  188. jl .LFill1
  189. imul $0x01010101,%eax { Expand al into a 4 subbytes of eax}
  190. shrl $2,%ecx
  191. andl $3,%edx
  192. rep
  193. stosl
  194. movl %edx,%ecx
  195. .LFill1:
  196. rep
  197. stosb
  198. .LFillEnd:
  199. {$ifdef REGCALL}
  200. pop %edi
  201. {$endif}
  202. end;
  203. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  204. {$ifndef FPC_SYSTEM_HAS_FILLWORD}
  205. {$define FPC_SYSTEM_HAS_FILLWORD}
  206. procedure fillword(var x;count : SizeInt;value : word);assembler;
  207. var
  208. saveedi : longint;
  209. asm
  210. movl %edi,saveedi
  211. {$ifdef REGCALL}
  212. movl %eax,%edi
  213. movzwl %cx,%eax
  214. movl %edx,%ecx
  215. {$else}
  216. movl x,%edi
  217. movl count,%ecx
  218. movzwl value,%eax
  219. {$endif}
  220. { check for zero or negative count }
  221. cmpl $0,%ecx
  222. jle .LFillWordEnd
  223. movl %eax,%edx
  224. shll $16,%eax
  225. orl %edx,%eax
  226. movl %ecx,%edx
  227. shrl $1,%ecx
  228. cld
  229. rep
  230. stosl
  231. movl %edx,%ecx
  232. andl $1,%ecx
  233. rep
  234. stosw
  235. .LFillWordEnd:
  236. movl saveedi,%edi
  237. end;
  238. {$endif FPC_SYSTEM_HAS_FILLWORD}
  239. {$ifndef FPC_SYSTEM_HAS_FILLDWORD}
  240. {$define FPC_SYSTEM_HAS_FILLDWORD}
  241. procedure filldword(var x;count : SizeInt;value : dword);assembler;
  242. var
  243. saveedi : longint;
  244. asm
  245. movl %edi,saveedi
  246. {$ifdef REGCALL}
  247. movl %eax,%edi
  248. movl %ecx,%eax
  249. movl %edx,%ecx
  250. {$else}
  251. movl x,%edi
  252. movl count,%ecx
  253. movl value,%eax
  254. {$endif}
  255. { check for zero or negative count }
  256. cmpl $0,%ecx
  257. jle .LFillDWordEnd
  258. cld
  259. rep
  260. stosl
  261. .LFillDWordEnd:
  262. movl saveedi,%edi
  263. end;
  264. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  265. {$ifndef FPC_SYSTEM_HAS_INDEXBYTE}
  266. {$define FPC_SYSTEM_HAS_INDEXBYTE}
  267. function IndexByte(Const buf;len:SizeInt;b:byte):SizeInt; assembler;
  268. var
  269. saveedi,saveebx : longint;
  270. asm
  271. movl %edi,saveedi
  272. movl %ebx,saveebx
  273. movl buf,%edi // Load String
  274. movb b,%bl
  275. movl len,%ecx // Load len
  276. xorl %eax,%eax
  277. testl %ecx,%ecx
  278. jz .Lcharposnotfound
  279. cld
  280. movl %ecx,%edx // Copy for easy manipulation
  281. movb %bl,%al
  282. repne
  283. scasb
  284. jne .Lcharposnotfound
  285. incl %ecx
  286. subl %ecx,%edx
  287. movl %edx,%eax
  288. jmp .Lready
  289. .Lcharposnotfound:
  290. movl $-1,%eax
  291. .Lready:
  292. movl saveedi,%edi
  293. movl saveebx,%ebx
  294. end;
  295. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  296. {$ifndef FPC_SYSTEM_HAS_INDEXWORD}
  297. {$define FPC_SYSTEM_HAS_INDEXWORD}
  298. function Indexword(Const buf;len:SizeInt;b:word):SizeInt; assembler;
  299. var
  300. saveedi,saveebx : longint;
  301. asm
  302. movl %edi,saveedi
  303. movl %ebx,saveebx
  304. movl Buf,%edi // Load String
  305. movw b,%bx
  306. movl Len,%ecx // Load len
  307. xorl %eax,%eax
  308. testl %ecx,%ecx
  309. jz .Lcharposnotfound
  310. cld
  311. movl %ecx,%edx // Copy for easy manipulation
  312. movw %bx,%ax
  313. repne
  314. scasw
  315. jne .Lcharposnotfound
  316. incl %ecx
  317. subl %ecx,%edx
  318. movl %edx,%eax
  319. jmp .Lready
  320. .Lcharposnotfound:
  321. movl $-1,%eax
  322. .Lready:
  323. movl saveedi,%edi
  324. movl saveebx,%ebx
  325. end;
  326. {$endif FPC_SYSTEM_HAS_INDEXWORD}
  327. {$ifndef FPC_SYSTEM_HAS_INDEXDWORD}
  328. {$define FPC_SYSTEM_HAS_INDEXDWORD}
  329. function IndexDWord(Const buf;len:SizeInt;b:DWord):SizeInt; assembler;
  330. var
  331. saveedi,saveebx : longint;
  332. asm
  333. movl %edi,saveedi
  334. movl %ebx,saveebx
  335. {$ifdef REGCALL}
  336. movl %eax,%edi
  337. movl %ecx,%ebx
  338. movl %edx,%ecx
  339. {$else}
  340. movl Len,%ecx // Load len
  341. movl Buf,%edi // Load String
  342. movl b,%ebx
  343. {$endif}
  344. xorl %eax,%eax
  345. testl %ecx,%ecx
  346. jz .Lcharposnotfound
  347. cld
  348. movl %ecx,%edx // Copy for easy manipulation
  349. movl %ebx,%eax
  350. repne
  351. scasl
  352. jne .Lcharposnotfound
  353. incl %ecx
  354. subl %ecx,%edx
  355. movl %edx,%eax
  356. jmp .Lready
  357. .Lcharposnotfound:
  358. movl $-1,%eax
  359. .Lready:
  360. movl saveedi,%edi
  361. movl saveebx,%ebx
  362. end;
  363. {$endif FPC_SYSTEM_HAS_INDEXDWORD}
  364. {$ifndef FPC_SYSTEM_HAS_COMPAREBYTE}
  365. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  366. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  367. var
  368. saveesi,saveedi : longint;
  369. asm
  370. movl %edi,saveedi
  371. movl %esi,saveesi
  372. cld
  373. {$ifdef REGCALL}
  374. movl %eax,%edi
  375. movl %edx,%esi
  376. movl %ecx,%eax
  377. {$else}
  378. movl len,%eax
  379. movl buf2,%esi { Load params}
  380. movl buf1,%edi
  381. {$endif}
  382. testl %eax,%eax {We address -1(%esi), so we have to deal with len=0}
  383. je .LCmpbyteExit
  384. cmpl $7,%eax {<7 not worth aligning and go through all trouble}
  385. jl .LCmpbyte2
  386. movl %edi,%ecx { Align on 32bits }
  387. negl %ecx { calc bytes to align (%edi and 3) xor 3= -%edi and 3}
  388. andl $3,%ecx
  389. subl %ecx,%eax { Subtract from number of bytes to go}
  390. orl %ecx,%ecx
  391. rep
  392. cmpsb {The actual 32-bit Aligning}
  393. jne .LCmpbyte3
  394. movl %eax,%ecx {bytes to do, divide by 4}
  395. andl $3,%eax {remainder}
  396. shrl $2,%ecx {The actual division}
  397. orl %ecx,%ecx {Sets zero flag if ecx=0 -> no cmp}
  398. rep
  399. cmpsl
  400. je .LCmpbyte2 { All equal? then to the left over bytes}
  401. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  402. subl %eax,%esi
  403. subl %eax,%edi
  404. .LCmpbyte2:
  405. movl %eax,%ecx {bytes still to (re)scan}
  406. orl %eax,%eax {prevent disaster in case %eax=0}
  407. rep
  408. cmpsb
  409. .LCmpbyte3:
  410. movzbl -1(%esi),%ecx
  411. movzbl -1(%edi),%eax // Compare failing (or equal) position
  412. subl %ecx,%eax
  413. .LCmpbyteExit:
  414. movl saveedi,%edi
  415. movl saveesi,%esi
  416. end;
  417. {$endif FPC_SYSTEM_HAS_COMPAREBYTE}
  418. {$ifndef FPC_SYSTEM_HAS_COMPAREWORD}
  419. {$define FPC_SYSTEM_HAS_COMPAREWORD}
  420. function CompareWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  421. var
  422. saveesi,saveedi,saveebx : longint;
  423. asm
  424. movl %edi,saveedi
  425. movl %esi,saveesi
  426. movl %ebx,saveebx
  427. cld
  428. {$ifdef REGCALL}
  429. movl %eax,%edi
  430. movl %edx,%esi
  431. movl %ecx,%eax
  432. {$else}
  433. movl len,%eax
  434. movl buf2,%esi { Load params}
  435. movl buf1,%edi
  436. {$endif}
  437. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  438. je .LCmpwordExit
  439. cmpl $5,%eax {<5 (3 bytes align + 4 bytes cmpsl = 4 words}
  440. jl .LCmpword2 { not worth aligning and go through all trouble}
  441. movl (%edi),%ebx // Compare alignment bytes.
  442. cmpl (%esi),%ebx
  443. jne .LCmpword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  444. shll $1,%eax {Convert word count to bytes}
  445. movl %edi,%edx { Align comparing is already done, so simply add}
  446. negl %edx { calc bytes to align -%edi and 3}
  447. andl $3,%edx
  448. addl %edx,%esi { Skip max 3 bytes alignment}
  449. addl %edx,%edi
  450. subl %edx,%eax { Subtract from number of bytes to go}
  451. movl %eax,%ecx { Make copy of bytes to go}
  452. andl $3,%eax { Calc remainder (mod 4) }
  453. andl $1,%edx { %edx is 1 if array not 2-aligned, 0 otherwise}
  454. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  455. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  456. rep { Compare entire DWords}
  457. cmpsl
  458. je .LCmpword2a { All equal? then to the left over bytes}
  459. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  460. subl %eax,%esi { Go back one DWord}
  461. subl %eax,%edi
  462. incl %eax {if not odd then this does nothing, else it makes
  463. sure that adding %edx increases from 2 to 3 words}
  464. .LCmpword2a:
  465. subl %edx,%esi { Subtract alignment}
  466. subl %edx,%edi
  467. addl %edx,%eax
  468. shrl $1,%eax
  469. .LCmpword2:
  470. movl %eax,%ecx {words still to (re)scan}
  471. orl %eax,%eax {prevent disaster in case %eax=0}
  472. rep
  473. cmpsw
  474. .LCmpword3:
  475. movzwl -2(%esi),%ecx
  476. movzwl -2(%edi),%eax // Compare failing (or equal) position
  477. subl %ecx,%eax // calculate end result.
  478. .LCmpwordExit:
  479. movl saveedi,%edi
  480. movl saveesi,%esi
  481. movl saveebx,%ebx
  482. end;
  483. {$endif FPC_SYSTEM_HAS_COMPAREWORD}
  484. {$ifndef FPC_SYSTEM_HAS_COMPAREDWORD}
  485. {$define FPC_SYSTEM_HAS_COMPAREDWORD}
  486. function CompareDWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  487. var
  488. saveesi,saveedi,saveebx : longint;
  489. asm
  490. movl %edi,saveedi
  491. movl %esi,saveesi
  492. movl %ebx,saveebx
  493. cld
  494. {$ifdef REGCALL}
  495. movl %eax,%edi
  496. movl %edx,%esi
  497. movl %ecx,%eax
  498. {$else}
  499. movl len,%eax
  500. movl buf2,%esi { Load params}
  501. movl buf1,%edi
  502. {$endif}
  503. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  504. je .LCmpDwordExit
  505. cmpl $3,%eax {<3 (3 bytes align + 4 bytes cmpsl) = 2 DWords}
  506. jl .LCmpDword2 { not worth aligning and go through all trouble}
  507. movl (%edi),%ebx // Compare alignment bytes.
  508. cmpl (%esi),%ebx
  509. jne .LCmpDword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  510. shll $2,%eax {Convert word count to bytes}
  511. movl %edi,%edx { Align comparing is already done, so simply add}
  512. negl %edx { calc bytes to align -%edi and 3}
  513. andl $3,%edx
  514. addl %edx,%esi { Skip max 3 bytes alignment}
  515. addl %edx,%edi
  516. subl %edx,%eax { Subtract from number of bytes to go}
  517. movl %eax,%ecx { Make copy of bytes to go}
  518. andl $3,%eax { Calc remainder (mod 4) }
  519. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  520. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  521. rep { Compare entire DWords}
  522. cmpsl
  523. je .LCmpDword2a { All equal? then to the left over bytes}
  524. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  525. subl %eax,%esi { Go back one DWord}
  526. subl %eax,%edi
  527. addl $3,%eax {if align<>0 this causes repcount to be 2}
  528. .LCmpDword2a:
  529. subl %edx,%esi { Subtract alignment}
  530. subl %edx,%edi
  531. addl %edx,%eax
  532. shrl $2,%eax
  533. .LCmpDword2:
  534. movl %eax,%ecx {words still to (re)scan}
  535. orl %eax,%eax {prevent disaster in case %eax=0}
  536. rep
  537. cmpsl
  538. .LCmpDword3:
  539. movzwl -4(%esi),%ecx
  540. movzwl -4(%edi),%eax // Compare failing (or equal) position
  541. subl %ecx,%eax // calculate end result.
  542. .LCmpDwordExit:
  543. movl saveedi,%edi
  544. movl saveesi,%esi
  545. movl saveebx,%ebx
  546. end;
  547. {$endif FPC_SYSTEM_HAS_COMPAREDWORD}
  548. {$ifndef FPC_SYSTEM_HAS_INDEXCHAR0}
  549. {$define FPC_SYSTEM_HAS_INDEXCHAR0}
  550. function IndexChar0(Const buf;len:SizeInt;b:Char):SizeInt; assembler;
  551. var
  552. saveesi,saveebx : longint;
  553. asm
  554. movl %esi,saveesi
  555. movl %ebx,saveebx
  556. // Can't use scasb, or will have to do it twice, think this
  557. // is faster for small "len"
  558. {$ifdef REGCALL}
  559. movl %eax,%esi // Load address
  560. movzbl %cl,%ebx // Load searchpattern
  561. {$else}
  562. movl Buf,%esi // Load address
  563. movl len,%edx // load maximal searchdistance
  564. movzbl b,%ebx // Load searchpattern
  565. {$endif}
  566. testl %edx,%edx
  567. je .LFound
  568. xorl %ecx,%ecx // zero index in Buf
  569. xorl %eax,%eax // To make DWord compares possible
  570. .LLoop:
  571. movb (%esi),%al // Load byte
  572. cmpb %al,%bl
  573. je .LFound // byte the same?
  574. incl %ecx
  575. incl %esi
  576. cmpl %edx,%ecx // Maximal distance reached?
  577. je .LNotFound
  578. testl %eax,%eax // Nullchar = end of search?
  579. jne .LLoop
  580. .LNotFound:
  581. movl $-1,%ecx // Not found return -1
  582. .LFound:
  583. movl %ecx,%eax
  584. movl saveesi,%esi
  585. movl saveebx,%ebx
  586. end;
  587. {$endif FPC_SYSTEM_HAS_INDEXCHAR0}
  588. {****************************************************************************
  589. String
  590. ****************************************************************************}
  591. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  592. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  593. function fpc_shortstr_to_shortstr(len:longint; const sstr: shortstring): shortstring; [public,alias: 'FPC_SHORTSTR_TO_SHORTSTR']; compilerproc;
  594. begin
  595. asm
  596. cld
  597. movl __RESULT,%edi
  598. movl sstr,%esi
  599. xorl %eax,%eax
  600. movl len,%ecx
  601. lodsb
  602. cmpl %ecx,%eax
  603. jbe .LStrCopy1
  604. movl %ecx,%eax
  605. .LStrCopy1:
  606. stosb
  607. cmpl $7,%eax
  608. jl .LStrCopy2
  609. movl %edi,%ecx { Align on 32bits }
  610. negl %ecx
  611. andl $3,%ecx
  612. subl %ecx,%eax
  613. rep
  614. movsb
  615. movl %eax,%ecx
  616. andl $3,%eax
  617. shrl $2,%ecx
  618. rep
  619. movsl
  620. .LStrCopy2:
  621. movl %eax,%ecx
  622. rep
  623. movsb
  624. end ['ESI','EDI','EAX','ECX'];
  625. end;
  626. procedure fpc_shortstr_assign(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_ASSIGN'];
  627. begin
  628. asm
  629. pushl %eax
  630. pushl %ecx
  631. cld
  632. movl dstr,%edi
  633. movl sstr,%esi
  634. xorl %eax,%eax
  635. movl len,%ecx
  636. lodsb
  637. cmpl %ecx,%eax
  638. jbe .LStrCopy1
  639. movl %ecx,%eax
  640. .LStrCopy1:
  641. stosb
  642. cmpl $7,%eax
  643. jl .LStrCopy2
  644. movl %edi,%ecx { Align on 32bits }
  645. negl %ecx
  646. andl $3,%ecx
  647. subl %ecx,%eax
  648. rep
  649. movsb
  650. movl %eax,%ecx
  651. andl $3,%eax
  652. shrl $2,%ecx
  653. rep
  654. movsl
  655. .LStrCopy2:
  656. movl %eax,%ecx
  657. rep
  658. movsb
  659. popl %ecx
  660. popl %eax
  661. end ['ESI','EDI'];
  662. end;
  663. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  664. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  665. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  666. function fpc_shortstr_concat(const s1,s2:shortstring):shortstring;compilerproc;
  667. begin
  668. asm
  669. movl __RESULT,%edi
  670. movl %edi,%ebx
  671. movl s1,%esi { first string }
  672. lodsb
  673. andl $0x0ff,%eax
  674. stosb
  675. cmpl $7,%eax
  676. jl .LStrConcat1
  677. movl %edi,%ecx { Align on 32bits }
  678. negl %ecx
  679. andl $3,%ecx
  680. subl %ecx,%eax
  681. rep
  682. movsb
  683. movl %eax,%ecx
  684. andl $3,%eax
  685. shrl $2,%ecx
  686. rep
  687. movsl
  688. .LStrConcat1:
  689. movl %eax,%ecx
  690. rep
  691. movsb
  692. movl s2,%esi { second string }
  693. movzbl (%ebx),%ecx
  694. negl %ecx
  695. addl $0x0ff,%ecx
  696. lodsb
  697. cmpl %ecx,%eax
  698. jbe .LStrConcat2
  699. movl %ecx,%eax
  700. .LStrConcat2:
  701. addb %al,(%ebx)
  702. cmpl $7,%eax
  703. jl .LStrConcat3
  704. movl %edi,%ecx { Align on 32bits }
  705. negl %ecx
  706. andl $3,%ecx
  707. subl %ecx,%eax
  708. rep
  709. movsb
  710. movl %eax,%ecx
  711. andl $3,%eax
  712. shrl $2,%ecx
  713. rep
  714. movsl
  715. .LStrConcat3:
  716. movl %eax,%ecx
  717. rep
  718. movsb
  719. end ['EBX','ECX','EAX','ESI','EDI'];
  720. end;
  721. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  722. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  723. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  724. procedure fpc_shortstr_append_shortstr(var s1:shortstring;const s2:shortstring);compilerproc;
  725. [public,alias:'FPC_SHORTSTR_APPEND_SHORTSTR'];
  726. begin
  727. asm
  728. movl s1,%edi
  729. movl s2,%esi
  730. movl %edi,%ebx
  731. movzbl (%edi),%ecx
  732. movl __HIGH(s1),%eax
  733. lea 1(%edi,%ecx),%edi
  734. negl %ecx
  735. addl %eax,%ecx
  736. // no need to zero eax, high(s1) <= 255
  737. lodsb
  738. cmpl %ecx,%eax
  739. jbe .LStrConcat1
  740. movl %ecx,%eax
  741. .LStrConcat1:
  742. addb %al,(%ebx)
  743. cmpl $7,%eax
  744. jl .LStrConcat2
  745. movl %edi,%ecx { Align on 32bits }
  746. negl %ecx
  747. andl $3,%ecx
  748. subl %ecx,%eax
  749. rep
  750. movsb
  751. movl %eax,%ecx
  752. andl $3,%eax
  753. shrl $2,%ecx
  754. rep
  755. movsl
  756. .LStrConcat2:
  757. movl %eax,%ecx
  758. rep
  759. movsb
  760. end ['EBX','ECX','EAX','ESI','EDI'];
  761. end;
  762. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  763. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  764. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  765. function fpc_shortstr_compare(const left,right:shortstring): longint;assembler; [public,alias:'FPC_SHORTSTR_COMPARE']; compilerproc;
  766. var
  767. saveesi,saveedi,saveebx : longint;
  768. asm
  769. movl %edi,saveedi
  770. movl %esi,saveesi
  771. movl %ebx,saveebx
  772. cld
  773. movl right,%esi
  774. movl left,%edi
  775. movzbl (%esi),%eax
  776. movzbl (%edi),%ebx
  777. movl %eax,%edx
  778. incl %esi
  779. incl %edi
  780. cmpl %ebx,%eax
  781. jbe .LStrCmp1
  782. movl %ebx,%eax
  783. .LStrCmp1:
  784. cmpl $7,%eax
  785. jl .LStrCmp2
  786. movl %edi,%ecx { Align on 32bits }
  787. negl %ecx
  788. andl $3,%ecx
  789. subl %ecx,%eax
  790. orl %ecx,%ecx
  791. rep
  792. cmpsb
  793. jne .LStrCmp3
  794. movl %eax,%ecx
  795. andl $3,%eax
  796. shrl $2,%ecx
  797. orl %ecx,%ecx
  798. rep
  799. cmpsl
  800. je .LStrCmp2
  801. movl $4,%eax
  802. subl %eax,%esi
  803. subl %eax,%edi
  804. .LStrCmp2:
  805. movl %eax,%ecx
  806. orl %eax,%eax
  807. rep
  808. cmpsb
  809. je .LStrCmp4
  810. .LStrCmp3:
  811. movzbl -1(%esi),%edx // Compare failing (or equal) position
  812. movzbl -1(%edi),%ebx
  813. .LStrCmp4:
  814. movl %ebx,%eax // Compare length or position
  815. subl %edx,%eax
  816. movl saveedi,%edi
  817. movl saveesi,%esi
  818. movl saveebx,%ebx
  819. end;
  820. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  821. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  822. {$define FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  823. function fpc_pchar_to_shortstr(p:pchar):shortstring;assembler;[public,alias:'FPC_PCHAR_TO_SHORTSTR']; compilerproc;
  824. {$include strpas.inc}
  825. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  826. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  827. {$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  828. function fpc_pchar_length(p:pchar):longint;assembler;[public,alias:'FPC_PCHAR_LENGTH']; compilerproc;
  829. {$include strlen.inc}
  830. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  831. {$define FPC_SYSTEM_HAS_GET_FRAME}
  832. function get_frame:pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  833. asm
  834. movl %ebp,%eax
  835. end ['EAX'];
  836. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  837. function get_caller_addr(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  838. asm
  839. {$ifndef REGCALL}
  840. movl framebp,%eax
  841. {$endif}
  842. orl %eax,%eax
  843. jz .Lg_a_null
  844. movl 4(%eax),%eax
  845. .Lg_a_null:
  846. end ['EAX'];
  847. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  848. function get_caller_frame(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  849. asm
  850. {$ifndef REGCALL}
  851. movl framebp,%eax
  852. {$endif}
  853. orl %eax,%eax
  854. jz .Lgnf_null
  855. movl (%eax),%eax
  856. .Lgnf_null:
  857. end ['EAX'];
  858. {****************************************************************************
  859. Math
  860. ****************************************************************************}
  861. {$define FPC_SYSTEM_HAS_ABS_LONGINT}
  862. function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  863. asm
  864. {$ifndef REGCALL}
  865. movl l,%eax
  866. {$endif}
  867. cltd
  868. xorl %edx,%eax
  869. subl %edx,%eax
  870. end ['EAX','EDX'];
  871. {$define FPC_SYSTEM_HAS_ODD_LONGINT}
  872. function odd(l:longint):boolean;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  873. asm
  874. {$ifdef SYSTEMINLINE}
  875. movl l,%eax
  876. {$else}
  877. {$ifndef REGCALL}
  878. movl l,%eax
  879. {$endif}
  880. {$endif}
  881. andl $1,%eax
  882. setnz %al
  883. end ['EAX'];
  884. {$define FPC_SYSTEM_HAS_SQR_LONGINT}
  885. function sqr(l:longint):longint;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  886. asm
  887. {$ifdef SYSTEMINLINE}
  888. movl l,%eax
  889. {$else}
  890. {$ifndef REGCALL}
  891. movl l,%eax
  892. {$endif}
  893. {$endif}
  894. imull %eax,%eax
  895. end ['EAX'];
  896. {$define FPC_SYSTEM_HAS_SPTR}
  897. Function Sptr : Pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  898. asm
  899. movl %esp,%eax
  900. end;
  901. {****************************************************************************
  902. Str()
  903. ****************************************************************************}
  904. {$define FPC_SYSTEM_HAS_INT_STR_LONGINT}
  905. procedure int_str(l : longint;var s : string);
  906. var
  907. buffer : array[0..15] of byte;
  908. isneg : byte;
  909. begin
  910. { Workaround: }
  911. if l=longint($80000000) then
  912. begin
  913. s:='-2147483648';
  914. exit;
  915. end;
  916. asm
  917. movl l,%eax // load Integer
  918. xorl %ecx,%ecx // String length=0
  919. leal buffer,%ebx
  920. movl $0x0a,%esi // load 10 as dividing constant.
  921. movb $0,isneg
  922. orl %eax,%eax // Sign ?
  923. jns .LM2
  924. movb $1,isneg
  925. negl %eax
  926. .LM2:
  927. cltd
  928. idivl %esi
  929. addb $0x30,%dl // convert Rest to ASCII.
  930. movb %dl,(%ebx)
  931. incl %ecx
  932. incl %ebx
  933. cmpl $0,%eax
  934. jnz .LM2
  935. { now copy the string }
  936. movl s,%edi // Load String address
  937. cmpb $0,isneg
  938. je .LM3
  939. movb $0x2d,(%ebx)
  940. incl %ecx
  941. incl %ebx
  942. .LM3:
  943. movb %cl,(%edi) // Copy String length
  944. incl %edi
  945. .LM4:
  946. decl %ebx
  947. movb (%ebx),%al
  948. stosb
  949. decl %ecx
  950. jnz .LM4
  951. end ['eax','ecx','edx','ebx','esi','edi'];
  952. end;
  953. {$define FPC_SYSTEM_HAS_INT_STR_LONGWORD}
  954. procedure int_str(c : longword;var s : string);
  955. var
  956. buffer : array[0..15] of byte;
  957. begin
  958. asm
  959. movl c,%eax // load CARDINAL
  960. xorl %ecx,%ecx // String length=0
  961. leal buffer,%ebx
  962. movl $0x0a,%esi // load 10 as dividing constant.
  963. .LM4:
  964. xorl %edx,%edx
  965. divl %esi
  966. addb $0x30,%dl // convert Rest to ASCII.
  967. movb %dl,(%ebx)
  968. incl %ecx
  969. incl %ebx
  970. cmpl $0,%eax
  971. jnz .LM4
  972. { now copy the string }
  973. movl s,%edi // Load String address
  974. movb %cl,(%edi) // Copy String length
  975. incl %edi
  976. .LM5:
  977. decl %ebx
  978. movb (%ebx),%al
  979. stosb
  980. decl %ecx
  981. jnz .LM5
  982. end ['eax','ecx','edx','ebx','esi','edi'];
  983. end;
  984. {****************************************************************************
  985. Bounds Check
  986. ****************************************************************************}
  987. { do a thread save inc/dec }
  988. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  989. function cpudeclocked(var l : longint) : boolean;assembler;
  990. asm
  991. {$ifndef REGCALL}
  992. movl l,%eax
  993. {$endif}
  994. { this check should be done because a lock takes a lot }
  995. { of time! }
  996. lock
  997. decl (%eax)
  998. setzb %al
  999. end;
  1000. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  1001. procedure cpuinclocked(var l : longint);assembler;
  1002. asm
  1003. {$ifndef REGCALL}
  1004. movl l,%eax
  1005. {$endif}
  1006. lock
  1007. incl (%eax)
  1008. end;
  1009. // inline SMP check and normal lock.
  1010. // the locked one is so slow, inlining doesn't matter.
  1011. function declocked(var l : longint) : boolean; inline;
  1012. begin
  1013. if not ismultithread then
  1014. begin
  1015. dec(l);
  1016. declocked:=l=0;
  1017. end
  1018. else
  1019. declocked:=cpudeclocked(l);
  1020. end;
  1021. procedure inclocked(var l : longint); inline;
  1022. begin
  1023. if not ismultithread then
  1024. inc(l)
  1025. else
  1026. cpuinclocked(l);
  1027. end;
  1028. {****************************************************************************
  1029. FPU
  1030. ****************************************************************************}
  1031. const
  1032. fpucw : word = $1332;
  1033. { Internal constants for use in system unit }
  1034. FPU_Invalid = 1;
  1035. FPU_Denormal = 2;
  1036. FPU_DivisionByZero = 4;
  1037. FPU_Overflow = 8;
  1038. FPU_Underflow = $10;
  1039. FPU_StackUnderflow = $20;
  1040. FPU_StackOverflow = $40;
  1041. FPU_ExceptionMask = $ff;
  1042. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  1043. Procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  1044. asm
  1045. fninit
  1046. fldcw fpucw
  1047. fwait
  1048. end;
  1049. {$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  1050. function fpc_freemem_x(p:pointer):ptrint; [external name 'FPC_FREEMEM_X'];
  1051. Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
  1052. asm
  1053. cmpl $0,(%eax)
  1054. jne .Ldecr_ref_continue
  1055. ret
  1056. .Ldecr_ref_continue:
  1057. // Temps allocated between ebp-24 and ebp+0
  1058. subl $4,%esp
  1059. // Var S located in register
  1060. // Var l located in register
  1061. movl %eax,(%esp)
  1062. .Lj3599:
  1063. // [101] l:=@PAnsiRec(S-FirstOff)^.Ref;
  1064. movl (%esp),%edx
  1065. movl (%edx),%edx
  1066. subl $8,%edx
  1067. // [102] If l^<0 then exit;
  1068. movl (%edx),%eax
  1069. testl %eax,%eax
  1070. jl .Lj3596
  1071. .Lj3603:
  1072. // [104] If declocked(l^) then
  1073. movb ismultithread,%al
  1074. testb %al,%al
  1075. jne .Lj3610
  1076. decl (%edx)
  1077. je .Lj3620
  1078. addl $4,%esp
  1079. ret
  1080. .Lj3610:
  1081. movl %edx,%eax
  1082. call cpudeclocked
  1083. movb %al,%cl
  1084. .Lj3613:
  1085. testb %cl,%cl
  1086. je .Lj3605
  1087. .Lj3620:
  1088. movl (%esp),%eax
  1089. movl (%eax),%eax
  1090. subl $8,%eax
  1091. call FPC_FREEMEM_X
  1092. movl (%esp),%eax
  1093. movl $0,(%eax)
  1094. .Lj3618:
  1095. .Lj3605:
  1096. .Lj3596:
  1097. // [107] end;
  1098. addl $4,%esp
  1099. end;
  1100. function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;
  1101. {$define FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  1102. Function fpc_ansistr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_ANSISTR_UNIQUE']; compilerproc; nostackframe;assembler;
  1103. asm
  1104. // Var S located in register
  1105. // Var $result located in register
  1106. movl %eax,%edx
  1107. // [437] pointer(result) := pointer(s);
  1108. movl (%eax),%eax
  1109. // [438] If Pointer(S)=Nil then
  1110. testl %eax,%eax
  1111. je .Lj4031
  1112. .Lj4036:
  1113. // [440] if PAnsiRec(Pointer(S)-Firstoff)^.Ref<>1 then
  1114. movl -8(%eax),%ecx
  1115. cmpl $1,%ecx
  1116. je .Lj4038
  1117. // [441] result:=fpc_truely_ansistr_unique(s);
  1118. movl %edx,%eax
  1119. call fpc_truely_ansistr_unique
  1120. .Lj4038:
  1121. .Lj4031:
  1122. // [442] end;
  1123. end;