GR32_LowLevel.pas 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
  1. unit GR32_LowLevel;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Michael Hansen <[email protected]>
  32. * Andre Beckedorf <[email protected]>
  33. * Mattias Andersson <[email protected]>
  34. *
  35. * ***** END LICENSE BLOCK ***** *)
  36. interface
  37. {$I GR32.inc}
  38. {$IFDEF PUREPASCAL}
  39. {$DEFINE USENATIVECODE}
  40. {$DEFINE USEMOVE}
  41. {$ENDIF}
  42. {$IFDEF USEINLINING}
  43. {$DEFINE USENATIVECODE}
  44. {$ENDIF}
  45. uses
  46. Graphics, GR32, GR32_Math;
  47. { Clamp function restricts value to [0..255] range }
  48. function Clamp(const Value: Integer): Integer; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  49. { An analogue of FillChar for 32 bit values }
  50. var
  51. FillLongword: procedure(var X; Count: Cardinal; Value: Longword);
  52. procedure FillWord(var X; Count: Cardinal; Value: Longword);
  53. { An analogue of Move for 32 bit values }
  54. {$IFDEF USEMOVE}
  55. procedure MoveLongword(const Source; var Dest; Count: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  56. {$ELSE}
  57. procedure MoveLongword(const Source; var Dest; Count: Integer);
  58. {$ENDIF}
  59. procedure MoveWord(const Source; var Dest; Count: Integer);
  60. {$IFDEF USESTACKALLOC}
  61. { Allocates a 'small' block of memory on the stack }
  62. function StackAlloc(Size: Integer): Pointer; register;
  63. { Pops memory allocated by StackAlloc }
  64. procedure StackFree(P: Pointer); register;
  65. {$ENDIF}
  66. { Exchange two 32-bit values }
  67. procedure Swap(var A, B: Pointer); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  68. procedure Swap(var A, B: Integer); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  69. procedure Swap(var A, B: TFixed); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  70. procedure Swap(var A, B: TColor32); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  71. procedure Swap32(var A, B); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  72. { Exchange A <-> B only if B < A }
  73. procedure TestSwap(var A, B: Integer); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  74. procedure TestSwap(var A, B: TFixed); overload;{$IFDEF USEINLINING} inline; {$ENDIF}
  75. { Exchange A <-> B only if B < A then restrict both to [0..Size-1] range }
  76. { returns true if resulting range has common points with [0..Size-1] range }
  77. function TestClip(var A, B: Integer; const Size: Integer): Boolean; overload;
  78. function TestClip(var A, B: Integer; const Start, Stop: Integer): Boolean; overload;
  79. { Returns value constrained to [Lo..Hi] range}
  80. function Constrain(const Value, Lo, Hi: Integer): Integer; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  81. function Constrain(const Value, Lo, Hi: Single): Single; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  82. { Returns value constrained to [min(Constrain1, Constrain2)..max(Constrain1, Constrain2] range}
  83. function SwapConstrain(const Value: Integer; Constrain1, Constrain2: Integer): Integer;
  84. { Returns min./max. value of A, B and C }
  85. function Min(const A, B, C: Integer): Integer; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  86. function Max(const A, B, C: Integer): Integer; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  87. { Clamp integer value to [0..Max] range }
  88. function Clamp(Value, Max: Integer): Integer; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  89. { Same but [Min..Max] range }
  90. function Clamp(Value, Min, Max: Integer): Integer; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  91. { Wrap integer value to [0..Max] range }
  92. function Wrap(Value, Max: Integer): Integer; overload;
  93. { Same but [Min..Max] range }
  94. function Wrap(Value, Min, Max: Integer): Integer; overload;
  95. { Wrap single value to [0..Max] range }
  96. function Wrap(Value, Max: Single): Single; overload; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  97. { Fast Wrap alternatives for cases where range + 1 is a power of two }
  98. function WrapPow2(Value, Max: Integer): Integer; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  99. function WrapPow2(Value, Min, Max: Integer): Integer; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  100. { Mirror integer value in [0..Max] range }
  101. function Mirror(Value, Max: Integer): Integer; overload;
  102. { Same but [Min..Max] range }
  103. function Mirror(Value, Min, Max: Integer): Integer; overload;
  104. { Fast Mirror alternatives for cases where range + 1 is a power of two }
  105. function MirrorPow2(Value, Max: Integer): Integer; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  106. function MirrorPow2(Value, Min, Max: Integer): Integer; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  107. { Functions to determine appropiate wrap procs (normal or power of 2 optimized)}
  108. function GetOptimalWrap(Max: Integer): TWrapProc; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  109. function GetOptimalWrap(Min, Max: Integer): TWrapProcEx; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  110. function GetOptimalMirror(Max: Integer): TWrapProc; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  111. function GetOptimalMirror(Min, Max: Integer): TWrapProcEx; {$IFDEF USEINLINING} inline; {$ENDIF} overload;
  112. { Functions to retrieve correct WrapProc given WrapMode (and range) }
  113. function GetWrapProc(WrapMode: TWrapMode): TWrapProc; overload;
  114. function GetWrapProc(WrapMode: TWrapMode; Max: Integer): TWrapProc; overload;
  115. function GetWrapProcEx(WrapMode: TWrapMode): TWrapProcEx; overload;
  116. function GetWrapProcEx(WrapMode: TWrapMode; Min, Max: Integer): TWrapProcEx; overload;
  117. const
  118. WRAP_PROCS: array[TWrapMode] of TWrapProc = (Clamp, Wrap, Mirror);
  119. WRAP_PROCS_EX: array[TWrapMode] of TWrapProcEx = (Clamp, Wrap, Mirror);
  120. { Fast Value div 255, correct result with Value in [0..66298] range }
  121. function Div255(Value: Cardinal): Cardinal; {$IFDEF USEINLINING} inline; {$ENDIF}
  122. { shift right with sign conservation }
  123. function SAR_3(Value: Integer): Integer;
  124. function SAR_4(Value: Integer): Integer;
  125. function SAR_6(Value: Integer): Integer;
  126. function SAR_8(Value: Integer): Integer;
  127. function SAR_9(Value: Integer): Integer;
  128. function SAR_11(Value: Integer): Integer;
  129. function SAR_12(Value: Integer): Integer;
  130. function SAR_13(Value: Integer): Integer;
  131. function SAR_14(Value: Integer): Integer;
  132. function SAR_15(Value: Integer): Integer;
  133. function SAR_16(Value: Integer): Integer;
  134. { ColorSwap exchanges ARGB <-> ABGR and fills A with $FF }
  135. function ColorSwap(WinColor: TColor): TColor32;
  136. implementation
  137. uses
  138. {$IFDEF FPC}
  139. SysUtils,
  140. {$ENDIF}
  141. GR32_System, GR32_Bindings;
  142. {$R-}{$Q-} // switch off overflow and range checking
  143. function Clamp(const Value: Integer): Integer;
  144. {$IFDEF USENATIVECODE}
  145. begin
  146. Result := Value;
  147. if Result > 255 then
  148. Result := 255
  149. else
  150. if Result < 0 then
  151. Result := 0;
  152. {$ELSE}
  153. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  154. asm
  155. {$IFDEF TARGET_x64}
  156. // in x64 calling convention parameters are passed in ECX, EDX, R8 & R9
  157. MOV EAX,ECX
  158. {$ENDIF}
  159. TEST EAX,$FFFFFF00
  160. JNZ @1
  161. RET
  162. @1: JS @2
  163. MOV EAX,$FF
  164. RET
  165. @2: XOR EAX,EAX
  166. {$ENDIF}
  167. end;
  168. procedure FillLongword_Pas(var X; Count: Cardinal; Value: Longword);
  169. var
  170. I: Integer;
  171. P: PIntegerArray;
  172. begin
  173. P := PIntegerArray(@X);
  174. for I := Count - 1 downto 0 do
  175. P[I] := Integer(Value);
  176. end;
  177. {$IFNDEF PUREPASCAL}
  178. procedure FillLongword_ASM(var X; Count: Cardinal; Value: Longword); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  179. asm
  180. {$IFDEF TARGET_x86}
  181. // EAX = X; EDX = Count; ECX = Value
  182. PUSH EDI
  183. MOV EDI,EAX // Point EDI to destination
  184. MOV EAX,ECX
  185. MOV ECX,EDX
  186. REP STOSD // Fill count dwords
  187. @Exit:
  188. POP EDI
  189. {$ENDIF}
  190. {$IFDEF TARGET_x64}
  191. // ECX = X; EDX = Count; R8 = Value
  192. PUSH RDI
  193. MOV RDI,RCX // Point EDI to destination
  194. MOV RAX,R8 // copy value from R8 to RAX (EAX)
  195. MOV ECX,EDX // copy count to ECX
  196. TEST ECX,ECX
  197. JS @Exit
  198. REP STOSD // Fill count dwords
  199. @Exit:
  200. POP RDI
  201. {$ENDIF}
  202. end;
  203. procedure FillLongword_MMX(var X; Count: Cardinal; Value: Longword); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  204. asm
  205. {$IFDEF TARGET_x86}
  206. // EAX = X; EDX = Count; ECX = Value
  207. TEST EDX, EDX // if Count = 0 then
  208. JZ @Exit // Exit
  209. PUSH EDI
  210. MOV EDI, EAX
  211. MOV EAX, EDX
  212. SHR EAX, 1
  213. SHL EAX, 1
  214. SUB EAX, EDX
  215. JE @QLoopIni
  216. MOV [EDI], ECX
  217. ADD EDI, 4
  218. DEC EDX
  219. JZ @ExitPOP
  220. @QLoopIni:
  221. MOVD MM1, ECX
  222. PUNPCKLDQ MM1, MM1
  223. SHR EDX, 1
  224. @QLoop:
  225. MOVQ [EDI], MM1
  226. ADD EDI, 8
  227. DEC EDX
  228. JNZ @QLoop
  229. EMMS
  230. @ExitPOP:
  231. POP EDI
  232. @Exit:
  233. {$ENDIF}
  234. {$IFDEF TARGET_x64}
  235. // RCX = X; RDX = Count; R8 = Value
  236. TEST RDX, RDX // if Count = 0 then
  237. JZ @Exit // Exit
  238. MOV RAX, RCX // RAX = X
  239. PUSH RDI // store RDI on stack
  240. MOV R9, RDX // R9 = Count
  241. MOV RDI, RDX // RDI = Count
  242. SHR RDI, 1 // RDI = RDI SHR 1
  243. SHL RDI, 1 // RDI = RDI SHL 1
  244. SUB R9, RDI // check if extra fill is necessary
  245. JE @QLoopIni
  246. MOV [RAX], R8D // eventually perform extra fill
  247. ADD RAX, 4 // Inc(X, 4)
  248. DEC RDX // Dec(Count)
  249. JZ @ExitPOP // if (Count = 0) then Exit
  250. @QLoopIni:
  251. MOVD MM0, R8D // MM0 = R8D
  252. PUNPCKLDQ MM0, MM0 // unpack MM0 register
  253. SHR RDX, 1 // RDX = RDX div 2
  254. @QLoop:
  255. MOVQ QWORD PTR [RAX], MM0 // perform fill
  256. ADD RAX, 8 // Inc(X, 8)
  257. DEC RDX // Dec(X);
  258. JNZ @QLoop
  259. EMMS
  260. @ExitPOP:
  261. POP RDI
  262. @Exit:
  263. {$ENDIF}
  264. end;
  265. procedure FillLongword_SSE2(var X; Count: Integer; Value: Longword); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  266. asm
  267. {$IFDEF TARGET_x86}
  268. // EAX = X; EDX = Count; ECX = Value
  269. TEST EDX, EDX // if Count = 0 then
  270. JZ @Exit // Exit
  271. PUSH EDI // push EDI on stack
  272. MOV EDI, EAX // Point EDI to destination
  273. CMP EDX, 32
  274. JL @SmallLoop
  275. AND EAX, 3 // get aligned count
  276. TEST EAX, EAX // check if X is not dividable by 4
  277. JNZ @SmallLoop // otherwise perform slow small loop
  278. MOV EAX, EDI
  279. SHR EAX, 2 // bytes to count
  280. AND EAX, 3 // get aligned count
  281. ADD EAX,-4
  282. NEG EAX // get count to advance
  283. JZ @SetupMain
  284. SUB EDX, EAX // subtract aligning start from total count
  285. @AligningLoop:
  286. MOV [EDI], ECX
  287. ADD EDI, 4
  288. DEC EAX
  289. JNZ @AligningLoop
  290. @SetupMain:
  291. MOV EAX, EDX // EAX = remaining count
  292. SHR EAX, 2
  293. SHL EAX, 2
  294. SUB EDX, EAX // EDX = remaining count
  295. SHR EAX, 2
  296. MOVD XMM0, ECX
  297. PUNPCKLDQ XMM0, XMM0
  298. PUNPCKLDQ XMM0, XMM0
  299. @SSE2Loop:
  300. MOVDQA [EDI], XMM0
  301. ADD EDI, 16
  302. DEC EAX
  303. JNZ @SSE2Loop
  304. @SmallLoop:
  305. MOV EAX,ECX
  306. MOV ECX,EDX
  307. REP STOSD // Fill count dwords
  308. @ExitPOP:
  309. POP EDI
  310. @Exit:
  311. {$ENDIF}
  312. {$IFDEF TARGET_x64}
  313. // RCX = X; RDX = Count; R8 = Value
  314. TEST RDX, RDX // if Count = 0 then
  315. JZ @Exit // Exit
  316. MOV R9, RCX // Point R9 to destination
  317. CMP RDX, 32
  318. JL @SmallLoop
  319. AND RCX, 3 // get aligned count
  320. TEST RCX, RCX // check if X is not dividable by 4
  321. JNZ @SmallLoop // otherwise perform slow small loop
  322. MOV RCX, R9
  323. SHR RCX, 2 // bytes to count
  324. AND RCX, 3 // get aligned count
  325. ADD RCX,-4
  326. NEG RCX // get count to advance
  327. JZ @SetupMain
  328. SUB RDX, RCX // subtract aligning start from total count
  329. @AligningLoop:
  330. MOV [R9], R8D
  331. ADD R9, 4
  332. DEC RCX
  333. JNZ @AligningLoop
  334. @SetupMain:
  335. MOV RCX, RDX // RCX = remaining count
  336. SHR RCX, 2
  337. SHL RCX, 2
  338. SUB RDX, RCX // RDX = remaining count
  339. SHR RCX, 2
  340. MOVD XMM0, R8D
  341. PUNPCKLDQ XMM0, XMM0
  342. PUNPCKLDQ XMM0, XMM0
  343. @SSE2Loop:
  344. MOVDQA [R9], XMM0
  345. ADD R9, 16
  346. DEC RCX
  347. JNZ @SSE2Loop
  348. TEST RDX, RDX
  349. JZ @Exit
  350. @SmallLoop:
  351. MOV [R9], R8D
  352. ADD R9, 4
  353. DEC RDX
  354. JNZ @SmallLoop
  355. @Exit:
  356. {$ENDIF}
  357. end;
  358. {$ENDIF}
  359. procedure FillWord(var X; Count: Cardinal; Value: LongWord);
  360. {$IFDEF USENATIVECODE}
  361. var
  362. I: Integer;
  363. P: PWordArray;
  364. begin
  365. P := PWordArray(@X);
  366. for I := Count - 1 downto 0 do
  367. P[I] := Value;
  368. {$ELSE}
  369. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  370. asm
  371. {$IFDEF TARGET_x86}
  372. // EAX = X; EDX = Count; ECX = Value
  373. PUSH EDI
  374. MOV EDI,EAX // Point EDI to destination
  375. MOV EAX,ECX
  376. MOV ECX,EDX
  377. TEST ECX,ECX
  378. JZ @exit
  379. REP STOSW // Fill count words
  380. @exit:
  381. POP EDI
  382. {$ENDIF}
  383. {$IFDEF TARGET_x64}
  384. // ECX = X; EDX = Count; R8D = Value
  385. PUSH RDI
  386. MOV RDI,RCX // Point EDI to destination
  387. MOV EAX,R8D
  388. MOV ECX,EDX
  389. TEST ECX,ECX
  390. JZ @exit
  391. REP STOSW // Fill count words
  392. @exit:
  393. POP RDI
  394. {$ENDIF}
  395. {$ENDIF}
  396. end;
  397. procedure MoveLongword(const Source; var Dest; Count: Integer);
  398. {$IFDEF USEMOVE}
  399. begin
  400. Move(Source, Dest, Count shl 2);
  401. {$ELSE}
  402. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  403. asm
  404. {$IFDEF TARGET_x86}
  405. // EAX = Source; EDX = Dest; ECX = Count
  406. PUSH ESI
  407. PUSH EDI
  408. MOV ESI,EAX
  409. MOV EDI,EDX
  410. CMP EDI,ESI
  411. JE @exit
  412. REP MOVSD
  413. @exit:
  414. POP EDI
  415. POP ESI
  416. {$ENDIF}
  417. {$IFDEF TARGET_x64}
  418. // RCX = Source; RDX = Dest; R8 = Count
  419. PUSH RSI
  420. PUSH RDI
  421. MOV RSI,RCX
  422. MOV RDI,RDX
  423. MOV RCX,R8
  424. CMP RDI,RSI
  425. JE @exit
  426. REP MOVSD
  427. @exit:
  428. POP RDI
  429. POP RSI
  430. {$ENDIF}
  431. {$ENDIF}
  432. end;
  433. procedure MoveWord(const Source; var Dest; Count: Integer);
  434. {$IFDEF USEMOVE}
  435. begin
  436. Move(Source, Dest, Count shl 1);
  437. {$ELSE}
  438. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  439. asm
  440. {$IFDEF TARGET_x86}
  441. // EAX = X; EDX = Count; ECX = Value
  442. PUSH ESI
  443. PUSH EDI
  444. MOV ESI,EAX
  445. MOV EDI,EDX
  446. MOV EAX,ECX
  447. CMP EDI,ESI
  448. JE @exit
  449. REP MOVSW
  450. @exit:
  451. POP EDI
  452. POP ESI
  453. {$ENDIF}
  454. {$IFDEF TARGET_x64}
  455. // ECX = X; EDX = Count; R8 = Value
  456. PUSH RSI
  457. PUSH RDI
  458. MOV RSI,RCX
  459. MOV RDI,RDX
  460. MOV RAX,R8
  461. CMP RDI,RSI
  462. JE @exit
  463. REP MOVSW
  464. @exit:
  465. POP RDI
  466. POP RSI
  467. {$ENDIF}
  468. {$ENDIF}
  469. end;
  470. procedure Swap(var A, B: Pointer);
  471. var
  472. T: Pointer;
  473. begin
  474. T := A;
  475. A := B;
  476. B := T;
  477. end;
  478. procedure Swap(var A, B: Integer);
  479. var
  480. T: Integer;
  481. begin
  482. T := A;
  483. A := B;
  484. B := T;
  485. end;
  486. procedure Swap(var A, B: TFixed);
  487. var
  488. T: TFixed;
  489. begin
  490. T := A;
  491. A := B;
  492. B := T;
  493. end;
  494. procedure Swap(var A, B: TColor32);
  495. var
  496. T: TColor32;
  497. begin
  498. T := A;
  499. A := B;
  500. B := T;
  501. end;
  502. procedure Swap32(var A, B);
  503. var
  504. T: Integer;
  505. begin
  506. T := Integer(A);
  507. Integer(A) := Integer(B);
  508. Integer(B) := T;
  509. end;
  510. procedure TestSwap(var A, B: Integer);
  511. var
  512. T: Integer;
  513. begin
  514. if B < A then
  515. begin
  516. T := A;
  517. A := B;
  518. B := T;
  519. end;
  520. end;
  521. procedure TestSwap(var A, B: TFixed);
  522. var
  523. T: TFixed;
  524. begin
  525. if B < A then
  526. begin
  527. T := A;
  528. A := B;
  529. B := T;
  530. end;
  531. end;
  532. function TestClip(var A, B: Integer; const Size: Integer): Boolean;
  533. begin
  534. TestSwap(A, B); // now A = min(A,B) and B = max(A, B)
  535. if A < 0 then
  536. A := 0;
  537. if B >= Size then
  538. B := Size - 1;
  539. Result := B >= A;
  540. end;
  541. function TestClip(var A, B: Integer; const Start, Stop: Integer): Boolean;
  542. begin
  543. TestSwap(A, B); // now A = min(A,B) and B = max(A, B)
  544. if A < Start then
  545. A := Start;
  546. if B >= Stop then
  547. B := Stop - 1;
  548. Result := B >= A;
  549. end;
  550. function Constrain(const Value, Lo, Hi: Integer): Integer;
  551. {$IFDEF USENATIVECODE}
  552. begin
  553. Result := Value;
  554. if Result < Lo then
  555. Result := Lo
  556. else
  557. if Result > Hi then
  558. Result := Hi;
  559. {$ELSE}
  560. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  561. asm
  562. {$IFDEF TARGET_x64}
  563. MOV EAX,ECX
  564. MOV ECX,R8D
  565. {$ENDIF}
  566. CMP EDX,EAX
  567. CMOVG EAX,EDX
  568. CMP ECX,EAX
  569. CMOVL EAX,ECX
  570. {$ENDIF}
  571. end;
  572. function Constrain(const Value, Lo, Hi: Single): Single; overload;
  573. begin
  574. Result := Value;
  575. if Result < Lo then
  576. Result := Lo
  577. else
  578. if Result > Hi then
  579. Result := Hi;
  580. end;
  581. function SwapConstrain(const Value: Integer; Constrain1, Constrain2: Integer): Integer;
  582. begin
  583. TestSwap(Constrain1, Constrain2);
  584. Result := Value;
  585. if Result < Constrain1 then
  586. Result := Constrain1
  587. else
  588. if Result > Constrain2 then
  589. Result := Constrain2;
  590. end;
  591. function Max(const A, B, C: Integer): Integer;
  592. {$IFDEF USENATIVECODE}
  593. begin
  594. if A > B then
  595. Result := A
  596. else
  597. Result := B;
  598. if C > Result then
  599. Result := C;
  600. {$ELSE}
  601. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  602. asm
  603. {$IFDEF TARGET_x64}
  604. MOV RAX,RCX
  605. MOV RCX,R8
  606. {$ENDIF}
  607. CMP EDX,EAX
  608. CMOVG EAX,EDX
  609. CMP ECX,EAX
  610. CMOVG EAX,ECX
  611. {$ENDIF}
  612. end;
  613. function Min(const A, B, C: Integer): Integer;
  614. {$IFDEF USENATIVECODE}
  615. begin
  616. if A < B then
  617. Result := A
  618. else
  619. Result := B;
  620. if C < Result then
  621. Result := C;
  622. {$ELSE}
  623. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  624. asm
  625. {$IFDEF TARGET_x64}
  626. MOV RAX,RCX
  627. MOV RCX,R8
  628. {$ENDIF}
  629. CMP EDX,EAX
  630. CMOVL EAX,EDX
  631. CMP ECX,EAX
  632. CMOVL EAX,ECX
  633. {$ENDIF}
  634. end;
  635. function Clamp(Value, Max: Integer): Integer;
  636. {$IFDEF USENATIVECODE}
  637. begin
  638. Result := Value;
  639. if Result > Max then
  640. Result := Max
  641. else
  642. if Result < 0 then
  643. Result := 0;
  644. {$ELSE}
  645. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  646. asm
  647. {$IFDEF TARGET_x64}
  648. MOV EAX,ECX
  649. MOV ECX,R8D
  650. {$ENDIF}
  651. CMP EAX,EDX
  652. JG @Above
  653. TEST EAX,EAX
  654. JL @Below
  655. RET
  656. @Above:
  657. MOV EAX,EDX
  658. RET
  659. @Below:
  660. MOV EAX,0
  661. RET
  662. {$ENDIF}
  663. end;
  664. function Clamp(Value, Min, Max: Integer): Integer;
  665. {$IFDEF USENATIVECODE}
  666. begin
  667. Result := Value;
  668. if Result > Max then
  669. Result := Max
  670. else
  671. if Result < Min then
  672. Result := Min;
  673. {$ELSE}
  674. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  675. asm
  676. {$IFDEF TARGET_x64}
  677. MOV EAX,ECX
  678. MOV ECX,R8D
  679. {$ENDIF}
  680. CMP EDX,EAX
  681. CMOVG EAX,EDX
  682. CMP ECX,EAX
  683. CMOVL EAX,ECX
  684. {$ENDIF}
  685. end;
  686. function Wrap(Value, Max: Integer): Integer;
  687. {$IFDEF USENATIVECODE}
  688. begin
  689. if Value < 0 then
  690. Result := Max + (Value - Max) mod (Max + 1)
  691. else
  692. Result := Value mod (Max + 1);
  693. {$ELSE}
  694. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  695. asm
  696. {$IFDEF TARGET_x64}
  697. MOV EAX,ECX
  698. MOV ECX,R8D
  699. LEA ECX,[RDX+1]
  700. {$ELSE}
  701. LEA ECX,[EDX+1]
  702. {$ENDIF}
  703. CDQ
  704. IDIV ECX
  705. MOV EAX,EDX
  706. TEST EAX,EAX
  707. JNL @Exit
  708. ADD EAX,ECX
  709. @Exit:
  710. {$ENDIF}
  711. end;
  712. function Wrap(Value, Min, Max: Integer): Integer;
  713. begin
  714. if Value < Min then
  715. Result := Max + (Value - Max) mod (Max - Min + 1)
  716. else
  717. Result := Min + (Value - Min) mod (Max - Min + 1);
  718. end;
  719. function Wrap(Value, Max: Single): Single;
  720. begin
  721. {$IFDEF USEFLOATMOD}
  722. Result := FloatMod(Value, Max);
  723. {$ELSE}
  724. if Max = 0 then
  725. begin
  726. Result := 0;
  727. Exit;
  728. end;
  729. Result := Value;
  730. while Result >= Max do
  731. Result := Result - Max;
  732. while Result < 0 do
  733. Result := Result + Max;
  734. {$ENDIF}
  735. end;
  736. function DivMod(Dividend, Divisor: Integer; out Remainder: Integer): Integer;
  737. {$IFDEF USENATIVECODE}
  738. begin
  739. Remainder := Dividend mod Divisor;
  740. Result := Dividend div Divisor;
  741. {$ELSE}
  742. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  743. asm
  744. {$IFDEF TARGET_x86}
  745. PUSH EBX
  746. MOV EBX,EDX
  747. CDQ
  748. IDIV EBX
  749. MOV [ECX],EDX
  750. POP EBX
  751. {$ENDIF}
  752. {$IFDEF TARGET_x64}
  753. PUSH RBX
  754. MOV EAX,ECX
  755. MOV ECX,R8D
  756. MOV EBX,EDX
  757. CDQ
  758. IDIV EBX
  759. MOV [RCX],EDX
  760. POP RBX
  761. {$ENDIF}
  762. {$ENDIF}
  763. end;
  764. function Mirror(Value, Max: Integer): Integer;
  765. {$IFDEF USENATIVECODE}
  766. var
  767. DivResult: Integer;
  768. begin
  769. if Value < 0 then
  770. begin
  771. DivResult := DivMod(Value - Max, Max + 1, Result);
  772. Inc(Result, Max);
  773. end
  774. else
  775. DivResult := DivMod(Value, Max + 1, Result);
  776. if Odd(DivResult) then
  777. Result := Max - Result;
  778. {$ELSE}
  779. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  780. asm
  781. {$IFDEF TARGET_x64}
  782. MOV EAX,ECX
  783. MOV ECX,R8D
  784. {$ENDIF}
  785. TEST EAX,EAX
  786. JNL @@1
  787. NEG EAX
  788. @@1:
  789. MOV ECX,EDX
  790. CDQ
  791. IDIV ECX
  792. TEST EAX,1
  793. MOV EAX,EDX
  794. JZ @Exit
  795. NEG EAX
  796. ADD EAX,ECX
  797. @Exit:
  798. {$ENDIF}
  799. end;
  800. function Mirror(Value, Min, Max: Integer): Integer;
  801. var
  802. DivResult: Integer;
  803. begin
  804. if Value < Min then
  805. begin
  806. DivResult := DivMod(Value - Max, Max - Min + 1, Result);
  807. Inc(Result, Max);
  808. end
  809. else
  810. begin
  811. DivResult := DivMod(Value - Min, Max - Min + 1, Result);
  812. Inc(Result, Min);
  813. end;
  814. if Odd(DivResult) then Result := Max + Min - Result;
  815. end;
  816. function WrapPow2(Value, Max: Integer): Integer; overload;
  817. begin
  818. Result := Value and Max;
  819. end;
  820. function WrapPow2(Value, Min, Max: Integer): Integer; overload;
  821. begin
  822. Result := (Value - Min) and (Max - Min) + Min;
  823. end;
  824. function MirrorPow2(Value, Max: Integer): Integer; overload;
  825. begin
  826. if Value and (Max + 1) = 0 then
  827. Result := Value and Max
  828. else
  829. Result := Max - Value and Max;
  830. end;
  831. function MirrorPow2(Value, Min, Max: Integer): Integer; overload;
  832. begin
  833. Value := Value - Min;
  834. Result := Max - Min;
  835. if Value and (Result + 1) = 0 then
  836. Result := Min + Value and Result
  837. else
  838. Result := Max - Value and Result;
  839. end;
  840. function GetOptimalWrap(Max: Integer): TWrapProc; overload;
  841. begin
  842. if (Max >= 0) and IsPowerOf2(Max + 1) then
  843. Result := WrapPow2
  844. else
  845. Result := Wrap;
  846. end;
  847. function GetOptimalWrap(Min, Max: Integer): TWrapProcEx; overload;
  848. begin
  849. if (Min >= 0) and (Max >= Min) and IsPowerOf2(Max - Min + 1) then
  850. Result := WrapPow2
  851. else
  852. Result := Wrap;
  853. end;
  854. function GetOptimalMirror(Max: Integer): TWrapProc; overload;
  855. begin
  856. if (Max >= 0) and IsPowerOf2(Max + 1) then
  857. Result := MirrorPow2
  858. else
  859. Result := Mirror;
  860. end;
  861. function GetOptimalMirror(Min, Max: Integer): TWrapProcEx; overload;
  862. begin
  863. if (Min >= 0) and (Max >= Min) and IsPowerOf2(Max - Min + 1) then
  864. Result := MirrorPow2
  865. else
  866. Result := Mirror;
  867. end;
  868. function GetWrapProc(WrapMode: TWrapMode): TWrapProc; overload;
  869. begin
  870. case WrapMode of
  871. wmRepeat:
  872. Result := Wrap;
  873. wmMirror:
  874. Result := Mirror;
  875. else //wmClamp:
  876. Result := Clamp;
  877. end;
  878. end;
  879. function GetWrapProc(WrapMode: TWrapMode; Max: Integer): TWrapProc; overload;
  880. begin
  881. case WrapMode of
  882. wmRepeat:
  883. Result := GetOptimalWrap(Max);
  884. wmMirror:
  885. Result := GetOptimalMirror(Max);
  886. else //wmClamp:
  887. Result := Clamp;
  888. end;
  889. end;
  890. function GetWrapProcEx(WrapMode: TWrapMode): TWrapProcEx; overload;
  891. begin
  892. case WrapMode of
  893. wmRepeat:
  894. Result := Wrap;
  895. wmMirror:
  896. Result := Mirror;
  897. else //wmClamp:
  898. Result := Clamp;
  899. end;
  900. end;
  901. function GetWrapProcEx(WrapMode: TWrapMode; Min, Max: Integer): TWrapProcEx; overload;
  902. begin
  903. case WrapMode of
  904. wmRepeat:
  905. Result := GetOptimalWrap(Min, Max);
  906. wmMirror:
  907. Result := GetOptimalMirror(Min, Max);
  908. else //wmClamp:
  909. Result := Clamp;
  910. end;
  911. end;
  912. function Div255(Value: Cardinal): Cardinal;
  913. begin
  914. Result := (Value * $8081) shr 23;
  915. end;
  916. { shift right with sign conservation }
  917. function SAR_3(Value: Integer): Integer;
  918. {$IFDEF PUREPASCAL}
  919. begin
  920. Result := Value div 8;
  921. {$ELSE}
  922. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  923. asm
  924. {$IFDEF TARGET_x64}
  925. MOV EAX,ECX
  926. {$ENDIF}
  927. SAR EAX,3
  928. {$ENDIF}
  929. end;
  930. function SAR_4(Value: Integer): Integer;
  931. {$IFDEF PUREPASCAL}
  932. begin
  933. Result := Value div 16;
  934. {$ELSE}
  935. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  936. asm
  937. {$IFDEF TARGET_x64}
  938. MOV EAX,ECX
  939. {$ENDIF}
  940. SAR EAX,4
  941. {$ENDIF}
  942. end;
  943. function SAR_6(Value: Integer): Integer;
  944. {$IFDEF PUREPASCAL}
  945. begin
  946. Result := Value div 64;
  947. {$ELSE}
  948. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  949. asm
  950. {$IFDEF TARGET_x64}
  951. MOV EAX,ECX
  952. {$ENDIF}
  953. SAR EAX,6
  954. {$ENDIF}
  955. end;
  956. function SAR_8(Value: Integer): Integer;
  957. {$IFDEF PUREPASCAL}
  958. begin
  959. Result := Value div 256;
  960. {$ELSE}
  961. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  962. asm
  963. {$IFDEF TARGET_x64}
  964. MOV EAX,ECX
  965. {$ENDIF}
  966. SAR EAX,8
  967. {$ENDIF}
  968. end;
  969. function SAR_9(Value: Integer): Integer;
  970. {$IFDEF PUREPASCAL}
  971. begin
  972. Result := Value div 512;
  973. {$ELSE}
  974. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  975. asm
  976. {$IFDEF TARGET_x64}
  977. MOV EAX,ECX
  978. {$ENDIF}
  979. SAR EAX,9
  980. {$ENDIF}
  981. end;
  982. function SAR_11(Value: Integer): Integer;
  983. {$IFDEF PUREPASCAL}
  984. begin
  985. Result := Value div 2048;
  986. {$ELSE}
  987. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  988. asm
  989. {$IFDEF TARGET_x64}
  990. MOV EAX,ECX
  991. {$ENDIF}
  992. SAR EAX,11
  993. {$ENDIF}
  994. end;
  995. function SAR_12(Value: Integer): Integer;
  996. {$IFDEF PUREPASCAL}
  997. begin
  998. Result := Value div 4096;
  999. {$ELSE}
  1000. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1001. asm
  1002. {$IFDEF TARGET_x64}
  1003. MOV EAX,ECX
  1004. {$ENDIF}
  1005. SAR EAX,12
  1006. {$ENDIF}
  1007. end;
  1008. function SAR_13(Value: Integer): Integer;
  1009. {$IFDEF PUREPASCAL}
  1010. begin
  1011. Result := Value div 8192;
  1012. {$ELSE}
  1013. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1014. asm
  1015. {$IFDEF TARGET_x64}
  1016. MOV EAX,ECX
  1017. {$ENDIF}
  1018. SAR EAX,13
  1019. {$ENDIF}
  1020. end;
  1021. function SAR_14(Value: Integer): Integer;
  1022. {$IFDEF PUREPASCAL}
  1023. begin
  1024. Result := Value div 16384;
  1025. {$ELSE}
  1026. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1027. asm
  1028. {$IFDEF TARGET_x64}
  1029. MOV EAX,ECX
  1030. {$ENDIF}
  1031. SAR EAX,14
  1032. {$ENDIF}
  1033. end;
  1034. function SAR_15(Value: Integer): Integer;
  1035. {$IFDEF PUREPASCAL}
  1036. begin
  1037. Result := Value div 32768;
  1038. {$ELSE}
  1039. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1040. asm
  1041. {$IFDEF TARGET_x64}
  1042. MOV EAX,ECX
  1043. {$ENDIF}
  1044. SAR EAX,15
  1045. {$ENDIF}
  1046. end;
  1047. function SAR_16(Value: Integer): Integer;
  1048. {$IFDEF PUREPASCAL}
  1049. begin
  1050. Result := Value div 65536;
  1051. {$ELSE}
  1052. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1053. asm
  1054. {$IFDEF TARGET_x64}
  1055. MOV EAX,ECX
  1056. {$ENDIF}
  1057. SAR EAX,16
  1058. {$ENDIF}
  1059. end;
  1060. { Colorswap exchanges ARGB <-> ABGR and fill A with $FF }
  1061. function ColorSwap(WinColor: TColor): TColor32;
  1062. {$IFDEF USENATIVECODE}
  1063. var
  1064. WCEn: TColor32Entry absolute WinColor;
  1065. REn : TColor32Entry absolute Result;
  1066. begin
  1067. Result := WCEn.ARGB;
  1068. REn.A := $FF;
  1069. REn.R := WCEn.B;
  1070. REn.B := WCEn.R;
  1071. {$ELSE}
  1072. {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1073. asm
  1074. // EAX = WinColor
  1075. // this function swaps R and B bytes in ABGR
  1076. // and writes $FF into A component
  1077. {$IFDEF TARGET_x64}
  1078. MOV EAX,ECX
  1079. {$ENDIF}
  1080. BSWAP EAX
  1081. MOV AL, $FF
  1082. ROR EAX,8
  1083. {$ENDIF}
  1084. end;
  1085. {$IFDEF USESTACKALLOC}
  1086. {$IFDEF PUREPASCAL}
  1087. function StackAlloc(Size: Integer): Pointer;
  1088. begin
  1089. GetMem(Result, Size);
  1090. end;
  1091. procedure StackFree(P: Pointer);
  1092. begin
  1093. FreeMem(P);
  1094. end;
  1095. {$ELSE}
  1096. { StackAlloc allocates a 'small' block of memory from the stack by
  1097. decrementing SP. This provides the allocation speed of a local variable,
  1098. but the runtime size flexibility of heap allocated memory.
  1099. x64 implementation by Jameel Halabi
  1100. }
  1101. function StackAlloc(Size: Integer): Pointer; register; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1102. asm
  1103. {$IFDEF TARGET_x86}
  1104. POP ECX // return address
  1105. MOV EDX, ESP
  1106. ADD EAX, 3
  1107. AND EAX, not 3 // round up to keep ESP dword aligned
  1108. CMP EAX, 4092
  1109. JLE @@2
  1110. @@1:
  1111. SUB ESP, 4092
  1112. PUSH EAX // make sure we touch guard page, to grow stack
  1113. SUB EAX, 4096
  1114. JNS @@1
  1115. ADD EAX, 4096
  1116. @@2:
  1117. SUB ESP, EAX
  1118. MOV EAX, ESP // function result = low memory address of block
  1119. PUSH EDX // save original SP, for cleanup
  1120. MOV EDX, ESP
  1121. SUB EDX, 4
  1122. PUSH EDX // save current SP, for sanity check (sp = [sp])
  1123. PUSH ECX // return to caller
  1124. {$ENDIF}
  1125. {$IFDEF TARGET_x64}
  1126. {$IFNDEF FPC}
  1127. .NOFRAME
  1128. {$ENDIF}
  1129. POP R8 // return address
  1130. MOV RDX, RSP // original SP
  1131. ADD ECX, 15
  1132. AND ECX, NOT 15 // round up to keep SP dqword aligned
  1133. CMP ECX, 4088
  1134. JLE @@2
  1135. @@1:
  1136. SUB RSP, 4088
  1137. PUSH RCX // make sure we touch guard page, to grow stack
  1138. SUB ECX, 4096
  1139. JNS @@1
  1140. ADD ECX, 4096
  1141. @@2:
  1142. SUB RSP, RCX
  1143. MOV RAX, RSP // function result = low memory address of block
  1144. PUSH RDX // save original SP, for cleanup
  1145. MOV RDX, RSP
  1146. SUB RDX, 8
  1147. PUSH RDX // save current SP, for sanity check (sp = [sp])
  1148. PUSH R8 // return to caller
  1149. {$ENDIF}
  1150. end;
  1151. { StackFree pops the memory allocated by StackAlloc off the stack.
  1152. - Calling StackFree is optional - SP will be restored when the calling routine
  1153. exits, but it's a good idea to free the stack allocated memory ASAP anyway.
  1154. - StackFree must be called in the same stack context as StackAlloc - not in
  1155. a subroutine or finally block.
  1156. - Multiple StackFree calls must occur in reverse order of their corresponding
  1157. StackAlloc calls.
  1158. - Built-in sanity checks guarantee that an improper call to StackFree will not
  1159. corrupt the stack. Worst case is that the stack block is not released until
  1160. the calling routine exits. }
  1161. procedure StackFree(P: Pointer); register; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1162. asm
  1163. {$IFDEF TARGET_x86}
  1164. POP ECX // return address
  1165. MOV EDX, DWORD PTR [ESP]
  1166. SUB EAX, 8
  1167. CMP EDX, ESP // sanity check #1 (SP = [SP])
  1168. JNE @Exit
  1169. CMP EDX, EAX // sanity check #2 (P = this stack block)
  1170. JNE @Exit
  1171. MOV ESP, DWORD PTR [ESP+4] // restore previous SP
  1172. @Exit:
  1173. PUSH ECX // return to caller
  1174. {$ENDIF}
  1175. {$IFDEF TARGET_x64}
  1176. {$IFNDEF FPC}
  1177. .NOFRAME
  1178. {$ENDIF}
  1179. POP R8 // return address
  1180. MOV RDX, QWORD PTR [RSP]
  1181. SUB RCX, 16
  1182. CMP RDX, RSP // sanity check #1 (SP = [SP])
  1183. JNE @Exit
  1184. CMP RDX, RCX // sanity check #2 (P = this stack block)
  1185. JNE @Exit
  1186. MOV RSP, QWORD PTR [RSP + 8] // restore previous SP
  1187. @Exit:
  1188. PUSH R8 // return to caller
  1189. {$ENDIF}
  1190. end;
  1191. {$ENDIF}
  1192. {$ENDIF}
  1193. {CPU target and feature Function templates}
  1194. const
  1195. FID_FILLLONGWORD = 0;
  1196. {Complete collection of unit templates}
  1197. var
  1198. Registry: TFunctionRegistry;
  1199. procedure RegisterBindings;
  1200. begin
  1201. Registry := NewRegistry('GR32_LowLevel bindings');
  1202. Registry.RegisterBinding(FID_FILLLONGWORD, @@FillLongWord);
  1203. Registry.Add(FID_FILLLONGWORD, @FillLongWord_Pas, []);
  1204. {$IFNDEF PUREPASCAL}
  1205. Registry.Add(FID_FILLLONGWORD, @FillLongWord_ASM, []);
  1206. Registry.Add(FID_FILLLONGWORD, @FillLongWord_MMX, [ciMMX]);
  1207. Registry.Add(FID_FILLLONGWORD, @FillLongword_SSE2, [ciSSE2]);
  1208. {$ENDIF}
  1209. Registry.RebindAll;
  1210. end;
  1211. initialization
  1212. RegisterBindings;
  1213. end.