i386.inc 33 KB

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