i386.inc 41 KB

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