i386.inc 41 KB

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