i386.inc 33 KB

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