i386.inc 38 KB

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