i386.inc 32 KB

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