GR32_LowLevel.pas 33 KB

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