i386.inc 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627
  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. pushfd
  28. pushfd
  29. pop eax
  30. mov ebx,eax
  31. xor eax,200000h
  32. push eax
  33. popfd
  34. pushfd
  35. pop eax
  36. popfd
  37. and eax,200000h
  38. and ebx,200000h
  39. cmp eax,ebx
  40. setnz al
  41. pop ebx
  42. end;
  43. {$asmmode ATT}
  44. procedure check_sse_support;
  45. var
  46. _ecx,_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. movl %ecx,_ecx
  56. popl %ebx
  57. end;
  58. has_sse_support:=((_edx and $2000000)<>0) and os_supports_sse;
  59. has_sse2_support:=((_edx and $4000000)<>0) and os_supports_sse;
  60. has_sse3_support:=((_ecx and $200)<>0) and os_supports_sse;
  61. end
  62. else
  63. begin
  64. { a cpu with without cpuid instruction supports never sse }
  65. has_sse_support:=false;
  66. has_sse2_support:=false;
  67. has_sse3_support:=false;
  68. end;
  69. end;
  70. { returns true, if the processor supports the mmx instructions }
  71. function mmx_support : boolean;
  72. var
  73. _edx : longint;
  74. begin
  75. if cpuid_support then
  76. begin
  77. asm
  78. pushl %ebx
  79. movl $1,%eax
  80. cpuid
  81. movl %edx,_edx
  82. popl %ebx
  83. end;
  84. mmx_support:=(_edx and $800000)<>0;
  85. end
  86. else
  87. { a cpu with without cpuid instruction supports never mmx }
  88. mmx_support:=false;
  89. end;
  90. {$ifndef FPC_PIC}
  91. {$ifndef FPC_SYSTEM_HAS_MOVE}
  92. {$define USE_FASTMOVE}
  93. {$i fastmove.inc}
  94. {$endif FPC_SYSTEM_HAS_MOVE}
  95. {$endif FPC_PIC}
  96. procedure fpc_cpuinit;
  97. begin
  98. { because of the brain dead sse detection on x86, this test is post poned to fpc_cpucodeinit which
  99. must be implemented OS dependend (FK)
  100. has_sse_support:=sse_support;
  101. has_mmx_support:=mmx_support;
  102. setup_fastmove;
  103. }
  104. os_supports_sse:=false;
  105. { don't let libraries influence the FPU cw set by the host program }
  106. if IsLibrary then
  107. Default8087CW:=Get8087CW;
  108. end;
  109. {$ifndef darwin}
  110. function fpc_geteipasebx : pointer; [public, alias: 'fpc_geteipasebx'];assembler; nostackframe;
  111. asm
  112. movl (%esp),%ebx
  113. end;
  114. function fpc_geteipasecx : pointer; [public, alias: 'fpc_geteipasecx'];assembler; nostackframe;
  115. asm
  116. movl (%esp),%ecx
  117. end;
  118. {$endif}
  119. {$ifndef FPC_SYSTEM_HAS_MOVE}
  120. {$define FPC_SYSTEM_HAS_MOVE}
  121. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];assembler;
  122. var
  123. saveesi,saveedi : longint;
  124. asm
  125. movl %edi,saveedi
  126. movl %esi,saveesi
  127. movl %eax,%esi
  128. movl %edx,%edi
  129. movl %ecx,%edx
  130. movl %edi,%eax
  131. { check for zero or negative count }
  132. cmpl $0,%edx
  133. jle .LMoveEnd
  134. { Check for back or forward }
  135. sub %esi,%eax
  136. jz .LMoveEnd { Do nothing when source=dest }
  137. jc .LFMove { Do forward, dest<source }
  138. cmp %edx,%eax
  139. jb .LBMove { Dest is in range of move, do backward }
  140. { Forward Copy }
  141. .LFMove:
  142. cld
  143. cmpl $15,%edx
  144. jl .LFMove1
  145. movl %edi,%ecx { Align on 32bits }
  146. negl %ecx
  147. andl $3,%ecx
  148. subl %ecx,%edx
  149. rep
  150. movsb
  151. movl %edx,%ecx
  152. andl $3,%edx
  153. shrl $2,%ecx
  154. rep
  155. movsl
  156. .LFMove1:
  157. movl %edx,%ecx
  158. rep
  159. movsb
  160. jmp .LMoveEnd
  161. { Backward Copy }
  162. .LBMove:
  163. std
  164. addl %edx,%esi
  165. addl %edx,%edi
  166. movl %edi,%ecx
  167. decl %esi
  168. decl %edi
  169. cmpl $15,%edx
  170. jl .LBMove1
  171. negl %ecx { Align on 32bits }
  172. andl $3,%ecx
  173. subl %ecx,%edx
  174. rep
  175. movsb
  176. movl %edx,%ecx
  177. andl $3,%edx
  178. shrl $2,%ecx
  179. subl $3,%esi
  180. subl $3,%edi
  181. rep
  182. movsl
  183. addl $3,%esi
  184. addl $3,%edi
  185. .LBMove1:
  186. movl %edx,%ecx
  187. rep
  188. movsb
  189. cld
  190. .LMoveEnd:
  191. movl saveedi,%edi
  192. movl saveesi,%esi
  193. end;
  194. {$endif FPC_SYSTEM_HAS_MOVE}
  195. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  196. {$define FPC_SYSTEM_HAS_FILLCHAR}
  197. Procedure FillChar(var x;count:SizeInt;value:byte);assembler; nostackframe;
  198. asm
  199. cmpl $22,%edx { empirically determined value on a Core 2 Duo Conroe }
  200. jg .LFillFull
  201. orl %edx,%edx
  202. jle .LFillZero
  203. .LFillLoop:
  204. movb %cl,(%eax)
  205. incl %eax
  206. decl %edx
  207. jne .LFillLoop
  208. .LFillZero:
  209. ret
  210. .LFillFull:
  211. cld
  212. push %edi
  213. movl %eax,%edi
  214. movzbl %cl,%eax
  215. movl %edx,%ecx
  216. imul $0x01010101,%eax { Expand al into a 4 subbytes of eax}
  217. shrl $2,%ecx
  218. andl $3,%edx
  219. rep
  220. stosl
  221. movl %edx,%ecx
  222. .LFill1:
  223. rep
  224. stosb
  225. .LFillEnd:
  226. pop %edi
  227. end;
  228. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  229. {$ifndef FPC_SYSTEM_HAS_FILLWORD}
  230. {$define FPC_SYSTEM_HAS_FILLWORD}
  231. procedure fillword(var x;count : SizeInt;value : word);assembler;
  232. var
  233. saveedi : longint;
  234. asm
  235. movl %edi,saveedi
  236. movl %eax,%edi
  237. movzwl %cx,%eax
  238. movl %edx,%ecx
  239. { check for zero or negative count }
  240. cmpl $0,%ecx
  241. jle .LFillWordEnd
  242. movl %eax,%edx
  243. shll $16,%eax
  244. orl %edx,%eax
  245. movl %ecx,%edx
  246. shrl $1,%ecx
  247. cld
  248. rep
  249. stosl
  250. movl %edx,%ecx
  251. andl $1,%ecx
  252. rep
  253. stosw
  254. .LFillWordEnd:
  255. movl saveedi,%edi
  256. end;
  257. {$endif FPC_SYSTEM_HAS_FILLWORD}
  258. {$ifndef FPC_SYSTEM_HAS_FILLDWORD}
  259. {$define FPC_SYSTEM_HAS_FILLDWORD}
  260. procedure filldword(var x;count : SizeInt;value : dword);assembler;
  261. var
  262. saveedi : longint;
  263. asm
  264. movl %edi,saveedi
  265. movl %eax,%edi
  266. movl %ecx,%eax
  267. movl %edx,%ecx
  268. { check for zero or negative count }
  269. cmpl $0,%ecx
  270. jle .LFillDWordEnd
  271. cld
  272. rep
  273. stosl
  274. .LFillDWordEnd:
  275. movl saveedi,%edi
  276. end;
  277. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  278. {$ifndef FPC_SYSTEM_HAS_INDEXBYTE}
  279. {$define FPC_SYSTEM_HAS_INDEXBYTE}
  280. function IndexByte(Const buf;len:SizeInt;b:byte):SizeInt; assembler; nostackframe;
  281. asm
  282. push %esi
  283. push %edi
  284. push %eax { save initial value of 'buf' }
  285. cmp $4,%edx { less than 4 bytes, just test byte by byte. }
  286. jb .Ltail
  287. mov %cl,%ch { prepare pattern }
  288. movzwl %cx,%esi
  289. shl $16,%ecx
  290. or %esi,%ecx
  291. .Lalignloop:
  292. test $3,%al { align to 4 bytes if necessary }
  293. je .Laligned
  294. cmp %cl,(%eax)
  295. je .Lexit
  296. inc %eax
  297. dec %edx
  298. jmp .Lalignloop
  299. .balign 16 { Main loop, unrolled 4 times for speed }
  300. .Lloop:
  301. mov (%eax),%esi { load dword }
  302. xor %ecx,%esi { XOR with pattern, bytes equal to target are now 0 }
  303. lea -0x01010101(%esi),%edi
  304. xor %esi,%edi { (x-0x01010101) xor x }
  305. not %esi
  306. and $0x80808080,%esi
  307. and %edi,%esi { ((x-0x01010101) xor x) and (not x) and 0x80808080 }
  308. jnz .Lfound { one of the bytes matches }
  309. mov 4(%eax),%esi
  310. xor %ecx,%esi
  311. lea -0x01010101(%esi),%edi
  312. xor %esi,%edi
  313. not %esi
  314. and $0x80808080,%esi
  315. and %edi,%esi
  316. jnz .Lfound4
  317. mov 8(%eax),%esi
  318. xor %ecx,%esi
  319. lea -0x01010101(%esi),%edi
  320. xor %esi,%edi
  321. not %esi
  322. and $0x80808080,%esi
  323. and %edi,%esi
  324. jnz .Lfound8
  325. mov 12(%eax),%esi
  326. xor %ecx,%esi
  327. lea -0x01010101(%esi),%edi
  328. xor %esi,%edi
  329. not %esi
  330. and $0x80808080,%esi
  331. and %edi,%esi
  332. jnz .Lfound12
  333. add $16,%eax
  334. .Laligned:
  335. sub $16,%edx
  336. jae .Lloop { Still more than 16 bytes remaining }
  337. { Process remaining bytes (<16 left at this point) }
  338. { length is offset by -16 at this point }
  339. .Lloop2:
  340. cmp $4-16,%edx { < 4 bytes left? }
  341. jb .Ltail
  342. mov (%eax),%esi
  343. xor %ecx,%esi
  344. lea -0x01010101(%esi),%edi
  345. xor %esi,%edi
  346. not %esi
  347. and $0x80808080,%esi
  348. and %edi,%esi
  349. jne .Lfound
  350. add $4,%eax
  351. sub $4,%edx
  352. jmp .Lloop2
  353. .Ltail: { Less than 4 bytes remaining, check one by one }
  354. and $3, %edx
  355. jz .Lnotfound
  356. .Lloop3:
  357. cmp %cl,(%eax)
  358. je .Lexit
  359. inc %eax
  360. dec %edx
  361. jnz .Lloop3
  362. .Lnotfound:
  363. or $-1,%eax
  364. jmp .Lexit1
  365. { add missing source pointer increments }
  366. .Lfound12:
  367. add $4,%eax
  368. .Lfound8:
  369. add $4,%eax
  370. .Lfound4:
  371. add $4,%eax
  372. .Lfound:
  373. test $0xff,%esi
  374. jnz .Lexit
  375. inc %eax
  376. test $0xff00,%esi
  377. jnz .Lexit
  378. inc %eax
  379. test $0xff0000,%esi
  380. jnz .Lexit
  381. inc %eax
  382. .Lexit:
  383. sub (%esp),%eax
  384. .Lexit1:
  385. pop %ecx { removes initial 'buf' value }
  386. pop %edi
  387. pop %esi
  388. end;
  389. {$endif FPC_SYSTEM_HAS_INDEXBYTE}
  390. {$ifndef FPC_SYSTEM_HAS_INDEXWORD}
  391. {$define FPC_SYSTEM_HAS_INDEXWORD}
  392. function Indexword(Const buf;len:SizeInt;b:word):SizeInt; assembler;
  393. var
  394. saveedi,saveebx : longint;
  395. asm
  396. movl %edi,saveedi
  397. movl %ebx,saveebx
  398. movl Buf,%edi // Load String
  399. movw b,%bx
  400. movl Len,%ecx // Load len
  401. xorl %eax,%eax
  402. testl %ecx,%ecx
  403. jz .Lcharposnotfound
  404. cld
  405. movl %ecx,%edx // Copy for easy manipulation
  406. movw %bx,%ax
  407. repne
  408. scasw
  409. jne .Lcharposnotfound
  410. incl %ecx
  411. subl %ecx,%edx
  412. movl %edx,%eax
  413. jmp .Lready
  414. .Lcharposnotfound:
  415. movl $-1,%eax
  416. .Lready:
  417. movl saveedi,%edi
  418. movl saveebx,%ebx
  419. end;
  420. {$endif FPC_SYSTEM_HAS_INDEXWORD}
  421. {$ifndef FPC_SYSTEM_HAS_INDEXDWORD}
  422. {$define FPC_SYSTEM_HAS_INDEXDWORD}
  423. function IndexDWord(Const buf;len:SizeInt;b:DWord):SizeInt; assembler;
  424. var
  425. saveedi,saveebx : longint;
  426. asm
  427. movl %edi,saveedi
  428. movl %ebx,saveebx
  429. movl %eax,%edi
  430. movl %ecx,%ebx
  431. movl %edx,%ecx
  432. xorl %eax,%eax
  433. testl %ecx,%ecx
  434. jz .Lcharposnotfound
  435. cld
  436. movl %ecx,%edx // Copy for easy manipulation
  437. movl %ebx,%eax
  438. repne
  439. scasl
  440. jne .Lcharposnotfound
  441. incl %ecx
  442. subl %ecx,%edx
  443. movl %edx,%eax
  444. jmp .Lready
  445. .Lcharposnotfound:
  446. movl $-1,%eax
  447. .Lready:
  448. movl saveedi,%edi
  449. movl saveebx,%ebx
  450. end;
  451. {$endif FPC_SYSTEM_HAS_INDEXDWORD}
  452. {$ifndef FPC_SYSTEM_HAS_COMPAREBYTE}
  453. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  454. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  455. asm
  456. cmpl $57,%ecx { empirically determined value on a Core 2 Duo Conroe }
  457. jg .LCmpbyteFull
  458. testl %ecx,%ecx
  459. je .LCmpbyteZero
  460. pushl %ebx
  461. .LCmpbyteLoop:
  462. movb (%eax),%bl
  463. cmpb (%edx),%bl
  464. leal 1(%eax),%eax
  465. leal 1(%edx),%edx
  466. jne .LCmpbyteExitFast
  467. decl %ecx
  468. jne .LCmpbyteLoop
  469. .LCmpbyteExitFast:
  470. movzbl -1(%edx),%ecx { Compare last position }
  471. movzbl %bl,%eax
  472. subl %ecx,%eax
  473. popl %ebx
  474. ret
  475. .LCmpbyteZero:
  476. movl $0,%eax
  477. ret
  478. .LCmpbyteFull:
  479. pushl %esi
  480. pushl %edi
  481. cld
  482. movl %eax,%edi
  483. movl %edx,%esi
  484. movl %ecx,%eax
  485. movl %edi,%ecx { Align on 32bits }
  486. negl %ecx { calc bytes to align (%edi and 3) xor 3= -%edi and 3 }
  487. andl $3,%ecx
  488. subl %ecx,%eax { Subtract from number of bytes to go }
  489. orl %ecx,%ecx
  490. rep
  491. cmpsb { The actual 32-bit Aligning }
  492. jne .LCmpbyte3
  493. movl %eax,%ecx { bytes to do, divide by 4 }
  494. andl $3,%eax { remainder }
  495. shrl $2,%ecx { The actual division }
  496. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp }
  497. rep
  498. cmpsl
  499. je .LCmpbyte2 { All equal? then to the left over bytes }
  500. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise }
  501. subl %eax,%esi
  502. subl %eax,%edi
  503. .LCmpbyte2:
  504. movl %eax,%ecx { bytes still to (re)scan }
  505. orl %eax,%eax { prevent disaster in case %eax=0 }
  506. rep
  507. cmpsb
  508. .LCmpbyte3:
  509. movzbl -1(%esi),%ecx
  510. movzbl -1(%edi),%eax { Compare failing (or equal) position }
  511. subl %ecx,%eax
  512. .LCmpbyteExit:
  513. popl %edi
  514. popl %esi
  515. end;
  516. {$endif FPC_SYSTEM_HAS_COMPAREBYTE}
  517. {$ifndef FPC_SYSTEM_HAS_COMPAREWORD}
  518. {$define FPC_SYSTEM_HAS_COMPAREWORD}
  519. function CompareWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  520. asm
  521. cmpl $32,%ecx { empirical average value, on a Athlon XP the
  522. break even is at 14, on a Core 2 Duo > 100 }
  523. jg .LCmpWordFull
  524. testl %ecx,%ecx
  525. je .LCmpWordZero
  526. pushl %ebx
  527. .LCmpWordLoop:
  528. movw (%eax),%bx
  529. cmpw (%edx),%bx
  530. leal 2(%eax),%eax
  531. leal 2(%edx),%edx
  532. jne .LCmpWordExitFast
  533. decl %ecx
  534. jne .LCmpWordLoop
  535. .LCmpWordExitFast:
  536. movzwl -2(%edx),%ecx { Compare last position }
  537. movzwl %bx,%eax
  538. subl %ecx,%eax
  539. popl %ebx
  540. ret
  541. .LCmpWordZero:
  542. movl $0,%eax
  543. ret
  544. .LCmpWordFull:
  545. pushl %esi
  546. pushl %edi
  547. pushl %ebx
  548. cld
  549. movl %eax,%edi
  550. movl %edx,%esi
  551. movl %ecx,%eax
  552. movl (%edi),%ebx // Compare alignment bytes.
  553. cmpl (%esi),%ebx
  554. jne .LCmpword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  555. shll $1,%eax {Convert word count to bytes}
  556. movl %edi,%edx { Align comparing is already done, so simply add}
  557. negl %edx { calc bytes to align -%edi and 3}
  558. andl $3,%edx
  559. addl %edx,%esi { Skip max 3 bytes alignment}
  560. addl %edx,%edi
  561. subl %edx,%eax { Subtract from number of bytes to go}
  562. movl %eax,%ecx { Make copy of bytes to go}
  563. andl $3,%eax { Calc remainder (mod 4) }
  564. andl $1,%edx { %edx is 1 if array not 2-aligned, 0 otherwise}
  565. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  566. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  567. rep { Compare entire DWords}
  568. cmpsl
  569. je .LCmpword2a { All equal? then to the left over bytes}
  570. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  571. subl %eax,%esi { Go back one DWord}
  572. subl %eax,%edi
  573. incl %eax {if not odd then this does nothing, else it makes
  574. sure that adding %edx increases from 2 to 3 words}
  575. .LCmpword2a:
  576. subl %edx,%esi { Subtract alignment}
  577. subl %edx,%edi
  578. addl %edx,%eax
  579. shrl $1,%eax
  580. .LCmpword2:
  581. movl %eax,%ecx {words still to (re)scan}
  582. orl %eax,%eax {prevent disaster in case %eax=0}
  583. rep
  584. cmpsw
  585. .LCmpword3:
  586. movzwl -2(%esi),%ecx
  587. movzwl -2(%edi),%eax // Compare failing (or equal) position
  588. subl %ecx,%eax // calculate end result.
  589. .LCmpwordExit:
  590. popl %ebx
  591. popl %edi
  592. popl %esi
  593. end;
  594. {$endif FPC_SYSTEM_HAS_COMPAREWORD}
  595. {$ifndef FPC_SYSTEM_HAS_COMPAREDWORD}
  596. {$define FPC_SYSTEM_HAS_COMPAREDWORD}
  597. function CompareDWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  598. asm
  599. cmpl $32,%ecx { empirical average value, on a Athlon XP the
  600. break even is at 12, on a Core 2 Duo > 100 }
  601. jg .LCmpDWordFull
  602. testl %ecx,%ecx
  603. je .LCmpDWordZero
  604. pushl %ebx
  605. .LCmpDWordLoop:
  606. movl (%eax),%ebx
  607. cmpl (%edx),%ebx
  608. leal 4(%eax),%eax
  609. leal 4(%edx),%edx
  610. jne .LCmpDWordExitFast
  611. decl %ecx
  612. jne .LCmpDWordLoop
  613. .LCmpDWordExitFast:
  614. xorl %eax,%eax
  615. movl -4(%edx),%edx // Compare failing (or equal) position
  616. subl %edx,%ebx // calculate end result.
  617. setb %dl
  618. seta %cl
  619. addb %cl,%al
  620. subb %dl,%al
  621. movsbl %al,%eax
  622. popl %ebx
  623. ret
  624. .LCmpDWordZero:
  625. movl $0,%eax
  626. ret
  627. .LCmpDWordFull:
  628. pushl %esi
  629. pushl %edi
  630. cld
  631. movl %eax,%edi
  632. movl %edx,%esi
  633. xorl %eax,%eax
  634. rep { Compare entire DWords}
  635. cmpsl
  636. movl -4(%edi),%edi // Compare failing (or equal) position
  637. subl -4(%esi),%edi // calculate end result.
  638. setb %dl
  639. seta %cl
  640. addb %cl,%al
  641. subb %dl,%al
  642. movsbl %al,%eax
  643. .LCmpDwordExit:
  644. popl %edi
  645. popl %esi
  646. end;
  647. {$endif FPC_SYSTEM_HAS_COMPAREDWORD}
  648. {$ifndef FPC_SYSTEM_HAS_INDEXCHAR0}
  649. {$define FPC_SYSTEM_HAS_INDEXCHAR0}
  650. function IndexChar0(Const buf;len:SizeInt;b:Char):SizeInt; assembler;
  651. var
  652. saveesi,saveebx : longint;
  653. asm
  654. movl %esi,saveesi
  655. movl %ebx,saveebx
  656. // Can't use scasb, or will have to do it twice, think this
  657. // is faster for small "len"
  658. movl %eax,%esi // Load address
  659. movzbl %cl,%ebx // Load searchpattern
  660. testl %edx,%edx
  661. je .LFound
  662. xorl %ecx,%ecx // zero index in Buf
  663. xorl %eax,%eax // To make DWord compares possible
  664. .balign 4
  665. .LLoop:
  666. movb (%esi),%al // Load byte
  667. cmpb %al,%bl
  668. je .LFound // byte the same?
  669. incl %ecx
  670. incl %esi
  671. cmpl %edx,%ecx // Maximal distance reached?
  672. je .LNotFound
  673. testl %eax,%eax // Nullchar = end of search?
  674. jne .LLoop
  675. .LNotFound:
  676. movl $-1,%ecx // Not found return -1
  677. .LFound:
  678. movl %ecx,%eax
  679. movl saveesi,%esi
  680. movl saveebx,%ebx
  681. end;
  682. {$endif FPC_SYSTEM_HAS_INDEXCHAR0}
  683. {****************************************************************************
  684. String
  685. ****************************************************************************}
  686. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  687. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  688. procedure fpc_shortstr_to_shortstr(out res:shortstring; const sstr: shortstring);assembler;[public,alias:'FPC_SHORTSTR_TO_SHORTSTR']; compilerproc;
  689. var
  690. saveesi,saveedi : longint;
  691. asm
  692. {$ifdef FPC_PROFILE}
  693. push %eax
  694. push %edx
  695. push %ecx
  696. call mcount
  697. pop %ecx
  698. pop %edx
  699. pop %eax
  700. {$endif FPC_PROFILE}
  701. movl %edi,saveedi
  702. movl %esi,saveesi
  703. cld
  704. movl res,%edi
  705. movl sstr,%esi
  706. movl %edx,%ecx
  707. xorl %eax,%eax
  708. lodsb
  709. cmpl %ecx,%eax
  710. jbe .LStrCopy1
  711. movl %ecx,%eax
  712. .LStrCopy1:
  713. stosb
  714. cmpl $7,%eax
  715. jl .LStrCopy2
  716. movl %edi,%ecx { Align on 32bits }
  717. negl %ecx
  718. andl $3,%ecx
  719. subl %ecx,%eax
  720. rep
  721. movsb
  722. movl %eax,%ecx
  723. andl $3,%eax
  724. shrl $2,%ecx
  725. rep
  726. movsl
  727. .LStrCopy2:
  728. movl %eax,%ecx
  729. rep
  730. movsb
  731. movl saveedi,%edi
  732. movl saveesi,%esi
  733. end;
  734. procedure fpc_shortstr_assign(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_ASSIGN'];
  735. begin
  736. asm
  737. {$ifdef FPC_PROFILE}
  738. push %eax
  739. push %edx
  740. push %ecx
  741. call mcount
  742. pop %ecx
  743. pop %edx
  744. pop %eax
  745. {$endif FPC_PROFILE}
  746. pushl %eax
  747. pushl %ecx
  748. cld
  749. movl dstr,%edi
  750. movl sstr,%esi
  751. xorl %eax,%eax
  752. movl len,%ecx
  753. lodsb
  754. cmpl %ecx,%eax
  755. jbe .LStrCopy1
  756. movl %ecx,%eax
  757. .LStrCopy1:
  758. stosb
  759. cmpl $7,%eax
  760. jl .LStrCopy2
  761. movl %edi,%ecx { Align on 32bits }
  762. negl %ecx
  763. andl $3,%ecx
  764. subl %ecx,%eax
  765. rep
  766. movsb
  767. movl %eax,%ecx
  768. andl $3,%eax
  769. shrl $2,%ecx
  770. rep
  771. movsl
  772. .LStrCopy2:
  773. movl %eax,%ecx
  774. rep
  775. movsb
  776. popl %ecx
  777. popl %eax
  778. end ['ESI','EDI'];
  779. end;
  780. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  781. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  782. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  783. function fpc_shortstr_compare(const left,right:shortstring): longint;assembler; [public,alias:'FPC_SHORTSTR_COMPARE']; compilerproc;
  784. var
  785. saveesi,saveedi,saveebx : longint;
  786. asm
  787. {$ifdef FPC_PROFILE}
  788. push %eax
  789. push %edx
  790. push %ecx
  791. call mcount
  792. pop %ecx
  793. pop %edx
  794. pop %eax
  795. {$endif FPC_PROFILE}
  796. movl %edi,saveedi
  797. movl %esi,saveesi
  798. movl %ebx,saveebx
  799. cld
  800. movl right,%esi
  801. movl left,%edi
  802. movzbl (%esi),%eax
  803. movzbl (%edi),%ebx
  804. movl %eax,%edx
  805. incl %esi
  806. incl %edi
  807. cmpl %ebx,%eax
  808. jbe .LStrCmp1
  809. movl %ebx,%eax
  810. .LStrCmp1:
  811. cmpl $7,%eax
  812. jl .LStrCmp2
  813. movl %edi,%ecx { Align on 32bits }
  814. negl %ecx
  815. andl $3,%ecx
  816. subl %ecx,%eax
  817. orl %ecx,%ecx
  818. rep
  819. cmpsb
  820. jne .LStrCmp3
  821. movl %eax,%ecx
  822. andl $3,%eax
  823. shrl $2,%ecx
  824. orl %ecx,%ecx
  825. rep
  826. cmpsl
  827. je .LStrCmp2
  828. movl $4,%eax
  829. subl %eax,%esi
  830. subl %eax,%edi
  831. .LStrCmp2:
  832. movl %eax,%ecx
  833. orl %eax,%eax
  834. rep
  835. cmpsb
  836. je .LStrCmp4
  837. .LStrCmp3:
  838. movzbl -1(%esi),%edx // Compare failing (or equal) position
  839. movzbl -1(%edi),%ebx
  840. .LStrCmp4:
  841. movl %ebx,%eax // Compare length or position
  842. subl %edx,%eax
  843. movl saveedi,%edi
  844. movl saveesi,%esi
  845. movl saveebx,%ebx
  846. end;
  847. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  848. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  849. {$define FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  850. procedure fpc_pchar_to_shortstr(out res : shortstring;p:pchar);assembler;[public,alias:'FPC_PCHAR_TO_SHORTSTR']; compilerproc;
  851. var
  852. saveres,saveebx,saveesi,saveedi : longint;
  853. asm
  854. {$ifdef FPC_PROFILE}
  855. push %eax
  856. push %edx
  857. push %ecx
  858. call mcount
  859. pop %ecx
  860. pop %edx
  861. pop %eax
  862. {$endif FPC_PROFILE}
  863. movl %ebx,saveebx
  864. movl %esi,saveesi
  865. movl %edi,saveedi
  866. movl %ecx,%esi
  867. movl %eax,%edi
  868. movl %edi,saveres
  869. movl $1,%ecx
  870. testl %esi,%esi
  871. movl %esi,%eax
  872. jz .LStrPasDone
  873. leal 3(%esi),%edx
  874. andl $-4,%edx
  875. // skip length byte
  876. incl %edi
  877. subl %esi,%edx
  878. jz .LStrPasAligned
  879. // align source to multiple of 4 (not dest, because we can't read past
  880. // the end of the source, since that may be past the end of the heap
  881. // -> sigsegv!!)
  882. .LStrPasAlignLoop:
  883. movb (%esi),%al
  884. incl %esi
  885. testb %al,%al
  886. jz .LStrPasDone
  887. incl %edi
  888. incb %cl
  889. decb %dl
  890. movb %al,-1(%edi)
  891. jne .LStrPasAlignLoop
  892. .balign 16
  893. .LStrPasAligned:
  894. movl (%esi),%ebx
  895. addl $4,%edi
  896. leal 0x0fefefeff(%ebx),%eax
  897. movl %ebx,%edx
  898. addl $4,%esi
  899. notl %edx
  900. andl %edx,%eax
  901. addl $4,%ecx
  902. andl $0x080808080,%eax
  903. movl %ebx,-4(%edi)
  904. jnz .LStrPasEndFound
  905. cmpl $252,%ecx
  906. ja .LStrPasPreEndLoop
  907. jmp .LStrPasAligned
  908. .LStrPasEndFound:
  909. subl $4,%ecx
  910. // this won't overwrite data since the result = 255 char string
  911. // and we never process more than the first 255 chars of p
  912. shrl $8,%eax
  913. jc .LStrPasDone
  914. incl %ecx
  915. shrl $8,%eax
  916. jc .LStrPasDone
  917. incl %ecx
  918. shrl $8,%eax
  919. jc .LStrPasDone
  920. incl %ecx
  921. jmp .LStrPasDone
  922. .LStrPasPreEndLoop:
  923. testb %cl,%cl
  924. jz .LStrPasDone
  925. movl (%esi),%eax
  926. .LStrPasEndLoop:
  927. testb %al,%al
  928. jz .LStrPasDone
  929. movb %al,(%edi)
  930. shrl $8,%eax
  931. incl %edi
  932. incb %cl
  933. jnz .LStrPasEndLoop
  934. .LStrPasDone:
  935. movl saveres,%edi
  936. addb $255,%cl
  937. movb %cl,(%edi)
  938. movl saveesi,%esi
  939. movl saveedi,%edi
  940. movl saveebx,%ebx
  941. end;
  942. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  943. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  944. {$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  945. function fpc_pchar_length(p:pchar):sizeint;assembler;[public,alias:'FPC_PCHAR_LENGTH']; compilerproc;
  946. var
  947. saveedi : longint;
  948. asm
  949. {$ifdef FPC_PROFILE}
  950. push %eax
  951. push %edx
  952. push %ecx
  953. call mcount
  954. pop %ecx
  955. pop %edx
  956. pop %eax
  957. {$endif FPC_PROFILE}
  958. test %eax,%eax
  959. jz .LStrLenDone
  960. movl %edi,saveedi
  961. movl %eax,%edi
  962. movl $0xffffffff,%ecx
  963. xorl %eax,%eax
  964. cld
  965. repne
  966. scasb
  967. movl $0xfffffffe,%eax
  968. subl %ecx,%eax
  969. movl saveedi,%edi
  970. .LStrLenDone:
  971. end;
  972. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  973. {$IFNDEF INTERNAL_BACKTRACE}
  974. {$define FPC_SYSTEM_HAS_GET_FRAME}
  975. function get_frame:pointer;assembler;nostackframe;{$ifdef SYSTEMINLINE}inline;{$endif}
  976. asm
  977. movl %ebp,%eax
  978. end;
  979. {$ENDIF not INTERNAL_BACKTRACE}
  980. {$define FPC_SYSTEM_HAS_GET_PC_ADDR}
  981. Function Get_pc_addr : Pointer;assembler;nostackframe;
  982. asm
  983. movl (%esp),%eax
  984. end;
  985. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  986. function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
  987. {$if defined(win32)}
  988. { Windows has StackTop always properly set }
  989. begin
  990. if assigned(framebp) and (framebp<=StackTop) and (framebp>=Sptr) then
  991. Result:=PPointer(framebp+4)^
  992. else
  993. Result:=nil;
  994. end;
  995. {$else defined(win32)}
  996. nostackframe;assembler;
  997. asm
  998. orl %eax,%eax
  999. jz .Lg_a_null
  1000. movl 4(%eax),%eax
  1001. .Lg_a_null:
  1002. end;
  1003. {$endif defined(win32)}
  1004. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  1005. function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;
  1006. {$if defined(win32)}
  1007. { Windows has StackTop always properly set }
  1008. begin
  1009. if assigned(framebp) and (framebp<=StackTop) and (framebp>=Sptr) then
  1010. Result:=PPointer(framebp)^
  1011. else
  1012. Result:=nil;
  1013. end;
  1014. {$else defined(win32)}
  1015. nostackframe;assembler;
  1016. asm
  1017. orl %eax,%eax
  1018. jz .Lgnf_null
  1019. movl (%eax),%eax
  1020. .Lgnf_null:
  1021. end;
  1022. {$endif defined(win32)}
  1023. {$define FPC_SYSTEM_HAS_SPTR}
  1024. Function Sptr : Pointer;assembler;nostackframe;
  1025. asm
  1026. movl %esp,%eax
  1027. end;
  1028. {****************************************************************************
  1029. Str()
  1030. ****************************************************************************}
  1031. {$if defined(disabled) and defined(regcall) }
  1032. {$define FPC_SYSTEM_HAS_INT_STR_LONGWORD}
  1033. {$define FPC_SYSTEM_HAS_INT_STR_LONGINT}
  1034. label str_int_shortcut;
  1035. procedure int_str(l:longword;out s:string);assembler;nostackframe;
  1036. asm
  1037. pushl %esi
  1038. pushl %edi
  1039. pushl %ebx
  1040. mov %edx,%edi
  1041. xor %edx,%edx
  1042. jmp str_int_shortcut
  1043. end;
  1044. procedure int_str(l:longint;out s:string);assembler;nostackframe;
  1045. {Optimized for speed, but balanced with size.}
  1046. const digits:array[0..9] of cardinal=(0,10,100,1000,10000,
  1047. 100000,1000000,10000000,
  1048. 100000000,1000000000);
  1049. asm
  1050. {$ifdef FPC_PROFILE}
  1051. push %eax
  1052. push %edx
  1053. push %ecx
  1054. call mcount
  1055. pop %ecx
  1056. pop %edx
  1057. pop %eax
  1058. {$endif FPC_PROFILE}
  1059. push %esi
  1060. push %edi
  1061. push %ebx
  1062. movl %edx,%edi
  1063. { Calculate absolute value and put sign in edx}
  1064. cltd
  1065. xorl %edx,%eax
  1066. subl %edx,%eax
  1067. negl %edx
  1068. str_int_shortcut:
  1069. movl %ecx,%esi
  1070. {Calculate amount of digits in ecx.}
  1071. xorl %ecx,%ecx
  1072. bsrl %eax,%ecx
  1073. incl %ecx
  1074. imul $1233,%ecx
  1075. shr $12,%ecx
  1076. {$ifdef FPC_PIC}
  1077. call fpc_geteipasebx
  1078. {$ifdef darwin}
  1079. movl digits-.Lpic(%ebx),%ebx
  1080. {$else}
  1081. addl $_GLOBAL_OFFSET_TABLE_,%ebx
  1082. movl digits@GOT(%ebx),%ebx
  1083. {$endif}
  1084. cmpl (%ebx,%ecx,4),%eax
  1085. {$else}
  1086. cmpl digits(,%ecx,4),%eax
  1087. {$endif}
  1088. cmc
  1089. adcl $0,%ecx {Nr. digits ready in ecx.}
  1090. {Write length & sign.}
  1091. lea (%edx,%ecx),%ebx
  1092. movb $45,%bh {movb $'-,%bh Not supported by our ATT reader.}
  1093. movw %bx,(%edi)
  1094. addl %edx,%edi
  1095. subl %edx,%esi
  1096. {Skip digits beyond string length.}
  1097. movl %eax,%edx
  1098. subl %ecx,%esi
  1099. jae .Lloop_write
  1100. .balign 4
  1101. .Lloop_skip:
  1102. movl $0xcccccccd,%eax {Divide by 10 using mul+shr}
  1103. mull %edx
  1104. shrl $3,%edx
  1105. decl %ecx
  1106. jz .Ldone {If (l<0) and (high(s)=1) this jump is taken.}
  1107. incl %esi
  1108. jnz .Lloop_skip
  1109. {Write out digits.}
  1110. .balign 4
  1111. .Lloop_write:
  1112. movl $0xcccccccd,%eax {Divide by 10 using mul+shr}
  1113. {Pre-add '0'}
  1114. leal 48(%edx),%ebx {leal $'0(,%edx),%ebx Not supported by our ATT reader.}
  1115. mull %edx
  1116. shrl $3,%edx
  1117. leal (%edx,%edx,8),%eax {x mod 10 = x-10*(x div 10)}
  1118. subl %edx,%ebx
  1119. subl %eax,%ebx
  1120. movb %bl,(%edi,%ecx)
  1121. decl %ecx
  1122. jnz .Lloop_write
  1123. .Ldone:
  1124. popl %ebx
  1125. popl %edi
  1126. popl %esi
  1127. end;
  1128. {$endif}
  1129. {****************************************************************************
  1130. Bounds Check
  1131. ****************************************************************************}
  1132. { do a thread-safe inc/dec }
  1133. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  1134. function cpudeclocked(var l : longint) : boolean;assembler;nostackframe;
  1135. asm
  1136. { this check should be done because a lock takes a lot }
  1137. { of time! }
  1138. lock
  1139. decl (%eax)
  1140. setzb %al
  1141. end;
  1142. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  1143. procedure cpuinclocked(var l : longint);assembler;nostackframe;
  1144. asm
  1145. lock
  1146. incl (%eax)
  1147. end;
  1148. // inline SMP check and normal lock.
  1149. // the locked one is so slow, inlining doesn't matter.
  1150. function declocked(var l : longint) : boolean; inline;
  1151. begin
  1152. if not ismultithread then
  1153. begin
  1154. dec(l);
  1155. declocked:=l=0;
  1156. end
  1157. else
  1158. declocked:=cpudeclocked(l);
  1159. end;
  1160. procedure inclocked(var l : longint); inline;
  1161. begin
  1162. if not ismultithread then
  1163. inc(l)
  1164. else
  1165. cpuinclocked(l);
  1166. end;
  1167. function InterLockedDecrement (var Target: longint) : longint; assembler;
  1168. asm
  1169. movl $-1,%edx
  1170. xchgl %edx,%eax
  1171. lock
  1172. xaddl %eax, (%edx)
  1173. decl %eax
  1174. end;
  1175. function InterLockedIncrement (var Target: longint) : longint; assembler;
  1176. asm
  1177. movl $1,%edx
  1178. xchgl %edx,%eax
  1179. lock
  1180. xaddl %eax, (%edx)
  1181. incl %eax
  1182. end;
  1183. function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler;
  1184. asm
  1185. xchgl (%eax),%edx
  1186. movl %edx,%eax
  1187. end;
  1188. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler;
  1189. asm
  1190. xchgl %eax,%edx
  1191. lock
  1192. xaddl %eax, (%edx)
  1193. end;
  1194. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler;
  1195. asm
  1196. xchgl %eax,%ecx
  1197. lock
  1198. cmpxchgl %edx, (%ecx)
  1199. end;
  1200. function InterlockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64; assembler;
  1201. asm
  1202. pushl %ebx
  1203. pushl %edi
  1204. movl %eax,%edi
  1205. movl Comperand+4,%edx
  1206. movl Comperand+0,%eax
  1207. movl NewValue+4,%ecx
  1208. movl NewValue+0,%ebx
  1209. lock cmpxchg8b (%edi)
  1210. pop %edi
  1211. pop %ebx
  1212. end;
  1213. {****************************************************************************
  1214. FPU
  1215. ****************************************************************************}
  1216. const
  1217. { Internal constants for use in system unit }
  1218. FPU_Invalid = 1;
  1219. FPU_Denormal = 2;
  1220. FPU_DivisionByZero = 4;
  1221. FPU_Overflow = 8;
  1222. FPU_Underflow = $10;
  1223. FPU_StackUnderflow = $20;
  1224. FPU_StackOverflow = $40;
  1225. FPU_ExceptionMask = $ff;
  1226. { use Default8087CW instead
  1227. fpucw : word = $1300 or FPU_StackUnderflow or FPU_Underflow or FPU_Denormal;
  1228. }
  1229. MM_MaskInvalidOp = %0000000010000000;
  1230. MM_MaskDenorm = %0000000100000000;
  1231. MM_MaskDivZero = %0000001000000000;
  1232. MM_MaskOverflow = %0000010000000000;
  1233. MM_MaskUnderflow = %0000100000000000;
  1234. MM_MaskPrecision = %0001000000000000;
  1235. mxcsr : dword = MM_MaskUnderflow or MM_MaskPrecision or MM_MaskDenorm;
  1236. {$define FPC_SYSTEM_HAS_SYSINITFPU}
  1237. Procedure SysInitFPU;
  1238. var
  1239. { these locals are so we don't have to hack pic code in the assembler }
  1240. localmxcsr: dword;
  1241. localfpucw: word;
  1242. begin
  1243. localfpucw:=Default8087CW;
  1244. asm
  1245. fninit
  1246. fldcw localfpucw
  1247. fwait
  1248. end;
  1249. if has_sse_support then
  1250. begin
  1251. localmxcsr:=mxcsr;
  1252. asm
  1253. { setup sse exceptions }
  1254. ldmxcsr localmxcsr
  1255. end;
  1256. end;
  1257. softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;
  1258. end;
  1259. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  1260. Procedure SysResetFPU;
  1261. var
  1262. { these locals are so we don't have to hack pic code in the assembler }
  1263. localmxcsr: dword;
  1264. localfpucw: word;
  1265. begin
  1266. localfpucw:=Default8087CW;
  1267. asm
  1268. fninit
  1269. fwait
  1270. fldcw localfpucw
  1271. end;
  1272. if has_sse_support then
  1273. begin
  1274. localmxcsr:=mxcsr;
  1275. asm
  1276. { setup sse exceptions }
  1277. ldmxcsr localmxcsr
  1278. end;
  1279. end;
  1280. softfloat_exception_flags:=0;
  1281. end;
  1282. { because of the brain dead sse detection on x86, this test is post poned }
  1283. procedure fpc_cpucodeinit;
  1284. begin
  1285. os_supports_sse:=true;
  1286. check_sse_support;
  1287. os_supports_sse:=has_sse_support;
  1288. if os_supports_sse then
  1289. begin
  1290. sse_check:=true;
  1291. asm
  1292. { force an sse exception if no sse is supported, the exception handler sets
  1293. os_supports_sse to false then }
  1294. { don't change this instruction, the code above depends on its size }
  1295. movaps %xmm7, %xmm6
  1296. end;
  1297. sse_check:=false;
  1298. end;
  1299. has_sse_support:=os_supports_sse;
  1300. if not(has_sse_support) then
  1301. begin
  1302. has_sse2_support:=false;
  1303. has_sse3_support:=false;
  1304. end;
  1305. { don't let libraries influence the FPU cw set by the host program }
  1306. if has_sse_support and
  1307. IsLibrary then
  1308. mxcsr:=GetSSECSR;
  1309. has_mmx_support:=mmx_support;
  1310. SysResetFPU;
  1311. if not(IsLibrary) then
  1312. SysInitFPU;
  1313. {$ifdef USE_FASTMOVE}
  1314. setup_fastmove;
  1315. {$endif}
  1316. end;
  1317. {$if not defined(darwin) and defined(regcall) }
  1318. { darwin requires that the stack is aligned to 16 bytes when calling another function }
  1319. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  1320. {$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  1321. function fpc_freemem_x(p:pointer):ptrint; [external name 'FPC_FREEMEM_X'];
  1322. Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
  1323. asm
  1324. cmpl $0,(%eax)
  1325. je .Lquit
  1326. pushl %esi
  1327. movl (%eax),%esi
  1328. subl $12,%esi // points to start of allocation
  1329. movl $0,(%eax) // s:=nil
  1330. cmpl $0,4(%esi) // exit if refcount<0
  1331. jl .Lj3596
  1332. {$ifdef FPC_PIC}
  1333. pushl %ebx
  1334. call fpc_geteipasebx
  1335. addl $_GLOBAL_OFFSET_TABLE_,%ebx
  1336. movl ismultithread@GOT(%ebx),%ebx
  1337. movl (%ebx),%ebx
  1338. cmp $0, %ebx
  1339. popl %ebx
  1340. {$else FPC_PIC}
  1341. cmpl $0,ismultithread
  1342. {$endif FPC_PIC}
  1343. jne .Lj3610
  1344. decl 4(%esi)
  1345. je .Lj3620
  1346. jmp .Lj3596
  1347. .Lj3610:
  1348. leal 4(%esi),%eax
  1349. call cpudeclocked
  1350. testb %al,%al
  1351. je .Lj3596
  1352. .Lj3620:
  1353. movl %esi,%eax
  1354. call FPC_FREEMEM_X
  1355. .Lj3596:
  1356. popl %esi
  1357. .Lquit:
  1358. end;
  1359. function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;
  1360. {$define FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  1361. Function fpc_ansistr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_ANSISTR_UNIQUE']; compilerproc; nostackframe;assembler;
  1362. asm
  1363. // Var S located in register
  1364. // Var $result located in register
  1365. movl %eax,%edx
  1366. // [437] pointer(result) := pointer(s);
  1367. movl (%eax),%eax
  1368. // [438] If Pointer(S)=Nil then
  1369. testl %eax,%eax
  1370. je .Lj4031
  1371. .Lj4036:
  1372. // [440] if PAnsiRec(Pointer(S)-Firstoff)^.Ref<>1 then
  1373. movl -8(%eax),%ecx
  1374. cmpl $1,%ecx
  1375. je .Lj4038
  1376. // [441] result:=fpc_truely_ansistr_unique(s);
  1377. movl %edx,%eax
  1378. call fpc_truely_ansistr_unique
  1379. .Lj4038:
  1380. .Lj4031:
  1381. // [442] end;
  1382. end;
  1383. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  1384. {$endif ndef darwin and defined(regcall) }
  1385. {$ifndef FPC_SYSTEM_HAS_MEM_BARRIER}
  1386. {$define FPC_SYSTEM_HAS_MEM_BARRIER}
  1387. procedure ReadBarrier;assembler;nostackframe;
  1388. asm
  1389. lock
  1390. addl $0,0(%esp)
  1391. { alternative: lfence on SSE capable CPUs }
  1392. end;
  1393. procedure ReadDependencyBarrier;{$ifdef SYSTEMINLINE}inline;{$endif}
  1394. begin
  1395. { reads imply barrier on earlier reads depended on }
  1396. end;
  1397. procedure ReadWriteBarrier;assembler;nostackframe;
  1398. asm
  1399. lock
  1400. addl $0,0(%esp)
  1401. { alternative: mfence on SSE capable CPUs }
  1402. end;
  1403. procedure WriteBarrier;assembler;nostackframe;
  1404. asm
  1405. { no write reordering on intel CPUs (yet) }
  1406. end;
  1407. {$endif}
  1408. {$ifndef FPC_SYSTEM_HAS_BSF_QWORD}
  1409. {$define FPC_SYSTEM_HAS_BSF_QWORD}
  1410. function BsfQWord(Const AValue : QWord): cardinal; assembler; nostackframe;
  1411. asm
  1412. bsfl 4(%esp),%eax
  1413. jnz .L2
  1414. .L1:
  1415. bsfl 8(%esp),%eax
  1416. jnz .L3
  1417. movl $223,%eax
  1418. .L3:
  1419. addl $32,%eax
  1420. .L2:
  1421. end;
  1422. {$endif FPC_SYSTEM_HAS_BSF_QWORD}
  1423. {$ifndef FPC_SYSTEM_HAS_BSR_QWORD}
  1424. {$define FPC_SYSTEM_HAS_BSR_QWORD}
  1425. function BsrQWord(Const AValue : QWord): cardinal; assembler; nostackframe;
  1426. asm
  1427. bsrl 8(%esp),%eax
  1428. jz .L1
  1429. add $32,%eax
  1430. jmp .L2
  1431. .L1:
  1432. bsrl 4(%esp),%eax
  1433. jnz .L2
  1434. movl $255,%eax
  1435. .L2:
  1436. end;
  1437. {$endif FPC_SYSTEM_HAS_BSR_QWORD}
  1438. {$ifndef FPC_SYSTEM_HAS_SAR_QWORD}
  1439. {$define FPC_SYSTEM_HAS_SAR_QWORD}
  1440. function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64; [Public,Alias:'FPC_SARINT64']; compilerproc; assembler; nostackframe;
  1441. asm
  1442. movb %al,%cl
  1443. movl 8(%esp),%edx
  1444. movl 4(%esp),%eax
  1445. andb $63,%cl
  1446. cmpb $32,%cl
  1447. jnb .L1
  1448. shrdl %cl,%edx,%eax
  1449. sarl %cl,%edx
  1450. jmp .Lexit
  1451. .L1:
  1452. movl %edx,%eax
  1453. sarl $31,%edx
  1454. andb $31,%cl
  1455. sarl %cl,%eax
  1456. .Lexit:
  1457. end;
  1458. {$endif FPC_SYSTEM_HAS_SAR_QWORD}