i386.inc 32 KB

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