i386.inc 40 KB

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