i386.inc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  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. has_sse_support,has_mmx_support : boolean;
  17. {$asmmode intel}
  18. function cpuid_support : boolean;assembler;
  19. {
  20. Check if the ID-flag can be changed, if changed then CpuID is supported.
  21. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  22. }
  23. asm
  24. pushf
  25. pushf
  26. pop eax
  27. mov ebx,eax
  28. xor eax,200000h
  29. push eax
  30. popf
  31. pushf
  32. pop eax
  33. popf
  34. and eax,200000h
  35. and ebx,200000h
  36. cmp eax,ebx
  37. setnz al
  38. end;
  39. {$asmmode ATT}
  40. function sse_support : boolean;
  41. var
  42. _edx : longint;
  43. begin
  44. if cpuid_support then
  45. begin
  46. asm
  47. movl $1,%eax
  48. cpuid
  49. movl %edx,_edx
  50. end;
  51. sse_support:=(_edx and $2000000)<>0;
  52. end
  53. else
  54. { a cpu with without cpuid instruction supports never sse }
  55. sse_support:=false;
  56. end;
  57. { returns true, if the processor supports the mmx instructions }
  58. function mmx_support : boolean;
  59. var
  60. _edx : longint;
  61. begin
  62. if cpuid_support then
  63. begin
  64. asm
  65. movl $1,%eax
  66. cpuid
  67. movl %edx,_edx
  68. end;
  69. mmx_support:=(_edx and $800000)<>0;
  70. end
  71. else
  72. { a cpu with without cpuid instruction supports never mmx }
  73. mmx_support:=false;
  74. end;
  75. {$i fastmove.inc}
  76. procedure fpc_cpuinit;
  77. begin
  78. has_sse_support:=sse_support;
  79. has_mmx_support:=mmx_support;
  80. setup_fastmove;
  81. end;
  82. function geteipasebx : pointer;assembler;[public,alias:'FPC_GETEIPINEBX'];
  83. asm
  84. movl (%esp),%ebx
  85. ret
  86. end;
  87. {$ifndef FPC_SYSTEM_HAS_MOVE}
  88. {$define FPC_SYSTEM_HAS_MOVE}
  89. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];assembler;
  90. var
  91. saveesi,saveedi : longint;
  92. asm
  93. movl %edi,saveedi
  94. movl %esi,saveesi
  95. {$ifdef REGCALL}
  96. movl %eax,%esi
  97. movl %edx,%edi
  98. movl %ecx,%edx
  99. {$else}
  100. movl dest,%edi
  101. movl source,%esi
  102. movl count,%edx
  103. {$endif}
  104. movl %edi,%eax
  105. { check for zero or negative count }
  106. cmpl $0,%edx
  107. jle .LMoveEnd
  108. { Check for back or forward }
  109. sub %esi,%eax
  110. jz .LMoveEnd { Do nothing when source=dest }
  111. jc .LFMove { Do forward, dest<source }
  112. cmp %edx,%eax
  113. jb .LBMove { Dest is in range of move, do backward }
  114. { Forward Copy }
  115. .LFMove:
  116. cld
  117. cmpl $15,%edx
  118. jl .LFMove1
  119. movl %edi,%ecx { Align on 32bits }
  120. negl %ecx
  121. andl $3,%ecx
  122. subl %ecx,%edx
  123. rep
  124. movsb
  125. movl %edx,%ecx
  126. andl $3,%edx
  127. shrl $2,%ecx
  128. rep
  129. movsl
  130. .LFMove1:
  131. movl %edx,%ecx
  132. rep
  133. movsb
  134. jmp .LMoveEnd
  135. { Backward Copy }
  136. .LBMove:
  137. std
  138. addl %edx,%esi
  139. addl %edx,%edi
  140. movl %edi,%ecx
  141. decl %esi
  142. decl %edi
  143. cmpl $15,%edx
  144. jl .LBMove1
  145. negl %ecx { Align on 32bits }
  146. andl $3,%ecx
  147. subl %ecx,%edx
  148. rep
  149. movsb
  150. movl %edx,%ecx
  151. andl $3,%edx
  152. shrl $2,%ecx
  153. subl $3,%esi
  154. subl $3,%edi
  155. rep
  156. movsl
  157. addl $3,%esi
  158. addl $3,%edi
  159. .LBMove1:
  160. movl %edx,%ecx
  161. rep
  162. movsb
  163. cld
  164. .LMoveEnd:
  165. movl saveedi,%edi
  166. movl saveesi,%esi
  167. end;
  168. {$endif FPC_SYSTEM_HAS_MOVE}
  169. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  170. {$define FPC_SYSTEM_HAS_FILLCHAR}
  171. Procedure FillChar(var x;count:SizeInt;value:byte);assembler;
  172. asm
  173. {A push is prefered over a local variable because a local
  174. variable causes the compiler to generate a stackframe.}
  175. cld
  176. {$ifdef REGCALL}
  177. push %edi
  178. movl %eax,%edi
  179. movzbl %cl,%eax
  180. movl %edx,%ecx
  181. {$else}
  182. movl x,%edi
  183. movl count,%ecx
  184. movzbl value,%eax
  185. movl %ecx,%edx
  186. {$endif}
  187. { check for zero or negative count }
  188. or %ecx,%ecx
  189. jle .LFillEnd
  190. cmpl $7,%ecx
  191. jl .LFill1
  192. imul $0x01010101,%eax { Expand al into a 4 subbytes of eax}
  193. shrl $2,%ecx
  194. andl $3,%edx
  195. rep
  196. stosl
  197. movl %edx,%ecx
  198. .LFill1:
  199. rep
  200. stosb
  201. .LFillEnd:
  202. {$ifdef REGCALL}
  203. pop %edi
  204. {$endif}
  205. end;
  206. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  207. {$ifndef FPC_SYSTEM_HAS_FILLWORD}
  208. {$define FPC_SYSTEM_HAS_FILLWORD}
  209. procedure fillword(var x;count : SizeInt;value : word);assembler;
  210. var
  211. saveedi : longint;
  212. asm
  213. movl %edi,saveedi
  214. {$ifdef REGCALL}
  215. movl %eax,%edi
  216. movzwl %cx,%eax
  217. movl %edx,%ecx
  218. {$else}
  219. movl x,%edi
  220. movl count,%ecx
  221. movzwl value,%eax
  222. {$endif}
  223. { check for zero or negative count }
  224. cmpl $0,%ecx
  225. jle .LFillWordEnd
  226. movl %eax,%edx
  227. shll $16,%eax
  228. orl %edx,%eax
  229. movl %ecx,%edx
  230. shrl $1,%ecx
  231. cld
  232. rep
  233. stosl
  234. movl %edx,%ecx
  235. andl $1,%ecx
  236. rep
  237. stosw
  238. .LFillWordEnd:
  239. movl saveedi,%edi
  240. end;
  241. {$endif FPC_SYSTEM_HAS_FILLWORD}
  242. {$ifndef FPC_SYSTEM_HAS_FILLDWORD}
  243. {$define FPC_SYSTEM_HAS_FILLDWORD}
  244. procedure filldword(var x;count : SizeInt;value : dword);assembler;
  245. var
  246. saveedi : longint;
  247. asm
  248. movl %edi,saveedi
  249. {$ifdef REGCALL}
  250. movl %eax,%edi
  251. movl %ecx,%eax
  252. movl %edx,%ecx
  253. {$else}
  254. movl x,%edi
  255. movl count,%ecx
  256. movl value,%eax
  257. {$endif}
  258. { check for zero or negative count }
  259. cmpl $0,%ecx
  260. jle .LFillDWordEnd
  261. cld
  262. rep
  263. stosl
  264. .LFillDWordEnd:
  265. movl saveedi,%edi
  266. end;
  267. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  268. {$ifndef FPC_SYSTEM_HAS_INDEXBYTE}
  269. {$define FPC_SYSTEM_HAS_INDEXBYTE}
  270. function IndexByte(Const buf;len:SizeInt;b:byte):SizeInt; assembler;
  271. var
  272. saveedi,saveebx : longint;
  273. asm
  274. movl %edi,saveedi
  275. movl %ebx,saveebx
  276. movl buf,%edi // Load String
  277. movb b,%bl
  278. movl len,%ecx // Load len
  279. xorl %eax,%eax
  280. testl %ecx,%ecx
  281. jz .Lcharposnotfound
  282. cld
  283. movl %ecx,%edx // Copy for easy manipulation
  284. movb %bl,%al
  285. repne
  286. scasb
  287. jne .Lcharposnotfound
  288. incl %ecx
  289. subl %ecx,%edx
  290. movl %edx,%eax
  291. jmp .Lready
  292. .Lcharposnotfound:
  293. movl $-1,%eax
  294. .Lready:
  295. movl saveedi,%edi
  296. movl saveebx,%ebx
  297. end;
  298. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  299. {$ifndef FPC_SYSTEM_HAS_INDEXWORD}
  300. {$define FPC_SYSTEM_HAS_INDEXWORD}
  301. function Indexword(Const buf;len:SizeInt;b:word):SizeInt; assembler;
  302. var
  303. saveedi,saveebx : longint;
  304. asm
  305. movl %edi,saveedi
  306. movl %ebx,saveebx
  307. movl Buf,%edi // Load String
  308. movw b,%bx
  309. movl Len,%ecx // Load len
  310. xorl %eax,%eax
  311. testl %ecx,%ecx
  312. jz .Lcharposnotfound
  313. cld
  314. movl %ecx,%edx // Copy for easy manipulation
  315. movw %bx,%ax
  316. repne
  317. scasw
  318. jne .Lcharposnotfound
  319. incl %ecx
  320. subl %ecx,%edx
  321. movl %edx,%eax
  322. jmp .Lready
  323. .Lcharposnotfound:
  324. movl $-1,%eax
  325. .Lready:
  326. movl saveedi,%edi
  327. movl saveebx,%ebx
  328. end;
  329. {$endif FPC_SYSTEM_HAS_INDEXWORD}
  330. {$ifndef FPC_SYSTEM_HAS_INDEXDWORD}
  331. {$define FPC_SYSTEM_HAS_INDEXDWORD}
  332. function IndexDWord(Const buf;len:SizeInt;b:DWord):SizeInt; assembler;
  333. var
  334. saveedi,saveebx : longint;
  335. asm
  336. movl %edi,saveedi
  337. movl %ebx,saveebx
  338. {$ifdef REGCALL}
  339. movl %eax,%edi
  340. movl %ecx,%ebx
  341. movl %edx,%ecx
  342. {$else}
  343. movl Len,%ecx // Load len
  344. movl Buf,%edi // Load String
  345. movl b,%ebx
  346. {$endif}
  347. xorl %eax,%eax
  348. testl %ecx,%ecx
  349. jz .Lcharposnotfound
  350. cld
  351. movl %ecx,%edx // Copy for easy manipulation
  352. movl %ebx,%eax
  353. repne
  354. scasl
  355. jne .Lcharposnotfound
  356. incl %ecx
  357. subl %ecx,%edx
  358. movl %edx,%eax
  359. jmp .Lready
  360. .Lcharposnotfound:
  361. movl $-1,%eax
  362. .Lready:
  363. movl saveedi,%edi
  364. movl saveebx,%ebx
  365. end;
  366. {$endif FPC_SYSTEM_HAS_INDEXDWORD}
  367. {$ifndef FPC_SYSTEM_HAS_COMPAREBYTE}
  368. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  369. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  370. var
  371. saveesi,saveedi : longint;
  372. asm
  373. movl %edi,saveedi
  374. movl %esi,saveesi
  375. cld
  376. {$ifdef REGCALL}
  377. movl %eax,%edi
  378. movl %edx,%esi
  379. movl %ecx,%eax
  380. {$else}
  381. movl len,%eax
  382. movl buf2,%esi { Load params}
  383. movl buf1,%edi
  384. {$endif}
  385. testl %eax,%eax {We address -1(%esi), so we have to deal with len=0}
  386. je .LCmpbyteExit
  387. cmpl $7,%eax {<7 not worth aligning and go through all trouble}
  388. jl .LCmpbyte2
  389. movl %edi,%ecx { Align on 32bits }
  390. negl %ecx { calc bytes to align (%edi and 3) xor 3= -%edi and 3}
  391. andl $3,%ecx
  392. subl %ecx,%eax { Subtract from number of bytes to go}
  393. orl %ecx,%ecx
  394. rep
  395. cmpsb {The actual 32-bit Aligning}
  396. jne .LCmpbyte3
  397. movl %eax,%ecx {bytes to do, divide by 4}
  398. andl $3,%eax {remainder}
  399. shrl $2,%ecx {The actual division}
  400. orl %ecx,%ecx {Sets zero flag if ecx=0 -> no cmp}
  401. rep
  402. cmpsl
  403. je .LCmpbyte2 { All equal? then to the left over bytes}
  404. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  405. subl %eax,%esi
  406. subl %eax,%edi
  407. .LCmpbyte2:
  408. movl %eax,%ecx {bytes still to (re)scan}
  409. orl %eax,%eax {prevent disaster in case %eax=0}
  410. rep
  411. cmpsb
  412. .LCmpbyte3:
  413. movzbl -1(%esi),%ecx
  414. movzbl -1(%edi),%eax // Compare failing (or equal) position
  415. subl %ecx,%eax
  416. .LCmpbyteExit:
  417. movl saveedi,%edi
  418. movl saveesi,%esi
  419. end;
  420. {$endif FPC_SYSTEM_HAS_COMPAREBYTE}
  421. {$ifndef FPC_SYSTEM_HAS_COMPAREWORD}
  422. {$define FPC_SYSTEM_HAS_COMPAREWORD}
  423. function CompareWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  424. var
  425. saveesi,saveedi,saveebx : longint;
  426. asm
  427. movl %edi,saveedi
  428. movl %esi,saveesi
  429. movl %ebx,saveebx
  430. cld
  431. {$ifdef REGCALL}
  432. movl %eax,%edi
  433. movl %edx,%esi
  434. movl %ecx,%eax
  435. {$else}
  436. movl len,%eax
  437. movl buf2,%esi { Load params}
  438. movl buf1,%edi
  439. {$endif}
  440. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  441. je .LCmpwordExit
  442. cmpl $5,%eax {<5 (3 bytes align + 4 bytes cmpsl = 4 words}
  443. jl .LCmpword2 { not worth aligning and go through all trouble}
  444. movl (%edi),%ebx // Compare alignment bytes.
  445. cmpl (%esi),%ebx
  446. jne .LCmpword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  447. shll $1,%eax {Convert word count to bytes}
  448. movl %edi,%edx { Align comparing is already done, so simply add}
  449. negl %edx { calc bytes to align -%edi and 3}
  450. andl $3,%edx
  451. addl %edx,%esi { Skip max 3 bytes alignment}
  452. addl %edx,%edi
  453. subl %edx,%eax { Subtract from number of bytes to go}
  454. movl %eax,%ecx { Make copy of bytes to go}
  455. andl $3,%eax { Calc remainder (mod 4) }
  456. andl $1,%edx { %edx is 1 if array not 2-aligned, 0 otherwise}
  457. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  458. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  459. rep { Compare entire DWords}
  460. cmpsl
  461. je .LCmpword2a { All equal? then to the left over bytes}
  462. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  463. subl %eax,%esi { Go back one DWord}
  464. subl %eax,%edi
  465. incl %eax {if not odd then this does nothing, else it makes
  466. sure that adding %edx increases from 2 to 3 words}
  467. .LCmpword2a:
  468. subl %edx,%esi { Subtract alignment}
  469. subl %edx,%edi
  470. addl %edx,%eax
  471. shrl $1,%eax
  472. .LCmpword2:
  473. movl %eax,%ecx {words still to (re)scan}
  474. orl %eax,%eax {prevent disaster in case %eax=0}
  475. rep
  476. cmpsw
  477. .LCmpword3:
  478. movzwl -2(%esi),%ecx
  479. movzwl -2(%edi),%eax // Compare failing (or equal) position
  480. subl %ecx,%eax // calculate end result.
  481. .LCmpwordExit:
  482. movl saveedi,%edi
  483. movl saveesi,%esi
  484. movl saveebx,%ebx
  485. end;
  486. {$endif FPC_SYSTEM_HAS_COMPAREWORD}
  487. {$ifndef FPC_SYSTEM_HAS_COMPAREDWORD}
  488. {$define FPC_SYSTEM_HAS_COMPAREDWORD}
  489. function CompareDWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler;
  490. var
  491. saveesi,saveedi,saveebx : longint;
  492. asm
  493. movl %edi,saveedi
  494. movl %esi,saveesi
  495. movl %ebx,saveebx
  496. cld
  497. {$ifdef REGCALL}
  498. movl %eax,%edi
  499. movl %edx,%esi
  500. movl %ecx,%eax
  501. {$else}
  502. movl len,%eax
  503. movl buf2,%esi { Load params}
  504. movl buf1,%edi
  505. {$endif}
  506. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  507. je .LCmpDwordExit
  508. cmpl $3,%eax {<3 (3 bytes align + 4 bytes cmpsl) = 2 DWords}
  509. jl .LCmpDword2 { not worth aligning and go through all trouble}
  510. movl (%edi),%ebx // Compare alignment bytes.
  511. cmpl (%esi),%ebx
  512. jne .LCmpDword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  513. shll $2,%eax {Convert word count to bytes}
  514. movl %edi,%edx { Align comparing is already done, so simply add}
  515. negl %edx { calc bytes to align -%edi and 3}
  516. andl $3,%edx
  517. addl %edx,%esi { Skip max 3 bytes alignment}
  518. addl %edx,%edi
  519. subl %edx,%eax { Subtract from number of bytes to go}
  520. movl %eax,%ecx { Make copy of bytes to go}
  521. andl $3,%eax { Calc remainder (mod 4) }
  522. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  523. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  524. rep { Compare entire DWords}
  525. cmpsl
  526. je .LCmpDword2a { All equal? then to the left over bytes}
  527. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  528. subl %eax,%esi { Go back one DWord}
  529. subl %eax,%edi
  530. addl $3,%eax {if align<>0 this causes repcount to be 2}
  531. .LCmpDword2a:
  532. subl %edx,%esi { Subtract alignment}
  533. subl %edx,%edi
  534. addl %edx,%eax
  535. shrl $2,%eax
  536. .LCmpDword2:
  537. movl %eax,%ecx {words still to (re)scan}
  538. orl %eax,%eax {prevent disaster in case %eax=0}
  539. rep
  540. cmpsl
  541. .LCmpDword3:
  542. movzwl -4(%esi),%ecx
  543. movzwl -4(%edi),%eax // Compare failing (or equal) position
  544. subl %ecx,%eax // calculate end result.
  545. .LCmpDwordExit:
  546. movl saveedi,%edi
  547. movl saveesi,%esi
  548. movl saveebx,%ebx
  549. end;
  550. {$endif FPC_SYSTEM_HAS_COMPAREDWORD}
  551. {$ifndef FPC_SYSTEM_HAS_INDEXCHAR0}
  552. {$define FPC_SYSTEM_HAS_INDEXCHAR0}
  553. function IndexChar0(Const buf;len:SizeInt;b:Char):SizeInt; assembler;
  554. var
  555. saveesi,saveebx : longint;
  556. asm
  557. movl %esi,saveesi
  558. movl %ebx,saveebx
  559. // Can't use scasb, or will have to do it twice, think this
  560. // is faster for small "len"
  561. {$ifdef REGCALL}
  562. movl %eax,%esi // Load address
  563. movzbl %cl,%ebx // Load searchpattern
  564. {$else}
  565. movl Buf,%esi // Load address
  566. movl len,%edx // load maximal searchdistance
  567. movzbl b,%ebx // Load searchpattern
  568. {$endif}
  569. testl %edx,%edx
  570. je .LFound
  571. xorl %ecx,%ecx // zero index in Buf
  572. xorl %eax,%eax // To make DWord compares possible
  573. .LLoop:
  574. movb (%esi),%al // Load byte
  575. cmpb %al,%bl
  576. je .LFound // byte the same?
  577. incl %ecx
  578. incl %esi
  579. cmpl %edx,%ecx // Maximal distance reached?
  580. je .LNotFound
  581. testl %eax,%eax // Nullchar = end of search?
  582. jne .LLoop
  583. .LNotFound:
  584. movl $-1,%ecx // Not found return -1
  585. .LFound:
  586. movl %ecx,%eax
  587. movl saveesi,%esi
  588. movl saveebx,%ebx
  589. end;
  590. {$endif FPC_SYSTEM_HAS_INDEXCHAR0}
  591. {****************************************************************************
  592. String
  593. ****************************************************************************}
  594. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  595. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  596. function fpc_shortstr_to_shortstr(len:longint; const sstr: shortstring): shortstring; [public,alias: 'FPC_SHORTSTR_TO_SHORTSTR']; compilerproc;
  597. begin
  598. asm
  599. cld
  600. movl __RESULT,%edi
  601. movl sstr,%esi
  602. xorl %eax,%eax
  603. movl len,%ecx
  604. lodsb
  605. cmpl %ecx,%eax
  606. jbe .LStrCopy1
  607. movl %ecx,%eax
  608. .LStrCopy1:
  609. stosb
  610. cmpl $7,%eax
  611. jl .LStrCopy2
  612. movl %edi,%ecx { Align on 32bits }
  613. negl %ecx
  614. andl $3,%ecx
  615. subl %ecx,%eax
  616. rep
  617. movsb
  618. movl %eax,%ecx
  619. andl $3,%eax
  620. shrl $2,%ecx
  621. rep
  622. movsl
  623. .LStrCopy2:
  624. movl %eax,%ecx
  625. rep
  626. movsb
  627. end ['ESI','EDI','EAX','ECX'];
  628. end;
  629. procedure fpc_shortstr_assign(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_ASSIGN'];
  630. begin
  631. asm
  632. pushl %eax
  633. pushl %ecx
  634. cld
  635. movl dstr,%edi
  636. movl sstr,%esi
  637. xorl %eax,%eax
  638. movl len,%ecx
  639. lodsb
  640. cmpl %ecx,%eax
  641. jbe .LStrCopy1
  642. movl %ecx,%eax
  643. .LStrCopy1:
  644. stosb
  645. cmpl $7,%eax
  646. jl .LStrCopy2
  647. movl %edi,%ecx { Align on 32bits }
  648. negl %ecx
  649. andl $3,%ecx
  650. subl %ecx,%eax
  651. rep
  652. movsb
  653. movl %eax,%ecx
  654. andl $3,%eax
  655. shrl $2,%ecx
  656. rep
  657. movsl
  658. .LStrCopy2:
  659. movl %eax,%ecx
  660. rep
  661. movsb
  662. popl %ecx
  663. popl %eax
  664. end ['ESI','EDI'];
  665. end;
  666. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  667. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  668. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  669. function fpc_shortstr_concat(const s1,s2:shortstring):shortstring;compilerproc;
  670. begin
  671. asm
  672. movl __RESULT,%edi
  673. movl %edi,%ebx
  674. movl s1,%esi { first string }
  675. lodsb
  676. andl $0x0ff,%eax
  677. stosb
  678. cmpl $7,%eax
  679. jl .LStrConcat1
  680. movl %edi,%ecx { Align on 32bits }
  681. negl %ecx
  682. andl $3,%ecx
  683. subl %ecx,%eax
  684. rep
  685. movsb
  686. movl %eax,%ecx
  687. andl $3,%eax
  688. shrl $2,%ecx
  689. rep
  690. movsl
  691. .LStrConcat1:
  692. movl %eax,%ecx
  693. rep
  694. movsb
  695. movl s2,%esi { second string }
  696. movzbl (%ebx),%ecx
  697. negl %ecx
  698. addl $0x0ff,%ecx
  699. lodsb
  700. cmpl %ecx,%eax
  701. jbe .LStrConcat2
  702. movl %ecx,%eax
  703. .LStrConcat2:
  704. addb %al,(%ebx)
  705. cmpl $7,%eax
  706. jl .LStrConcat3
  707. movl %edi,%ecx { Align on 32bits }
  708. negl %ecx
  709. andl $3,%ecx
  710. subl %ecx,%eax
  711. rep
  712. movsb
  713. movl %eax,%ecx
  714. andl $3,%eax
  715. shrl $2,%ecx
  716. rep
  717. movsl
  718. .LStrConcat3:
  719. movl %eax,%ecx
  720. rep
  721. movsb
  722. end ['EBX','ECX','EAX','ESI','EDI'];
  723. end;
  724. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  725. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  726. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  727. procedure fpc_shortstr_append_shortstr(var s1:shortstring;const s2:shortstring);compilerproc;
  728. [public,alias:'FPC_SHORTSTR_APPEND_SHORTSTR'];
  729. begin
  730. asm
  731. movl s1,%edi
  732. movl s2,%esi
  733. movl %edi,%ebx
  734. movzbl (%edi),%ecx
  735. movl __HIGH(s1),%eax
  736. lea 1(%edi,%ecx),%edi
  737. negl %ecx
  738. addl %eax,%ecx
  739. // no need to zero eax, high(s1) <= 255
  740. lodsb
  741. cmpl %ecx,%eax
  742. jbe .LStrConcat1
  743. movl %ecx,%eax
  744. .LStrConcat1:
  745. addb %al,(%ebx)
  746. cmpl $7,%eax
  747. jl .LStrConcat2
  748. movl %edi,%ecx { Align on 32bits }
  749. negl %ecx
  750. andl $3,%ecx
  751. subl %ecx,%eax
  752. rep
  753. movsb
  754. movl %eax,%ecx
  755. andl $3,%eax
  756. shrl $2,%ecx
  757. rep
  758. movsl
  759. .LStrConcat2:
  760. movl %eax,%ecx
  761. rep
  762. movsb
  763. end ['EBX','ECX','EAX','ESI','EDI'];
  764. end;
  765. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
  766. {$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  767. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  768. function fpc_shortstr_compare(const left,right:shortstring): longint;assembler; [public,alias:'FPC_SHORTSTR_COMPARE']; compilerproc;
  769. var
  770. saveesi,saveedi,saveebx : longint;
  771. asm
  772. movl %edi,saveedi
  773. movl %esi,saveesi
  774. movl %ebx,saveebx
  775. cld
  776. movl right,%esi
  777. movl left,%edi
  778. movzbl (%esi),%eax
  779. movzbl (%edi),%ebx
  780. movl %eax,%edx
  781. incl %esi
  782. incl %edi
  783. cmpl %ebx,%eax
  784. jbe .LStrCmp1
  785. movl %ebx,%eax
  786. .LStrCmp1:
  787. cmpl $7,%eax
  788. jl .LStrCmp2
  789. movl %edi,%ecx { Align on 32bits }
  790. negl %ecx
  791. andl $3,%ecx
  792. subl %ecx,%eax
  793. orl %ecx,%ecx
  794. rep
  795. cmpsb
  796. jne .LStrCmp3
  797. movl %eax,%ecx
  798. andl $3,%eax
  799. shrl $2,%ecx
  800. orl %ecx,%ecx
  801. rep
  802. cmpsl
  803. je .LStrCmp2
  804. movl $4,%eax
  805. subl %eax,%esi
  806. subl %eax,%edi
  807. .LStrCmp2:
  808. movl %eax,%ecx
  809. orl %eax,%eax
  810. rep
  811. cmpsb
  812. je .LStrCmp4
  813. .LStrCmp3:
  814. movzbl -1(%esi),%edx // Compare failing (or equal) position
  815. movzbl -1(%edi),%ebx
  816. .LStrCmp4:
  817. movl %ebx,%eax // Compare length or position
  818. subl %edx,%eax
  819. movl saveedi,%edi
  820. movl saveesi,%esi
  821. movl saveebx,%ebx
  822. end;
  823. {$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  824. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  825. {$define FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  826. function fpc_pchar_to_shortstr(p:pchar):shortstring;assembler;[public,alias:'FPC_PCHAR_TO_SHORTSTR']; compilerproc;
  827. {$include strpas.inc}
  828. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  829. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  830. {$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  831. function fpc_pchar_length(p:pchar):longint;assembler;[public,alias:'FPC_PCHAR_LENGTH']; compilerproc;
  832. {$include strlen.inc}
  833. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  834. {$define FPC_SYSTEM_HAS_GET_FRAME}
  835. function get_frame:pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  836. asm
  837. movl %ebp,%eax
  838. end ['EAX'];
  839. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  840. function get_caller_addr(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  841. asm
  842. {$ifndef REGCALL}
  843. movl framebp,%eax
  844. {$endif}
  845. orl %eax,%eax
  846. jz .Lg_a_null
  847. movl 4(%eax),%eax
  848. .Lg_a_null:
  849. end ['EAX'];
  850. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  851. function get_caller_frame(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  852. asm
  853. {$ifndef REGCALL}
  854. movl framebp,%eax
  855. {$endif}
  856. orl %eax,%eax
  857. jz .Lgnf_null
  858. movl (%eax),%eax
  859. .Lgnf_null:
  860. end ['EAX'];
  861. {****************************************************************************
  862. Math
  863. ****************************************************************************}
  864. {$define FPC_SYSTEM_HAS_ABS_LONGINT}
  865. function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  866. asm
  867. {$ifndef REGCALL}
  868. movl l,%eax
  869. {$endif}
  870. cltd
  871. xorl %edx,%eax
  872. subl %edx,%eax
  873. end ['EAX','EDX'];
  874. {$define FPC_SYSTEM_HAS_ODD_LONGINT}
  875. function odd(l:longint):boolean;assembler;{$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. andl $1,%eax
  885. setnz %al
  886. end ['EAX'];
  887. {$define FPC_SYSTEM_HAS_SQR_LONGINT}
  888. function sqr(l:longint):longint;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  889. asm
  890. {$ifdef SYSTEMINLINE}
  891. movl l,%eax
  892. {$else}
  893. {$ifndef REGCALL}
  894. movl l,%eax
  895. {$endif}
  896. {$endif}
  897. imull %eax,%eax
  898. end ['EAX'];
  899. {$define FPC_SYSTEM_HAS_SPTR}
  900. Function Sptr : Pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  901. asm
  902. movl %esp,%eax
  903. end;
  904. {****************************************************************************
  905. Str()
  906. ****************************************************************************}
  907. {$define FPC_SYSTEM_HAS_INT_STR_LONGINT}
  908. procedure int_str(l : longint;var s : string);
  909. var
  910. buffer : array[0..15] of byte;
  911. isneg : byte;
  912. begin
  913. { Workaround: }
  914. if l=longint($80000000) then
  915. begin
  916. s:='-2147483648';
  917. exit;
  918. end;
  919. asm
  920. movl l,%eax // load Integer
  921. xorl %ecx,%ecx // String length=0
  922. leal buffer,%ebx
  923. movl $0x0a,%esi // load 10 as dividing constant.
  924. movb $0,isneg
  925. orl %eax,%eax // Sign ?
  926. jns .LM2
  927. movb $1,isneg
  928. negl %eax
  929. .LM2:
  930. cltd
  931. idivl %esi
  932. addb $0x30,%dl // convert Rest to ASCII.
  933. movb %dl,(%ebx)
  934. incl %ecx
  935. incl %ebx
  936. cmpl $0,%eax
  937. jnz .LM2
  938. { now copy the string }
  939. movl s,%edi // Load String address
  940. cmpb $0,isneg
  941. je .LM3
  942. movb $0x2d,(%ebx)
  943. incl %ecx
  944. incl %ebx
  945. .LM3:
  946. movb %cl,(%edi) // Copy String length
  947. incl %edi
  948. .LM4:
  949. decl %ebx
  950. movb (%ebx),%al
  951. stosb
  952. decl %ecx
  953. jnz .LM4
  954. end ['eax','ecx','edx','ebx','esi','edi'];
  955. end;
  956. {$define FPC_SYSTEM_HAS_INT_STR_LONGWORD}
  957. procedure int_str(c : longword;var s : string);
  958. var
  959. buffer : array[0..15] of byte;
  960. begin
  961. asm
  962. movl c,%eax // load CARDINAL
  963. xorl %ecx,%ecx // String length=0
  964. leal buffer,%ebx
  965. movl $0x0a,%esi // load 10 as dividing constant.
  966. .LM4:
  967. xorl %edx,%edx
  968. divl %esi
  969. addb $0x30,%dl // convert Rest to ASCII.
  970. movb %dl,(%ebx)
  971. incl %ecx
  972. incl %ebx
  973. cmpl $0,%eax
  974. jnz .LM4
  975. { now copy the string }
  976. movl s,%edi // Load String address
  977. movb %cl,(%edi) // Copy String length
  978. incl %edi
  979. .LM5:
  980. decl %ebx
  981. movb (%ebx),%al
  982. stosb
  983. decl %ecx
  984. jnz .LM5
  985. end ['eax','ecx','edx','ebx','esi','edi'];
  986. end;
  987. {****************************************************************************
  988. Bounds Check
  989. ****************************************************************************}
  990. { do a thread save inc/dec }
  991. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  992. function cpudeclocked(var l : longint) : boolean;assembler;
  993. asm
  994. {$ifndef REGCALL}
  995. movl l,%eax
  996. {$endif}
  997. { this check should be done because a lock takes a lot }
  998. { of time! }
  999. lock
  1000. decl (%eax)
  1001. setzb %al
  1002. end;
  1003. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  1004. procedure cpuinclocked(var l : longint);assembler;
  1005. asm
  1006. {$ifndef REGCALL}
  1007. movl l,%eax
  1008. {$endif}
  1009. lock
  1010. incl (%eax)
  1011. end;
  1012. // inline SMP check and normal lock.
  1013. // the locked one is so slow, inlining doesn't matter.
  1014. function declocked(var l : longint) : boolean; inline;
  1015. begin
  1016. if not ismultithread then
  1017. begin
  1018. dec(l);
  1019. declocked:=l=0;
  1020. end
  1021. else
  1022. declocked:=cpudeclocked(l);
  1023. end;
  1024. procedure inclocked(var l : longint); inline;
  1025. begin
  1026. if not ismultithread then
  1027. inc(l)
  1028. else
  1029. cpuinclocked(l);
  1030. end;
  1031. {****************************************************************************
  1032. FPU
  1033. ****************************************************************************}
  1034. const
  1035. fpucw : word = $1332;
  1036. { Internal constants for use in system unit }
  1037. FPU_Invalid = 1;
  1038. FPU_Denormal = 2;
  1039. FPU_DivisionByZero = 4;
  1040. FPU_Overflow = 8;
  1041. FPU_Underflow = $10;
  1042. FPU_StackUnderflow = $20;
  1043. FPU_StackOverflow = $40;
  1044. FPU_ExceptionMask = $ff;
  1045. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  1046. Procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  1047. asm
  1048. fninit
  1049. fldcw fpucw
  1050. fwait
  1051. end;