i386.inc 39 KB

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