2
0

GR32_Math.pas 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192
  1. unit GR32_Math;
  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 Additional Math Routines for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson <[email protected]>
  26. * (parts of this unit were moved here from GR32_System.pas and GR32.pas by Alex A. Denisov)
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2005-2009
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. * Michael Hansen <[email protected]>
  33. *
  34. * ***** END LICENSE BLOCK ***** *)
  35. interface
  36. {$include GR32.inc}
  37. uses
  38. GR32,
  39. {$IFDEF FPC}
  40. GR32_Math_FPC,
  41. {$ENDIF}
  42. GR32_Bindings;
  43. //------------------------------------------------------------------------------
  44. //
  45. // Fixed point math routines
  46. //
  47. //------------------------------------------------------------------------------
  48. function FixedFloor(A: TFixed): Integer;
  49. function FixedCeil(A: TFixed): Integer;
  50. function FixedMul(A, B: TFixed): TFixed;
  51. function FixedDiv(A, B: TFixed): TFixed;
  52. function OneOver(Value: TFixed): TFixed;
  53. function FixedRound(A: TFixed): Integer; {$IFDEF PUREPASCAL} inline; {$ENDIF}
  54. function FixedSqr(Value: TFixed): TFixed;
  55. function FixedSqrtLP(Value: TFixed): TFixed; // 8-bit precision
  56. function FixedSqrtHP(Value: TFixed): TFixed; // 16-bit precision
  57. // Fixed point interpolation
  58. function FixedCombine(W, X, Y: TFixed): TFixed;
  59. //------------------------------------------------------------------------------
  60. //
  61. // Trigonometric routines
  62. //
  63. //------------------------------------------------------------------------------
  64. procedure SinCos(const Theta: TFloat; out Sin, Cos: TFloat); overload;
  65. procedure SinCos(const Theta, Radius: Single; out Sin, Cos: Single); overload;
  66. procedure SinCos(const Theta, ScaleX, ScaleY: TFloat; out Sin, Cos: Single); overload;
  67. function Hypot(const X, Y: TFloat): TFloat; overload;
  68. function Hypot(const X, Y: Integer): Integer; overload;
  69. // Fast*: Fast approximations
  70. function FastSqrt(const Value: TFloat): TFloat; {$IFDEF PUREPASCAL} inline; {$ENDIF}
  71. function FastSqrtBab1(const Value: TFloat): TFloat;
  72. function FastSqrtBab2(const Value: TFloat): TFloat;
  73. function FastInvSqrt(const Value: TFloat): TFloat; {$IFDEF PUREPASCAL} inline; {$ENDIF}
  74. //------------------------------------------------------------------------------
  75. //
  76. // Misc. Routines
  77. //
  78. //------------------------------------------------------------------------------
  79. { MulDiv a faster implementation of Windows.MulDiv funtion }
  80. // The MSDN documentation for MulDiv states:
  81. // [...] the return value is the result of the multiplication and division, rounded
  82. // to the nearest integer. If the result is a positive half integer (ends in .5),
  83. // it is rounded up. If the result is a negative half integer, it is rounded down.
  84. function MulDiv(Multiplicand, Multiplier, Divisor: Integer): Integer;
  85. function DivMod(Dividend, Divisor: Integer; var Remainder: Integer): Integer;
  86. // Power of 2 functions. Only valid for values >= 0.
  87. // Determine if X is a power of 2, returns true when X = 1,2,4,8,16 etc.
  88. function IsPowerOf2(Value: Integer): Boolean; {$IFDEF USEINLINING} inline; {$ENDIF}
  89. // Returns X rounded DOWN to the PREVIOUS power of two, i.e. 5->4, 7->4, 8->4, 9->8
  90. function PrevPowerOf2(Value: Integer): Integer;
  91. // Returns X rounded UP to the NEXT power of two, i.e. 5->8, 7->8, 8->16, 15->16
  92. function NextPowerOf2(Value: Integer): Integer;
  93. // fast average without overflow, useful for e.g. fixed point math
  94. function Average(A, B: Integer): Integer; {$IFDEF PUREPASCAL} inline; {$ENDIF}
  95. // fast sign function
  96. function Sign(Value: Integer): Integer; {$IFDEF PUREPASCAL} inline; {$ENDIF}
  97. //------------------------------------------------------------------------------
  98. //
  99. // Modulus
  100. //
  101. //------------------------------------------------------------------------------
  102. // See also: https://en.wikipedia.org/wiki/Modulo
  103. //------------------------------------------------------------------------------
  104. //
  105. // FMod(Numerator, Denominator)
  106. //
  107. // Similar to Mod() but for floating point values.
  108. // Returns a value in the [0..Denominator) range. I.e. Denominator is exclusive.
  109. // NAN is not checked. If Denominator=0, An exception is raised or INF or NAN is
  110. // returned depending on the implementation
  111. //
  112. // Equivalent to the Delphi RTL Math.FMod function.
  113. //
  114. // Result := Numerator - Denominator * Trunc(Numerator / Denominator);
  115. //
  116. function FMod(ANumerator, ADenominator: Double): Double; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  117. function FMod(ANumerator, ADenominator: TFloat): TFloat; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  118. //
  119. // FloatMod(Numerator, Denominator)
  120. //
  121. // Returns a value in the [0..Denominator) range. I.e. Denominator is exclusive.
  122. // NAN is not checked. If Denominator=0, Numerator is returned.
  123. //
  124. // Note that, unlike FMod, FloatMod uses the Floor() definition of modulus:
  125. //
  126. // Result := Numerator - Denominator * Floor(Numerator / Denominator);
  127. //
  128. // While FMod uses the Trunc definition:
  129. //
  130. // Result := Numerator - Denominator * Trunc(Numerator / Denominator);
  131. //
  132. // For an implementation using the Trunc() definition, see the
  133. // FloatRemainder function.
  134. //
  135. function FloatMod(ANumerator, ADenominator: Double): Double; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  136. function FloatMod(ANumerator, ADenominator: TFloat): TFloat; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  137. //
  138. // FloatRemainder(Numerator, Denominator)
  139. //
  140. // Returns a value in the [0..Denominator) range. I.e. Denominator is exclusive.
  141. // NAN is not checked. If Denominator=0, Numerator is returned.
  142. //
  143. // Similar to the FloatMod function but uses Round() instead of Floor():
  144. //
  145. // Result := Numerator - Denominator * Round(Numerator / Denominator);
  146. //
  147. // This corresponds to the C++ remainder() function.
  148. //
  149. function FloatRemainder(ANumerator, ADenominator: Double): Double; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  150. function FloatRemainder(ANumerator, ADenominator: TFloat): TFloat; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  151. //------------------------------------------------------------------------------
  152. //
  153. // Prefix Sum
  154. //
  155. //------------------------------------------------------------------------------
  156. // Also known as: CumSum, Cumulative Sum
  157. //------------------------------------------------------------------------------
  158. type
  159. TCumSumProc = procedure(Values: PSingleArray; Count: Integer);
  160. var
  161. CumSum: TCumSumProc;
  162. //------------------------------------------------------------------------------
  163. //
  164. // Bindings
  165. //
  166. //------------------------------------------------------------------------------
  167. type
  168. TFloatMod_FProc = function(ANumerator, ADenominator: TFloat): TFloat;
  169. TFloatMod_DProc = function(ANumerator, ADenominator: Double): Double;
  170. var
  171. FloatMod_F: TFloatMod_FProc; // Single
  172. FloatMod_D: TFloatMod_DProc; // Double
  173. FloatRemainder_F: TFloatMod_FProc; // Single
  174. FloatRemainder_D: TFloatMod_DProc; // Double
  175. FMod_F: TFloatMod_FProc; // Single
  176. FMod_D: TFloatMod_DProc; // Double
  177. var
  178. MathRegistry: TFunctionRegistry;
  179. const
  180. FID_CUMSUM = 0;
  181. FID_FLOATMOD_F = 1;
  182. FID_FLOATMOD_D = 2;
  183. FID_FLOATREMAINDER_F = 3;
  184. FID_FLOATREMAINDER_D = 4;
  185. FID_FMOD_F = 5;
  186. FID_FMOD_D = 6;
  187. //------------------------------------------------------------------------------
  188. //------------------------------------------------------------------------------
  189. //------------------------------------------------------------------------------
  190. implementation
  191. uses
  192. {$if not defined(FPC)}
  193. System.Math,
  194. {$else}
  195. Math,
  196. {$ifend}
  197. GR32_System,
  198. GR32.Types.SIMD;
  199. {$IFDEF PUREPASCAL}
  200. const
  201. FixedOneS: Single = 65536;
  202. {$ENDIF}
  203. //------------------------------------------------------------------------------
  204. //
  205. // Fixed-point math
  206. //
  207. //------------------------------------------------------------------------------
  208. // FixedFloor
  209. //------------------------------------------------------------------------------
  210. {$IFDEF PUREPASCAL}
  211. function FixedFloor(A: TFixed): Integer;
  212. begin
  213. Result := A div FixedOne;
  214. end;
  215. {$ELSE}
  216. function FixedFloor(A: TFixed): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  217. asm
  218. {$if defined(TARGET_x86)}
  219. SAR EAX, 16
  220. {$elseif defined(TARGET_x64)}
  221. MOV EAX, ECX
  222. SAR EAX, 16
  223. {$else}
  224. {$error 'Missing target'}
  225. {$ifend}
  226. end;
  227. {$ENDIF}
  228. //------------------------------------------------------------------------------
  229. // FixedCeil
  230. //------------------------------------------------------------------------------
  231. {$IFDEF PUREPASCAL}
  232. function FixedCeil(A: TFixed): Integer;
  233. begin
  234. Result := (A + $FFFF) div FixedOne;
  235. end;
  236. {$ELSE}
  237. function FixedCeil(A: TFixed): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  238. asm
  239. {$if defined(TARGET_x86)}
  240. ADD EAX, $0000FFFF
  241. SAR EAX, 16
  242. {$elseif defined(TARGET_x64)}
  243. MOV EAX, ECX
  244. ADD EAX, $0000FFFF
  245. SAR EAX, 16
  246. {$else}
  247. {$error 'Missing target'}
  248. {$ifend}
  249. end;
  250. {$ENDIF}
  251. //------------------------------------------------------------------------------
  252. // FixedRound
  253. //------------------------------------------------------------------------------
  254. {$IFDEF PUREPASCAL}
  255. function FixedRound(A: TFixed): Integer;
  256. begin
  257. Result := (A + $7FFF);
  258. Result := (Cardinal(Result) shr 16) or (($10000000 - (Cardinal((Result and a) shr 31))) shl 16); // [*]
  259. { [*] Above line is just a branchless version of:
  260. if Integer(Result and A) < 0 then
  261. Result := (Result shr 16) or $FFFF0000
  262. else
  263. Result := (Result shr 16);
  264. }
  265. end;
  266. {$ELSE}
  267. function FixedRound(A: TFixed): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  268. asm
  269. {$if defined(TARGET_x86)}
  270. ADD EAX, FixedHalf
  271. SAR EAX, 16
  272. {$elseif defined(TARGET_x64)}
  273. MOV EAX, ECX
  274. ADD EAX, FixedHalf
  275. SAR EAX, 16
  276. {$else}
  277. {$error 'Missing target'}
  278. {$ifend}
  279. end;
  280. {$ENDIF}
  281. //------------------------------------------------------------------------------
  282. // FixedMul
  283. //------------------------------------------------------------------------------
  284. {$IFDEF PUREPASCAL}
  285. function FixedMul(A, B: TFixed): TFixed;
  286. begin
  287. Result := Round(A * FixedToFloat * B);
  288. end;
  289. {$ELSE}
  290. function FixedMul(A, B: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  291. asm
  292. {$if defined(TARGET_x86)}
  293. IMUL EDX
  294. SHRD EAX, EDX, 16
  295. {$elseif defined(TARGET_x64)}
  296. MOV EAX, ECX
  297. IMUL EDX
  298. SHRD EAX, EDX, 16
  299. {$else}
  300. {$error 'Missing target'}
  301. {$ifend}
  302. end;
  303. {$ENDIF}
  304. //------------------------------------------------------------------------------
  305. // FixedDiv
  306. //------------------------------------------------------------------------------
  307. {$IFDEF PUREPASCAL}
  308. function FixedDiv(A, B: TFixed): TFixed;
  309. begin
  310. Result := Round(A / B * FixedOne);
  311. end;
  312. {$ELSE}
  313. function FixedDiv(A, B: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  314. asm
  315. {$if defined(TARGET_x86)}
  316. MOV ECX, B
  317. CDQ
  318. SHLD EDX, EAX, 16
  319. SHL EAX, 16
  320. IDIV ECX
  321. {$elseif defined(TARGET_x64)}
  322. MOV EAX, ECX
  323. MOV ECX, EDX
  324. CDQ
  325. SHLD EDX, EAX, 16
  326. SHL EAX, 16
  327. IDIV ECX
  328. {$else}
  329. {$error 'Missing target'}
  330. {$ifend}
  331. end;
  332. {$ENDIF}
  333. //------------------------------------------------------------------------------
  334. // OneOver
  335. //------------------------------------------------------------------------------
  336. {$IFDEF PUREPASCAL}
  337. function OneOver(Value: TFixed): TFixed;
  338. const
  339. Dividend: Single = 4294967296; // FixedOne * FixedOne
  340. begin
  341. Result := Round(Dividend / Value);
  342. end;
  343. {$ELSE}
  344. function OneOver(Value: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  345. asm
  346. {$if defined(TARGET_x86)}
  347. MOV ECX, Value
  348. XOR EAX, EAX
  349. MOV EDX, 1
  350. IDIV ECX
  351. {$elseif defined(TARGET_x64)}
  352. XOR EAX, EAX
  353. MOV EDX, 1
  354. IDIV ECX
  355. {$else}
  356. {$error 'Missing target'}
  357. {$ifend}
  358. end;
  359. {$ENDIF}
  360. //------------------------------------------------------------------------------
  361. // FixedSqr
  362. //------------------------------------------------------------------------------
  363. {$IFDEF PUREPASCAL}
  364. function FixedSqr(Value: TFixed): TFixed;
  365. begin
  366. Result := Round(Value * FixedToFloat * Value);
  367. end;
  368. {$ELSE}
  369. function FixedSqr(Value: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  370. asm
  371. {$if defined(TARGET_x86)}
  372. IMUL EAX
  373. SHRD EAX, EDX, 16
  374. {$elseif defined(TARGET_x64)}
  375. MOV EAX, Value
  376. IMUL EAX
  377. SHRD EAX, EDX, 16
  378. {$else}
  379. {$error 'Missing target'}
  380. {$ifend}
  381. end;
  382. {$ENDIF}
  383. //------------------------------------------------------------------------------
  384. // FixedSqrt
  385. //------------------------------------------------------------------------------
  386. {$IFDEF PUREPASCAL}
  387. function FixedSqrtLP(Value: TFixed): TFixed;
  388. begin
  389. Result := Round(Sqrt(Value * FixedOneS));
  390. end;
  391. {$ELSE}
  392. function FixedSqrtLP(Value: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  393. asm
  394. {$if defined(TARGET_x86)}
  395. PUSH EBX
  396. MOV ECX, EAX
  397. XOR EAX, EAX
  398. MOV EBX, $40000000
  399. @SqrtLP1:
  400. MOV EDX, ECX
  401. SUB EDX, EBX
  402. JL @SqrtLP2
  403. SUB EDX, EAX
  404. JL @SqrtLP2
  405. MOV ECX, EDX
  406. SHR EAX, 1
  407. OR EAX, EBX
  408. SHR EBX, 2
  409. JNZ @SqrtLP1
  410. SHL EAX, 8
  411. JMP @SqrtLP3
  412. @SqrtLP2:
  413. SHR EAX, 1
  414. SHR EBX, 2
  415. JNZ @SqrtLP1
  416. SHL EAX, 8
  417. @SqrtLP3:
  418. POP EBX
  419. {$elseif defined(TARGET_x64)}
  420. XOR EAX, EAX
  421. MOV R8D, $40000000
  422. @SqrtLP1:
  423. MOV EDX, ECX
  424. SUB EDX, R8D
  425. JL @SqrtLP2
  426. SUB EDX, EAX
  427. JL @SqrtLP2
  428. MOV ECX, EDX
  429. SHR EAX, 1
  430. OR EAX, R8D
  431. SHR R8D, 2
  432. JNZ @SqrtLP1
  433. SHL EAX, 8
  434. RET
  435. @SqrtLP2:
  436. SHR EAX, 1
  437. SHR R8D, 2
  438. JNZ @SqrtLP1
  439. SHL EAX, 8
  440. {$else}
  441. {$error 'Missing target'}
  442. {$ifend}
  443. end;
  444. {$ENDIF}
  445. //------------------------------------------------------------------------------
  446. {$IFDEF PUREPASCAL}
  447. function FixedSqrtHP(Value: TFixed): TFixed;
  448. begin
  449. Result := Round(Sqrt(Value * FixedOneS));
  450. end;
  451. {$ELSE}
  452. function FixedSqrtHP(Value: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  453. asm
  454. {$if defined(TARGET_x86)}
  455. PUSH EBX
  456. MOV ECX, EAX
  457. XOR EAX, EAX
  458. MOV EBX, $40000000
  459. @SqrtHP1:
  460. MOV EDX, ECX
  461. SUB EDX, EBX
  462. JB @SqrtHP2
  463. SUB EDX, EAX
  464. JB @SqrtHP2
  465. MOV ECX, EDX
  466. SHR EAX, 1
  467. OR EAX, EBX
  468. SHR EBX, 2
  469. JNZ @SqrtHP1
  470. JMP @SqrtHP5
  471. @SqrtHP2:
  472. SHR EAX, 1
  473. SHR EBX, 2
  474. JNZ @SqrtHP1
  475. @SqrtHP5:
  476. MOV EBX, $00004000
  477. SHL EAX, 16
  478. SHL ECX, 16
  479. @SqrtHP3:
  480. MOV EDX, ECX
  481. SUB EDX, EBX
  482. JB @SqrtHP4
  483. SUB EDX, EAX
  484. JB @SqrtHP4
  485. MOV ECX, EDX
  486. SHR EAX, 1
  487. OR EAX, EBX
  488. SHR EBX, 2
  489. JNZ @SqrtHP3
  490. JMP @SqrtHP6
  491. @SqrtHP4:
  492. SHR EAX, 1
  493. SHR EBX, 2
  494. JNZ @SqrtHP3
  495. @SqrtHP6:
  496. POP EBX
  497. {$elseif defined(TARGET_x64)}
  498. XOR EAX, EAX
  499. MOV R8D, $40000000
  500. @SqrtHP1:
  501. MOV EDX, ECX
  502. SUB EDX, R8D
  503. JB @SqrtHP2
  504. SUB EDX, EAX
  505. JB @SqrtHP2
  506. MOV ECX, EDX
  507. SHR EAX, 1
  508. OR EAX, R8D
  509. SHR R8D, 2
  510. JNZ @SqrtHP1
  511. JMP @SqrtHP5
  512. @SqrtHP2:
  513. SHR EAX, 1
  514. SHR R8D, 2
  515. JNZ @SqrtHP1
  516. @SqrtHP5:
  517. MOV R8D, $00004000
  518. SHL EAX, 16
  519. SHL ECX, 16
  520. @SqrtHP3:
  521. MOV EDX, ECX
  522. SUB EDX, R8D
  523. JB @SqrtHP4
  524. SUB EDX, EAX
  525. JB @SqrtHP4
  526. MOV ECX, EDX
  527. SHR EAX, 1
  528. OR EAX, R8D
  529. SHR R8D, 2
  530. JNZ @SqrtHP3
  531. RET
  532. @SqrtHP4:
  533. SHR EAX, 1
  534. SHR R8D, 2
  535. JNZ @SqrtHP3
  536. {$else}
  537. {$error 'Missing target'}
  538. {$ifend}
  539. end;
  540. {$ENDIF}
  541. //------------------------------------------------------------------------------
  542. // FixedCombine
  543. //------------------------------------------------------------------------------
  544. // combine fixed value X and fixed value Y with the weight of X given in W
  545. // Result Z = W * X + (1 - W) * Y = Y + (X - Y) * W
  546. // Fixed Point Version: Result Z = Y + (X - Y) * W / 65536
  547. //------------------------------------------------------------------------------
  548. {$IFDEF PUREPASCAL}
  549. function FixedCombine(W, X, Y: TFixed): TFixed;
  550. begin
  551. Result := Round(Y + (X - Y) * FixedToFloat * W);
  552. end;
  553. {$ELSE}
  554. function FixedCombine(W, X, Y: TFixed): TFixed; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  555. // EAX <- W, EDX <- X, ECX <- Y
  556. asm
  557. {$if defined(TARGET_x86)}
  558. SUB EDX, ECX
  559. IMUL EDX
  560. SHRD EAX, EDX, 16
  561. ADD EAX, ECX
  562. {$elseif defined(TARGET_x64)}
  563. MOV EAX, ECX
  564. SUB EDX, R8D
  565. IMUL EDX
  566. SHRD EAX, EDX, 16
  567. ADD EAX, R8D
  568. {$else}
  569. {$error 'Missing target'}
  570. {$ifend}
  571. end;
  572. {$ENDIF}
  573. //------------------------------------------------------------------------------
  574. //
  575. // Trigonometry
  576. //
  577. //------------------------------------------------------------------------------
  578. // SinCos
  579. //------------------------------------------------------------------------------
  580. {$if defined(PUREPASCAL) or defined(NATIVE_SINCOS)}
  581. procedure SinCos(const Theta: TFloat; out Sin, Cos: TFloat);
  582. var
  583. S, C: Extended;
  584. begin
  585. {$ifndef FPC}System.{$endif}Math.SinCos(Theta, S, C);
  586. Sin := S;
  587. Cos := C;
  588. end;
  589. {$else}
  590. procedure SinCos(const Theta: TFloat; out Sin, Cos: TFloat); {$IFDEF FPC} assembler; {$ENDIF}
  591. {$if defined(TARGET_x86)}
  592. asm
  593. FLD Theta
  594. FSINCOS
  595. FSTP DWORD PTR [EDX] // cosine
  596. FSTP DWORD PTR [EAX] // sine
  597. {$elseif defined(TARGET_x64)}
  598. var
  599. Temp: TFloat;
  600. asm
  601. MOVD Temp, Theta
  602. FLD Temp
  603. FSINCOS
  604. FSTP [Sin] // cosine
  605. FSTP [Cos] // sine
  606. {$else}
  607. {$error 'Missing target'}
  608. {$ifend}
  609. end;
  610. {$ifend}
  611. //------------------------------------------------------------------------------
  612. {$if defined(PUREPASCAL) or defined(NATIVE_SINCOS)}
  613. procedure SinCos(const Theta, Radius: TFloat; out Sin, Cos: TFloat);
  614. var
  615. S, C: Extended;
  616. begin
  617. {$ifndef FPC}System.{$endif}Math.SinCos(Theta, S, C);
  618. Sin := S * Radius;
  619. Cos := C * Radius;
  620. end;
  621. {$else}
  622. procedure SinCos(const Theta, Radius: TFloat; out Sin, Cos: TFloat); {$IFDEF FPC} assembler; {$ENDIF}
  623. {$if defined(TARGET_x86)}
  624. asm
  625. FLD Theta
  626. FSINCOS
  627. FMUL Radius
  628. FSTP DWORD PTR [EDX] // cosine
  629. FMUL Radius
  630. FSTP DWORD PTR [EAX] // sine
  631. {$elseif defined(TARGET_x64)}
  632. var
  633. Temp: TFloat;
  634. asm
  635. MOVD Temp, Theta
  636. FLD Temp
  637. MOVD Temp, Radius
  638. FSINCOS
  639. FMUL Temp
  640. FSTP [Cos]
  641. FMUL Temp
  642. FSTP [Sin]
  643. {$else}
  644. {$error 'Missing target'}
  645. {$ifend}
  646. end;
  647. {$ifend}
  648. //------------------------------------------------------------------------------
  649. {$if defined(PUREPASCAL) or defined(NATIVE_SINCOS)}
  650. procedure SinCos(const Theta, ScaleX, ScaleY: TFloat; out Sin, Cos: Single);
  651. var
  652. S, C: Extended;
  653. begin
  654. {$ifndef FPC}System.{$endif}Math.SinCos(Theta, S, C);
  655. Sin := S * ScaleX;
  656. Cos := C * ScaleY;
  657. end;
  658. {$else}
  659. procedure SinCos(const Theta, ScaleX, ScaleY: TFloat; out Sin, Cos: Single); {$IFDEF FPC} assembler; {$ENDIF}
  660. {$if defined(TARGET_x86)}
  661. asm
  662. FLD Theta
  663. FSINCOS
  664. FMUL ScaleX
  665. FSTP DWORD PTR [EDX] // cosine
  666. FMUL ScaleY
  667. FSTP DWORD PTR [EAX] // sine
  668. {$elseif defined(TARGET_x64)}
  669. var
  670. Temp: TFloat;
  671. asm
  672. MOVD Temp, Theta
  673. FLD Temp
  674. FSINCOS
  675. MOVD Temp, ScaleX
  676. FMUL Temp
  677. FSTP [Cos]
  678. MOVD Temp, ScaleY
  679. FMUL Temp
  680. FSTP [Sin]
  681. {$else}
  682. {$error 'Missing target'}
  683. {$ifend}
  684. end;
  685. {$ifend}
  686. //------------------------------------------------------------------------------
  687. // Hypot
  688. //------------------------------------------------------------------------------
  689. {$IFDEF PUREPASCAL}
  690. function Hypot(const X, Y: TFloat): TFloat;
  691. begin
  692. Result := Sqrt(Sqr(X) + Sqr(Y));
  693. end;
  694. {$ELSE}
  695. function Hypot(const X, Y: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64} nostackframe; {$ENDIF}{$ENDIF}
  696. asm
  697. {$if defined(TARGET_x86)}
  698. FLD X
  699. FMUL ST,ST
  700. FLD Y
  701. FMUL ST,ST
  702. FADDP ST(1),ST
  703. FSQRT
  704. FWAIT
  705. {$elseif defined(TARGET_x64)}
  706. MULSS XMM0, XMM0
  707. MULSS XMM1, XMM1
  708. ADDSS XMM0, XMM1
  709. SQRTSS XMM0, XMM0
  710. {$else}
  711. {$error 'Missing target'}
  712. {$ifend}
  713. end;
  714. {$ENDIF}
  715. //------------------------------------------------------------------------------
  716. {$if defined(PUREPASCAL) or (True)}
  717. function Hypot(const X, Y: Integer): Integer;
  718. begin
  719. Result := Round({$ifndef FPC}System.{$endif}Math.Hypot(X, Y));
  720. end;
  721. {$else}
  722. // TODO : Disabled for some reason. Document why!
  723. function Hypot(const X, Y: Integer): Integer; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  724. asm
  725. {$if defined(TARGET_x86)}
  726. IMUL RAX, RCX, RDX
  727. {$elseif defined(TARGET_x64)}
  728. FLD X
  729. FMUL ST,ST
  730. FLD Y
  731. FMUL ST,ST
  732. FADDP ST(1),ST
  733. FSQRT
  734. FISTP [ESP - 4]
  735. MOV EAX, [ESP - 4]
  736. FWAIT
  737. {$else}
  738. {$error 'Missing target'}
  739. {$ifend}
  740. end;
  741. {$ifend}
  742. //------------------------------------------------------------------------------
  743. //
  744. // Fast approximations
  745. //
  746. //------------------------------------------------------------------------------
  747. // FastSqrt
  748. //------------------------------------------------------------------------------
  749. {$IFDEF PUREPASCAL}
  750. function FastSqrt(const Value: TFloat): TFloat;
  751. var
  752. I: Integer absolute Value;
  753. J: Integer absolute Result;
  754. begin
  755. J := (I - $3F800000) div 2 + $3F800000;
  756. end;
  757. {$ELSE}
  758. function FastSqrt(const Value: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  759. asm
  760. {$if defined(TARGET_x86)}
  761. //
  762. // Sqrt(x) = x * InvSqrt(x)
  763. //
  764. // RSQRT is accurate only to ~11 bits.
  765. // Note: RSQRT(0) = INF, INF*0 = NAN !
  766. //
  767. MOV ECX, [Value]
  768. MOVD XMM0, ECX
  769. RSQRTSS XMM1, XMM0
  770. MULSS XMM1, XMM0
  771. UCOMISS XMM1, XMM1 // when XMM1=NAN then XMM1<>XMM1
  772. MOVD EAX, XMM1
  773. CMOVP EAX, ECX // Result := Value (which we assume is zero) if Result was NAN
  774. MOV [Result], EAX
  775. (* Fast, but pretty bad, approximations:
  776. see http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation
  777. MOV EAX, DWORD PTR Value
  778. { As outlined in the wikipedia article:
  779. SUB EAX, $00800000
  780. SAR EAX, 1
  781. ADD EAX, $20000000
  782. }
  783. { Previous GR32 implementation:
  784. SUB EAX, $3F800000
  785. SAR EAX, 1
  786. ADD EAX, $3F800000
  787. }
  788. MOV DWORD PTR [ESP - 4], EAX
  789. FLD DWORD PTR [ESP - 4]
  790. *)
  791. {$elseif defined(TARGET_x64)}
  792. SQRTSS XMM0, XMM0
  793. {$else}
  794. {$error 'Missing target'}
  795. {$ifend}
  796. end;
  797. {$ENDIF}
  798. //------------------------------------------------------------------------------
  799. // FastSqrtBab1
  800. //------------------------------------------------------------------------------
  801. // See http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation
  802. // Additionally one babylonian step added
  803. //------------------------------------------------------------------------------
  804. {$IFDEF PUREPASCAL}
  805. function FastSqrtBab1(const Value: TFloat): TFloat;
  806. const
  807. CHalf : TFloat = 0.5;
  808. var
  809. I: Integer absolute Value;
  810. J: Integer absolute Result;
  811. begin
  812. J := (I - $3F800000) div 2 + $3F800000;
  813. Result := CHalf * (Result + Value / Result);
  814. end;
  815. {$ELSE}
  816. function FastSqrtBab1(const Value: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  817. const
  818. CHalf : TFloat = 0.5;
  819. asm
  820. {$if defined(TARGET_x86)}
  821. MOV EAX, Value
  822. SUB EAX, $3F800000
  823. SAR EAX, 1
  824. ADD EAX, $3F800000
  825. MOV DWORD PTR [ESP - 4], EAX
  826. FLD Value
  827. FDIV DWORD PTR [ESP - 4]
  828. FADD DWORD PTR [ESP - 4]
  829. FMUL CHalf
  830. {$elseif defined(TARGET_x64)}
  831. SQRTSS XMM0, XMM0
  832. {$else}
  833. {$error 'Missing target'}
  834. {$ifend}
  835. end;
  836. {$ENDIF}
  837. //------------------------------------------------------------------------------
  838. // FastSqrtBab2
  839. //------------------------------------------------------------------------------
  840. // See http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation
  841. // Additionally two babylonian steps added
  842. //------------------------------------------------------------------------------
  843. {$IFDEF PUREPASCAL}
  844. function FastSqrtBab2(const Value: TFloat): TFloat;
  845. const
  846. CQuarter : TFloat = 0.25;
  847. var
  848. J: Integer absolute Result;
  849. begin
  850. Result := Value;
  851. J := ((J - (1 shl 23)) shr 1) + (1 shl 29);
  852. Result := Result + Value / Result;
  853. Result := CQuarter * Result + Value / Result;
  854. end;
  855. {$ELSE}
  856. function FastSqrtBab2(const Value: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  857. const
  858. CHalf : TFloat = 0.5;
  859. asm
  860. {$if defined(TARGET_x86)}
  861. MOV EAX, Value
  862. SUB EAX, $3F800000
  863. SAR EAX, 1
  864. ADD EAX, $3F800000
  865. MOV DWORD PTR [ESP - 4], EAX
  866. FLD Value
  867. FDIV DWORD PTR [ESP - 4]
  868. FADD DWORD PTR [ESP - 4]
  869. FMUL CHalf
  870. {$elseif defined(TARGET_x64)}
  871. MOVD EAX, Value
  872. SUB EAX, $3F800000
  873. SAR EAX, 1
  874. ADD EAX, $3F800000
  875. MOVD XMM1, EAX
  876. DIVSS XMM0, XMM1
  877. ADDSS XMM0, XMM1
  878. MOVD XMM1, [RIP + CHalf]
  879. MULSS XMM0, XMM1
  880. {$else}
  881. {$error 'Missing target'}
  882. {$ifend}
  883. end;
  884. {$ENDIF}
  885. //------------------------------------------------------------------------------
  886. // FastInvSqrt
  887. //------------------------------------------------------------------------------
  888. {$IFDEF PUREPASCAL}
  889. function FastInvSqrt(const Value: TFloat): TFloat;
  890. var
  891. IntCst : Cardinal absolute result;
  892. begin
  893. Result := Value;
  894. IntCst := ($BE6EB50C - IntCst) shr 1;
  895. Result := 0.5 * Result * (3 - Value * Sqr(Result));
  896. end;
  897. {$ELSE}
  898. function FastInvSqrt(const Value: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF}{$ENDIF}
  899. //
  900. // Note: RSQRT is accurate only to ~11 bits.
  901. //
  902. asm
  903. {$if defined(TARGET_x86)}
  904. MOVSS XMM0, [Value]
  905. RSQRTSS XMM0, XMM0
  906. MOVSS [Result], XMM0
  907. {$elseif defined(TARGET_x64)}
  908. RSQRTSS XMM0, XMM0
  909. {$else}
  910. {$error 'Missing target'}
  911. {$ifend}
  912. end;
  913. {$ENDIF}
  914. //------------------------------------------------------------------------------
  915. //
  916. // Misc. Routines
  917. //
  918. //------------------------------------------------------------------------------
  919. //
  920. // MulDiv
  921. //
  922. //------------------------------------------------------------------------------
  923. {$IFDEF PUREPASCAL}
  924. function MulDiv(Multiplicand, Multiplier, Divisor: Integer): Integer;
  925. begin
  926. Result := (Int64(Multiplicand) * Int64(Multiplier) + Divisor div 2) div Divisor;
  927. end;
  928. {$ELSE}
  929. function MulDiv(Multiplicand, Multiplier, Divisor: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  930. asm
  931. {$if defined(TARGET_x86)}
  932. PUSH EBX // Imperative save
  933. PUSH ESI // of EBX and ESI
  934. MOV EBX, EAX // Result will be negative or positive so set rounding direction
  935. XOR EBX, EDX // Negative: substract 1 in case of rounding
  936. XOR EBX, ECX // Positive: add 1
  937. OR EAX, EAX // Make all operands positive, ready for unsigned operations
  938. JNS @m1Ok // minimizing branching
  939. NEG EAX
  940. @m1Ok:
  941. OR EDX, EDX
  942. JNS @m2Ok
  943. NEG EDX
  944. @m2Ok:
  945. OR ECX, ECX
  946. JNS @DivOk
  947. NEG ECX
  948. @DivOK:
  949. MUL EDX // Unsigned multiply (Multiplicand*Multiplier)
  950. MOV ESI, EDX // Check for overflow, by comparing
  951. SHL ESI, 1 // 2 times the high-order 32 bits of the product (EDX)
  952. CMP ESI, ECX // with the Divisor.
  953. JAE @Overfl // If equal or greater than overflow with division anticipated
  954. DIV ECX // Unsigned divide of product by Divisor
  955. SUB ECX, EDX // Check if the result must be adjusted by adding or substracting
  956. CMP ECX, EDX // 1 (*.5 -> nearest integer), by comparing the difference of
  957. JA @NoAdd // Divisor and remainder with the remainder. If it is greater then
  958. INC EAX // no rounding needed; add 1 to result otherwise
  959. @NoAdd:
  960. OR EBX, EDX // From unsigned operations back the to original sign of the result
  961. JNS @Exit // must be positive
  962. NEG EAX // must be negative
  963. JMP @Exit
  964. @Overfl:
  965. OR EAX, -1 // 3 bytes alternative for MOV EAX,-1. Windows.MulDiv "overflow"
  966. // and "zero-divide" return value
  967. @Exit:
  968. POP ESI // Restore
  969. POP EBX // esi and EBX
  970. {$elseif defined(TARGET_x64)}
  971. MOV EAX, ECX // Result will be negative or positive so set rounding direction
  972. XOR ECX, EDX // Negative: substract 1 in case of rounding
  973. XOR ECX, R8D // Positive: add 1
  974. OR EAX, EAX // Make all operands positive, ready for unsigned operations
  975. JNS @m1Ok // minimizing branching
  976. NEG EAX
  977. @m1Ok:
  978. OR EDX, EDX
  979. JNS @m2Ok
  980. NEG EDX
  981. @m2Ok:
  982. OR R8D, R8D
  983. JNS @DivOk
  984. NEG R8D
  985. @DivOK:
  986. MUL EDX // Unsigned multiply (Multiplicand*Multiplier)
  987. MOV R9D, EDX // Check for overflow, by comparing
  988. SHL R9D, 1 // 2 times the high-order 32 bits of the product (EDX)
  989. CMP R9D, R8D // with the Divisor.
  990. JAE @Overfl // If equal or greater than overflow with division anticipated
  991. DIV R8D // Unsigned divide of product by Divisor
  992. SUB R8D, EDX // Check if the result must be adjusted by adding or substracting
  993. CMP R8D, EDX // 1 (*.5 -> nearest integer), by comparing the difference of
  994. JA @NoAdd // Divisor and remainder with the remainder. If it is greater then
  995. INC EAX // no rounding needed; add 1 to result otherwise
  996. @NoAdd:
  997. OR ECX, EDX // From unsigned operations back the to original sign of the result
  998. JNS @Exit // must be positive
  999. NEG EAX // must be negative
  1000. JMP @Exit
  1001. @Overfl:
  1002. OR EAX, -1 // 3 bytes alternative for MOV EAX,-1. Windows.MulDiv "overflow"
  1003. // and "zero-divide" return value
  1004. @Exit:
  1005. {$else}
  1006. {$error 'Missing target'}
  1007. {$ifend}
  1008. end;
  1009. {$ENDIF}
  1010. //------------------------------------------------------------------------------
  1011. //
  1012. // IsPowerOf2
  1013. //
  1014. //------------------------------------------------------------------------------
  1015. // Returns true when X = 1,2,4,8,16 etc.
  1016. //------------------------------------------------------------------------------
  1017. function IsPowerOf2(Value: Integer): Boolean;
  1018. begin
  1019. Result := (Value <> 0) and (Cardinal(Value) and (Cardinal(Value) - 1) = 0);
  1020. end;
  1021. //------------------------------------------------------------------------------
  1022. //
  1023. // PrevPowerOf2
  1024. //
  1025. //------------------------------------------------------------------------------
  1026. // Returns X rounded down to the power of two
  1027. //------------------------------------------------------------------------------
  1028. {$IFDEF PUREPASCAL}
  1029. function PrevPowerOf2(Value: Integer): Integer;
  1030. begin
  1031. Result := Value;
  1032. Result := Result or (Result shr 1);
  1033. Result := Result or (Result shr 2);
  1034. Result := Result or (Result shr 4);
  1035. Result := Result or (Result shr 8);
  1036. Result := Result or (Result shr 16);
  1037. Dec(Result, Result shr 1);
  1038. end;
  1039. {$ELSE}
  1040. function PrevPowerOf2(Value: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1041. asm
  1042. {$if defined(TARGET_x86)}
  1043. BSR ECX, EAX
  1044. SHR EAX, CL
  1045. SHL EAX, CL
  1046. {$elseif defined(TARGET_x64)}
  1047. MOV EAX, Value
  1048. BSR ECX, EAX
  1049. SHR EAX, CL
  1050. SHL EAX, CL
  1051. {$else}
  1052. {$error 'Missing target'}
  1053. {$ifend}
  1054. end;
  1055. {$ENDIF}
  1056. //------------------------------------------------------------------------------
  1057. //
  1058. // NextPowerOf2
  1059. //
  1060. //------------------------------------------------------------------------------
  1061. // Returns X rounded up to the power of two, i.e. 5 -> 8, 7 -> 8, 15 -> 16
  1062. //------------------------------------------------------------------------------
  1063. {$IFDEF PUREPASCAL}
  1064. function NextPowerOf2(Value: Integer): Integer;
  1065. begin
  1066. if (Value = 0) then
  1067. Exit(1);
  1068. Result := Value-1;
  1069. Result := Result or (Result shr 1);
  1070. Result := Result or (Result shr 2);
  1071. Result := Result or (Result shr 4);
  1072. Result := Result or (Result shr 8);
  1073. Result := Result or (Result shr 16);
  1074. Inc(Result);
  1075. end;
  1076. {$ELSE}
  1077. function NextPowerOf2(Value: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1078. asm
  1079. {$if defined(TARGET_x86)}
  1080. DEC EAX
  1081. JLE @1
  1082. BSR ECX, EAX
  1083. MOV EAX, 2
  1084. SHL EAX, CL
  1085. RET
  1086. @1:
  1087. MOV EAX, 1
  1088. {$elseif defined(TARGET_x64)}
  1089. MOV EAX, Value
  1090. DEC EAX
  1091. JLE @1
  1092. BSR ECX, EAX
  1093. MOV EAX, 2
  1094. SHL EAX, CL
  1095. RET
  1096. @1:
  1097. MOV EAX, 1
  1098. {$else}
  1099. {$error 'Missing target'}
  1100. {$ifend}
  1101. end;
  1102. {$ENDIF}
  1103. //------------------------------------------------------------------------------
  1104. //
  1105. // Average
  1106. //
  1107. //------------------------------------------------------------------------------
  1108. // Fast average without overflow, useful e.g. for fixed point math
  1109. // (A + B) / 2 = (A and B) + (A xor B) / 2
  1110. //------------------------------------------------------------------------------
  1111. {$IFDEF PUREPASCAL}
  1112. function Average(A, B: Integer): Integer;
  1113. begin
  1114. Result := (A and B) + (A xor B) div 2;
  1115. end;
  1116. {$ELSE}
  1117. function Average(A, B: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1118. asm
  1119. {$if defined(TARGET_x86)}
  1120. MOV ECX, EDX
  1121. XOR EDX, EAX
  1122. SAR EDX, 1
  1123. AND EAX, ECX
  1124. ADD EAX, EDX
  1125. {$elseif defined(TARGET_x64)}
  1126. MOV EAX, A
  1127. MOV ECX, EDX
  1128. XOR EDX, EAX
  1129. SAR EDX, 1
  1130. AND EAX, ECX
  1131. ADD EAX, EDX
  1132. {$else}
  1133. {$error 'Missing target'}
  1134. {$ifend}
  1135. end;
  1136. {$ENDIF}
  1137. //------------------------------------------------------------------------------
  1138. //
  1139. // Sign
  1140. //
  1141. //------------------------------------------------------------------------------
  1142. {$IFDEF PUREPASCAL}
  1143. function Sign(Value: Integer): Integer;
  1144. begin
  1145. // Defer to Math.Sign
  1146. Result := Integer({$ifndef FPC}System.{$endif}Math.Sign(Value));
  1147. end;
  1148. {$ELSE}
  1149. function Sign(Value: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1150. asm
  1151. {$if defined(TARGET_x86)}
  1152. { New algorithm provides no speed saving under 32-bit, so just use this
  1153. smaller one }
  1154. CDQ
  1155. NEG EAX
  1156. ADC EDX, EDX
  1157. MOV EAX, EDX
  1158. {$elseif defined(TARGET_x64)}
  1159. {$IFDEF MSWINDOWS}
  1160. XOR EDX, EDX
  1161. TEST ECX, ECX
  1162. SETG DL
  1163. SAR ECX, 31
  1164. LEA EAX, [EDX + ECX]
  1165. {$ELSE}
  1166. XOR EDX, EDX
  1167. TEST EDI, EDI
  1168. SETG DL
  1169. SAR EDI, 31
  1170. LEA EAX, [EDX + EDI]
  1171. {$ENDIF}
  1172. {$else}
  1173. {$error 'Missing target'}
  1174. {$ifend}
  1175. end;
  1176. {$ENDIF}
  1177. //------------------------------------------------------------------------------
  1178. //
  1179. // FloatMod
  1180. //
  1181. //------------------------------------------------------------------------------
  1182. function FloatMod(ANumerator, ADenominator: Double): Double;
  1183. begin
  1184. Result := FloatMod_D(ANumerator, ADenominator);
  1185. end;
  1186. function FloatMod(ANumerator, ADenominator: TFloat): TFloat;
  1187. begin
  1188. Result := FloatMod_F(ANumerator, ADenominator);
  1189. end;
  1190. //------------------------------------------------------------------------------
  1191. function FloatMod_F_Pas(ANumerator, ADenominator: TFloat): TFloat;
  1192. begin
  1193. if ((ANumerator >= 0) and (ANumerator < ADenominator)) or (ADenominator = 0) then
  1194. Result := ANumerator
  1195. else
  1196. Result := ANumerator - ADenominator * Floor(ANumerator / ADenominator);
  1197. end;
  1198. function FloatMod_D_Pas(ANumerator, ADenominator: Double): Double;
  1199. begin
  1200. if ((ANumerator >= 0) and (ANumerator < ADenominator)) or (ADenominator = 0) then
  1201. Result := ANumerator
  1202. else
  1203. Result := ANumerator - ADenominator * Floor(ANumerator / ADenominator);
  1204. end;
  1205. //------------------------------------------------------------------------------
  1206. {$ifndef PUREPASCAL}
  1207. // Note: FloatMod_F_SSE41 and FloatRemainder_F_SSE41 are identical except for the ROUNDSS parameter. Keep in sync!
  1208. // Note: Float*_D_SSE41 and Float*_F_SSE41 are the exact same except the D variant uses the *d instructions and and the F
  1209. // variant uses the *s instructions. Keep in sync!
  1210. function FloatMod_F_SSE41(ANumerator, ADenominator: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1211. asm
  1212. {$if defined(TARGET_x86)}
  1213. movss xmm0, ANumerator
  1214. movss xmm1, ADenominator
  1215. {$ifend}
  1216. xorps xmm2, xmm2
  1217. // if (ANumerator < 0) then...
  1218. comiss xmm0, xmm2
  1219. // ...do modulus...
  1220. jb @@do_mod
  1221. // if (ADenominator > ANumerator) then...
  1222. comiss xmm1, xmm0
  1223. // ...Result := ANumerator
  1224. ja @@return_value
  1225. @@do_mod:
  1226. // if (ADenominator = 0) then...
  1227. ucomiss xmm1, xmm2
  1228. lahf // AH <- Status flags
  1229. test ah, $44 // Test(AH, ZF or PF)
  1230. // ...Result := ANumerator
  1231. jnp @@return_value
  1232. // a := ANumerator / ADenominator
  1233. movss xmm2, xmm0
  1234. divss xmm2, xmm1
  1235. // b := Floor(a)
  1236. roundss xmm2, xmm2, SSE_ROUND.TO_NEG_INF + SSE_ROUND.NO_EXC
  1237. // c := ADenominator * b
  1238. mulss xmm2, xmm1
  1239. // Result := ANumerator - c;
  1240. subss xmm0, xmm2
  1241. // Fall through...
  1242. @@return_value:
  1243. {$if defined(TARGET_x86)}
  1244. movss Result, xmm0
  1245. {$elseif not defined(TARGET_x64)}
  1246. {$error 'Missing target'}
  1247. {$ifend}
  1248. end;
  1249. // Note: FloatMod_D_SSE41 and FloatRemainder_D_SSE41 are identical except for the ROUNDSD parameter. Keep in sync!
  1250. // Note: Float*_D_SSE41 and Float*_F_SSE41 are the exact same except the D variant uses the *d instructions and and the F
  1251. // variant uses the *s instructions. Keep in sync!
  1252. function FloatMod_D_SSE41(ANumerator, ADenominator: Double): Double; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1253. asm
  1254. {$if defined(TARGET_x86)}
  1255. movsd xmm0, ANumerator // XMM0 <- ANumerator
  1256. movsd xmm1, ADenominator // XMM1 <- ADenominator
  1257. {$ifend}
  1258. xorpd xmm2, xmm2 // XMM2 <- 0
  1259. // if (ANumerator < 0) then...
  1260. comisd xmm0, xmm2
  1261. // ...do modulus...
  1262. jb @@do_mod
  1263. // if (ADenominator > ANumerator) then...
  1264. comisd xmm1, xmm0
  1265. // ...Result := ANumerator
  1266. ja @@return_value
  1267. @@do_mod:
  1268. // if (ADenominator = 0) then...
  1269. ucomisd xmm1, xmm2
  1270. lahf // AH <- Status flags
  1271. test ah, $44 // Test(AH, ZF or PF)
  1272. // ...Result := ANumerator
  1273. jnp @@return_value
  1274. // a := ANumerator / ADenominator
  1275. movsd xmm2, xmm0
  1276. divsd xmm2, xmm1
  1277. // b := Floor(a)
  1278. roundsd xmm2, xmm2, SSE_ROUND.TO_NEG_INF + SSE_ROUND.NO_EXC
  1279. // c := ADenominator * b
  1280. mulsd xmm2, xmm1
  1281. // Result := ANumerator - c;
  1282. subsd xmm0, xmm2
  1283. // Fall through...
  1284. @@return_value:
  1285. {$if defined(TARGET_x86)}
  1286. movsd Result, xmm0
  1287. {$elseif not defined(TARGET_x64)}
  1288. {$error 'Missing target'}
  1289. {$ifend}
  1290. end;
  1291. {$endif PUREPASCAL}
  1292. //------------------------------------------------------------------------------
  1293. //
  1294. // FloatRemainder
  1295. //
  1296. //------------------------------------------------------------------------------
  1297. function FloatRemainder(ANumerator, ADenominator: Double): Double;
  1298. begin
  1299. Result := FloatRemainder_D(ANumerator, ADenominator);
  1300. end;
  1301. function FloatRemainder(ANumerator, ADenominator: TFloat): TFloat;
  1302. begin
  1303. Result := FloatRemainder_F(ANumerator, ADenominator);
  1304. end;
  1305. //------------------------------------------------------------------------------
  1306. function FloatRemainder_D_Pas(ANumerator, ADenominator: Double): Double;
  1307. begin
  1308. if ((ANumerator >= 0) and (ANumerator < ADenominator)) or (ADenominator = 0) then
  1309. Result := ANumerator
  1310. else
  1311. Result := ANumerator - ADenominator * Round(ANumerator / ADenominator);
  1312. end;
  1313. function FloatRemainder_F_Pas(ANumerator, ADenominator: TFloat): TFloat;
  1314. begin
  1315. if ((ANumerator >= 0) and (ANumerator < ADenominator)) or (ADenominator = 0) then
  1316. Result := ANumerator
  1317. else
  1318. Result := ANumerator - ADenominator * Round(ANumerator / ADenominator);
  1319. end;
  1320. //------------------------------------------------------------------------------
  1321. {$ifndef PUREPASCAL}
  1322. // Note: FloatMod_F_SSE41 and FloatRemainder_F_SSE41 are identical except for the ROUNDSS parameter. Keep in sync!
  1323. // Note: Float*_D_SSE41 and Float*_F_SSE41 are the exact same except the D variant uses the *d instructions and and the F
  1324. // variant uses the *s instructions. Keep in sync!
  1325. function FloatRemainder_F_SSE41(ANumerator, ADenominator: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1326. asm
  1327. {$if defined(TARGET_x86)}
  1328. movss xmm0, ANumerator
  1329. movss xmm1, ADenominator
  1330. {$ifend}
  1331. xorps xmm2, xmm2
  1332. // if (ANumerator < 0) then...
  1333. comiss xmm0, xmm2
  1334. // ...do modulus...
  1335. jb @@do_mod
  1336. // if (ADenominator > ANumerator) then...
  1337. comiss xmm1, xmm0
  1338. // ...Result := ANumerator
  1339. ja @@return_value
  1340. @@do_mod:
  1341. // if (ADenominator = 0) then...
  1342. ucomiss xmm1, xmm2
  1343. lahf // AH <- Status flags
  1344. test ah, $44 // Test(AH, ZF or PF)
  1345. // ...Result := ANumerator
  1346. jnp @@return_value
  1347. // a := ANumerator / ADenominator
  1348. movss xmm2, xmm0
  1349. divss xmm2, xmm1
  1350. // b := Round(a)
  1351. roundss xmm2, xmm2, SSE_ROUND.TO_NEAREST_INT + SSE_ROUND.NO_EXC
  1352. // c := ADenominator * b
  1353. mulss xmm2, xmm1
  1354. // Result := ANumerator - c;
  1355. subss xmm0, xmm2
  1356. // Fall through...
  1357. @@return_value:
  1358. {$if defined(TARGET_x86)}
  1359. movss Result, xmm0
  1360. {$elseif not defined(TARGET_x64)}
  1361. {$error 'Missing target'}
  1362. {$ifend}
  1363. end;
  1364. // Note: FloatMod_D_SSE41 and FloatRemainder_D_SSE41 are identical except for the ROUNDSD parameter. Keep in sync!
  1365. // Note: Float*_D_SSE41 and Float*_F_SSE41 are the exact same except the D variant uses the *d instructions and and the F
  1366. // variant uses the *s instructions. Keep in sync!
  1367. function FloatRemainder_D_SSE41(ANumerator, ADenominator: Double): Double; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1368. asm
  1369. {$if defined(TARGET_x86)}
  1370. movsd xmm0, ANumerator // XMM0 <- ANumerator
  1371. movsd xmm1, ADenominator // XMM1 <- ADenominator
  1372. {$ifend}
  1373. xorpd xmm2, xmm2
  1374. // if (ANumerator < 0) then...
  1375. comisd xmm0, xmm2
  1376. // ...do modulus...
  1377. jb @@do_mod
  1378. // if (ADenominator > ANumerator) then...
  1379. comisd xmm1, xmm0
  1380. // ...Result := ANumerator
  1381. ja @@return_value
  1382. @@do_mod:
  1383. // if (ADenominator = 0) then...
  1384. ucomisd xmm1, xmm2
  1385. lahf // AH <- Status flags
  1386. test ah, $44 // Test(AH, ZF or PF)
  1387. // ...Result := ANumerator
  1388. jnp @@return_value
  1389. // a := ANumerator / ADenominator
  1390. movsd xmm2, xmm0
  1391. divsd xmm2, xmm1
  1392. // b := Floor(a)
  1393. roundsd xmm2, xmm2, SSE_ROUND.TO_NEAREST_INT + SSE_ROUND.NO_EXC
  1394. // c := ADenominator * b
  1395. mulsd xmm2, xmm1
  1396. // Result := ANumerator - c;
  1397. subsd xmm0, xmm2
  1398. // Fall through...
  1399. @@return_value:
  1400. {$if defined(TARGET_x86)}
  1401. movsd Result, xmm0
  1402. {$elseif not defined(TARGET_x64)}
  1403. {$error 'Missing target'}
  1404. {$ifend}
  1405. end;
  1406. {$endif PUREPASCAL}
  1407. //------------------------------------------------------------------------------
  1408. //
  1409. // FMod
  1410. //
  1411. //------------------------------------------------------------------------------
  1412. function FMod(ANumerator, ADenominator: Double): Double;
  1413. begin
  1414. Result := FMod_D(ANumerator, ADenominator);
  1415. end;
  1416. function FMod(ANumerator, ADenominator: TFloat): TFloat;
  1417. begin
  1418. Result := FMod_F(ANumerator, ADenominator);
  1419. end;
  1420. //------------------------------------------------------------------------------
  1421. function FMod_F_Pas(ANumerator, ADenominator: TFloat): TFloat;
  1422. begin
  1423. Result := ANumerator - ADenominator * Trunc(ANumerator / ADenominator);
  1424. end;
  1425. function FMod_D_Pas(ANumerator, ADenominator: Double): Double;
  1426. begin
  1427. Result := ANumerator - ADenominator * Trunc(ANumerator / ADenominator);
  1428. end;
  1429. //------------------------------------------------------------------------------
  1430. {$ifndef PUREPASCAL}
  1431. // Note: FMod_F_SSE2 and FMod_D_SSE2 are the exact same except the D variant uses the *d instructions and and the F
  1432. // variant uses the *s instructions. Keep in sync!
  1433. function FMod_F_SSE2(ANumerator, ADenominator: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1434. asm
  1435. {$if defined(TARGET_x86)}
  1436. movss xmm0, ANumerator // XMM0 <- ANumerator
  1437. movss xmm1, ADenominator // XMM1 <- ADenominator
  1438. {$ifend}
  1439. // a := ANumerator
  1440. movss xmm2, xmm0
  1441. // a := ANumerator / ADenominator
  1442. divss xmm2, xmm1
  1443. // b := Trunc(a)
  1444. cvttss2si ecx, xmm2
  1445. cvtsi2ss xmm2, ecx
  1446. // c := b*ADenominator
  1447. mulss xmm2, xmm1
  1448. // Result := ANumerator - c;
  1449. subss xmm0, xmm2
  1450. {$if defined(TARGET_x86)}
  1451. movss Result, xmm0
  1452. {$elseif not defined(TARGET_x64)}
  1453. {$error 'Missing target'}
  1454. {$ifend}
  1455. end;
  1456. function FMod_D_SSE2(ANumerator, ADenominator: Double): Double; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1457. asm
  1458. {$if defined(TARGET_x86)}
  1459. movsd xmm0, ANumerator // XMM0 <- ANumerator
  1460. movsd xmm1, ADenominator // XMM1 <- ADenominator
  1461. {$ifend}
  1462. // a := ANumerator
  1463. movsd xmm2, xmm0
  1464. // a := ANumerator / ADenominator
  1465. divsd xmm2, xmm1
  1466. // b := Trunc(a)
  1467. cvttsd2si ecx, xmm2
  1468. cvtsi2sd xmm2, ecx
  1469. // c := b*ADenominator
  1470. mulsd xmm2, xmm1
  1471. // Result := ANumerator - c;
  1472. subsd xmm0, xmm2
  1473. {$if defined(TARGET_x86)}
  1474. movsd Result, xmm0
  1475. {$elseif not defined(TARGET_x64)}
  1476. {$error 'Missing target'}
  1477. {$ifend}
  1478. end;
  1479. {$endif PUREPASCAL}
  1480. //------------------------------------------------------------------------------
  1481. {$ifndef PUREPASCAL}
  1482. // Note: FMod_F_SSE41 and FMod_D_SSE41 are the exact same except the D variant uses the *d instructions and and the F
  1483. // variant uses the *s instructions. Keep in sync!
  1484. function FMod_F_SSE41(ANumerator, ADenominator: TFloat): TFloat; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1485. asm
  1486. {$if defined(TARGET_x86)}
  1487. movss xmm0, ANumerator // XMM0 <- ANumerator
  1488. movss xmm1, ADenominator // XMM1 <- ADenominator
  1489. {$ifend}
  1490. // a := ANumerator
  1491. movss xmm2, xmm0
  1492. // a := ANumerator / ADenominator
  1493. divss xmm2, xmm1
  1494. // b := Trunc(a)
  1495. roundss xmm2, xmm2, SSE_ROUND.TO_ZERO + SSE_ROUND.NO_EXC
  1496. // c := b*ADenominator
  1497. mulss xmm2, xmm1
  1498. // Result := ANumerator - c;
  1499. subss xmm0, xmm2
  1500. {$if defined(TARGET_x86)}
  1501. movss Result, xmm0
  1502. {$elseif not defined(TARGET_x64)}
  1503. {$error 'Missing target'}
  1504. {$ifend}
  1505. end;
  1506. function FMod_D_SSE41(ANumerator, ADenominator: Double): Double; {$IFDEF FPC} assembler; {$IFDEF TARGET_X64}nostackframe;{$ENDIF} {$ENDIF}
  1507. asm
  1508. {$if defined(TARGET_x86)}
  1509. movsd xmm0, ANumerator // XMM0 <- ANumerator
  1510. movsd xmm1, ADenominator // XMM1 <- ADenominator
  1511. {$ifend}
  1512. // a := ANumerator
  1513. movsd xmm2, xmm0
  1514. // a := ANumerator / ADenominator
  1515. divsd xmm2, xmm1
  1516. // b := Trunc(a)
  1517. roundsd xmm2, xmm2, SSE_ROUND.TO_ZERO + SSE_ROUND.NO_EXC
  1518. // c := b*ADenominator
  1519. mulsd xmm2, xmm1
  1520. // Result := ANumerator - c;
  1521. subsd xmm0, xmm2
  1522. {$if defined(TARGET_x86)}
  1523. movsd Result, xmm0
  1524. {$elseif not defined(TARGET_x64)}
  1525. {$error 'Missing target'}
  1526. {$ifend}
  1527. end;
  1528. {$endif PUREPASCAL}
  1529. //------------------------------------------------------------------------------
  1530. //
  1531. // DivMod
  1532. //
  1533. //------------------------------------------------------------------------------
  1534. {$IFDEF PUREPASCAL}
  1535. function DivMod(Dividend, Divisor: Integer; var Remainder: Integer): Integer;
  1536. begin
  1537. Result := Dividend div Divisor;
  1538. Remainder := Dividend mod Divisor;
  1539. end;
  1540. {$ELSE}
  1541. function DivMod(Dividend, Divisor: Integer; var Remainder: Integer): Integer; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1542. asm
  1543. {$if defined(TARGET_x86)}
  1544. PUSH EDX
  1545. CDQ
  1546. IDIV DWORD PTR [ESP]
  1547. ADD ESP, $04
  1548. MOV DWORD PTR [ECX], edx
  1549. {$elseif defined(TARGET_x64)}
  1550. {$IFDEF MSWINDOWS}
  1551. MOV EAX, ECX
  1552. MOV ECX, EDX
  1553. CDQ
  1554. IDIV ECX
  1555. MOV [R8],EDX
  1556. {$ELSE}
  1557. MOV EAX, EDI
  1558. MOV RDI, RDX
  1559. CDQ
  1560. IDIV ESI
  1561. MOV [RDI],EDX
  1562. {$ENDIF}
  1563. {$else}
  1564. {$error 'Missing target'}
  1565. {$ifend}
  1566. end;
  1567. {$ENDIF}
  1568. //------------------------------------------------------------------------------
  1569. //
  1570. // CumSum
  1571. //
  1572. //------------------------------------------------------------------------------
  1573. procedure CumSum_Pas(Values: PSingleArray; Count: Integer);
  1574. var
  1575. I: Integer;
  1576. V: TFloat;
  1577. begin
  1578. V := Values[0];
  1579. for I := 1 to Count - 1 do
  1580. begin
  1581. V := V + Values[I];
  1582. Values[I] := V;
  1583. end;
  1584. end;
  1585. //------------------------------------------------------------------------------
  1586. // Reference Pascal version of CumSum_SSE2_Simple
  1587. procedure CumSum_Pas_Simple(Values: PSingleArray; Count: Integer);
  1588. var
  1589. V: TFloat;
  1590. begin
  1591. Values := pointer(@Values[Count]);
  1592. Count := -Count;
  1593. V := 0;
  1594. while Count <> 0 do
  1595. begin
  1596. V := V + Values[Count];
  1597. Values[Count] := V;
  1598. Inc(Count);
  1599. end;
  1600. end;
  1601. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  1602. // Very simple SSE2 version for Sandy- and Ivy Bridge
  1603. procedure CumSum_SSE2_Simple(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1604. asm
  1605. {$if defined(TARGET_x86)}
  1606. // Parameters (x86):
  1607. // EAX <- Values
  1608. // EDX <- Count
  1609. // SSE register usage:
  1610. // XMM0: Running total
  1611. // while Count <> 0 do
  1612. TEST EDX, EDX
  1613. JLE @Done
  1614. // Values := pointer(@Values[Count]);
  1615. LEA EAX, [EAX + EDX * 4] // Get address of last entry + 1
  1616. // Count := -Count;
  1617. NEG EDX // Negate count so we can use it as an offset to move forward
  1618. // V := 0;
  1619. PXOR XMM0, XMM0 // XMM0 <- 0
  1620. @Loop:
  1621. // V := V + Values[Count];
  1622. ADDSS XMM0, dword ptr [EAX + EDX * 4]
  1623. // Values[Count] := V;
  1624. MOVSS dword ptr [EAX + EDX * 4], XMM0
  1625. // Inc(Count);
  1626. ADD EDX, 1
  1627. // while Count <> 0 do
  1628. JS @Loop
  1629. @Done:
  1630. {$elseif defined(TARGET_x64)}
  1631. // Parameters (x64):
  1632. // RCX <- Values
  1633. // RDX <- Count
  1634. // SSE register usage:
  1635. // XMM0: Running total
  1636. // while Count <> 0 do
  1637. TEST RDX, RDX
  1638. JLE @Done
  1639. // Values := pointer(@Values[Count]);
  1640. LEA RCX, [RCX + RDX * 4] // Get address of last entry + 1
  1641. // Count := -Count;
  1642. NEG RDX // Negate count so we can use it as an offset to move forward
  1643. // V := 0;
  1644. PXOR XMM0, XMM0 // XMM0 <- 0
  1645. @Loop:
  1646. // V := V + Values[Count];
  1647. ADDSS XMM0, dword ptr [RCX + RDX * 4]
  1648. // Values[Count] := V;
  1649. MOVSS dword ptr [RCX + RDX * 4], XMM0
  1650. // Inc(Count);
  1651. ADD RDX, 1
  1652. // while Count <> 0 do
  1653. JS @Loop
  1654. @Done:
  1655. {$else}
  1656. {$error 'Missing target'}
  1657. {$ifend}
  1658. end;
  1659. // Aligned SSE2 version -- Credits: Sanyin <[email protected]>
  1660. procedure CumSum_SSE2(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1661. asm
  1662. {$if defined(TARGET_x86)}
  1663. MOV ECX,EDX
  1664. CMP ECX,2 // if count < 2, exit
  1665. JL @END
  1666. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  1667. JL @SMALL
  1668. {--- align memory ---}
  1669. PUSH EBX
  1670. PXOR XMM4,XMM4
  1671. MOV EBX,EAX
  1672. AND EBX,15 // get aligned count
  1673. JZ @ENDALIGNING // already aligned
  1674. ADD EBX,-16
  1675. NEG EBX // get bytes to advance
  1676. JZ @ENDALIGNING // already aligned
  1677. MOV ECX,EBX
  1678. SAR ECX,2 // div with 4 to get cnt
  1679. SUB EDX,ECX
  1680. ADD EAX,4
  1681. DEC ECX
  1682. JZ @SETUPLAST // one element
  1683. @ALIGNINGLOOP:
  1684. FLD DWORD PTR [EAX-4]
  1685. FADD DWORD PTR [EAX]
  1686. FSTP DWORD PTR [EAX]
  1687. ADD EAX,4
  1688. DEC ECX
  1689. JNZ @ALIGNINGLOOP
  1690. @SETUPLAST:
  1691. MOVUPS XMM4,[EAX-4]
  1692. PSLLDQ XMM4,12
  1693. PSRLDQ XMM4,12
  1694. @ENDALIGNING:
  1695. POP EBX
  1696. PUSH EBX
  1697. MOV ECX,EDX
  1698. SAR ECX,2
  1699. @LOOP:
  1700. MOVAPS XMM0,[EAX]
  1701. PXOR XMM5,XMM5
  1702. PCMPEQD XMM5,XMM0
  1703. PMOVMSKB EBX,XMM5
  1704. CMP EBX,$0000FFFF
  1705. JNE @NORMAL
  1706. PSHUFD XMM0,XMM4,0
  1707. JMP @SKIP
  1708. @NORMAL:
  1709. ADDPS XMM0,XMM4
  1710. PSHUFD XMM1,XMM0,$e4
  1711. PSLLDQ XMM1,4
  1712. PSHUFD XMM2,XMM1,$90
  1713. PSHUFD XMM3,XMM1,$40
  1714. ADDPS XMM2,XMM3
  1715. ADDPS XMM1,XMM2
  1716. ADDPS XMM0,XMM1
  1717. PSHUFLW XMM4,XMM0,$E4
  1718. PSRLDQ XMM4,12
  1719. @SKIP:
  1720. PREFETCHNTA [eax+16*16*2]
  1721. MOVAPS [EAX],XMM0
  1722. ADD EAX,16
  1723. SUB ECX,1
  1724. JNZ @LOOP
  1725. POP EBX
  1726. MOV ECX,EDX
  1727. SAR ECX,2
  1728. SHL ECX,2
  1729. SUB EDX,ECX
  1730. MOV ECX,EDX
  1731. JZ @END
  1732. @LOOP2:
  1733. FLD DWORD PTR [EAX-4]
  1734. FADD DWORD PTR [EAX]
  1735. FSTP DWORD PTR [EAX]
  1736. ADD EAX,4
  1737. DEC ECX
  1738. JNZ @LOOP2
  1739. JMP @END
  1740. @SMALL:
  1741. MOV ECX,EDX
  1742. ADD EAX,4
  1743. DEC ECX
  1744. @LOOP3:
  1745. FLD DWORD PTR [EAX-4]
  1746. FADD DWORD PTR [EAX]
  1747. FSTP DWORD PTR [EAX]
  1748. ADD EAX,4
  1749. DEC ECX
  1750. JNZ @LOOP3
  1751. @END:
  1752. {$elseif defined(TARGET_x64)}
  1753. CMP EDX,2 // if count < 2, exit
  1754. JL @END
  1755. MOV RAX,RCX
  1756. MOV ECX,EDX
  1757. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  1758. JL @SMALL
  1759. {--- align memory ---}
  1760. PXOR XMM4,XMM4
  1761. MOV R8D,EAX
  1762. AND R8D,15 // get aligned count
  1763. JZ @ENDALIGNING // already aligned
  1764. ADD R8D,-16
  1765. NEG R8D // get bytes to advance
  1766. JZ @ENDALIGNING // already aligned
  1767. MOV ECX,R8D
  1768. SAR ECX,2 // div with 4 to get cnt
  1769. SUB EDX,ECX
  1770. ADD RAX,4
  1771. DEC ECX
  1772. JZ @SETUPLAST // one element
  1773. @ALIGNINGLOOP:
  1774. FLD DWORD PTR [RAX - 4]
  1775. FADD DWORD PTR [RAX]
  1776. FSTP DWORD PTR [RAX]
  1777. ADD RAX,4
  1778. DEC ECX
  1779. JNZ @ALIGNINGLOOP
  1780. @SETUPLAST:
  1781. MOVUPS XMM4,[RAX - 4]
  1782. PSLLDQ XMM4,12
  1783. PSRLDQ XMM4,12
  1784. @ENDALIGNING:
  1785. MOV ECX,EDX
  1786. SAR ECX,2
  1787. @LOOP:
  1788. MOVAPS XMM0,[RAX]
  1789. PXOR XMM5,XMM5
  1790. PCMPEQD XMM5,XMM0
  1791. PMOVMSKB R8D,XMM5
  1792. CMP R8D,$0000FFFF
  1793. JNE @NORMAL
  1794. PSHUFD XMM0,XMM4,0
  1795. JMP @SKIP
  1796. @NORMAL:
  1797. ADDPS XMM0,XMM4
  1798. PSHUFD XMM1,XMM0,$e4
  1799. PSLLDQ XMM1,4
  1800. PSHUFD XMM2,XMM1,$90
  1801. PSHUFD XMM3,XMM1,$40
  1802. ADDPS XMM2,XMM3
  1803. ADDPS XMM1,XMM2
  1804. ADDPS XMM0,XMM1
  1805. PSHUFLW XMM4,XMM0,$E4
  1806. PSRLDQ XMM4,12
  1807. @SKIP:
  1808. PREFETCHNTA [RAX + 32 * 2]
  1809. MOVAPS [RAX],XMM0
  1810. ADD RAX,16
  1811. SUB ECX,1
  1812. JNZ @LOOP
  1813. MOV ECX,EDX
  1814. SAR ECX,2
  1815. SHL ECX,2
  1816. SUB EDX,ECX
  1817. MOV ECX,EDX
  1818. JZ @END
  1819. @LOOP2:
  1820. FLD DWORD PTR [RAX - 4]
  1821. FADD DWORD PTR [RAX]
  1822. FSTP DWORD PTR [RAX]
  1823. ADD RAX,4
  1824. DEC ECX
  1825. JNZ @LOOP2
  1826. JMP @END
  1827. @SMALL:
  1828. ADD RAX,4
  1829. DEC ECX
  1830. @LOOP3:
  1831. FLD DWORD PTR [RAX - 4]
  1832. FADD DWORD PTR [RAX]
  1833. FSTP DWORD PTR [RAX]
  1834. ADD RAX,4
  1835. DEC ECX
  1836. JNZ @LOOP3
  1837. @END:
  1838. {$else}
  1839. {$error 'Missing target'}
  1840. {$ifend}
  1841. end;
  1842. // Contributed by Kadaif, based on Sanyin's aligned SSE2 version
  1843. procedure CumSum_SSE2_kadaif1(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  1844. asm
  1845. {$if defined(TARGET_x86)}
  1846. MOV ECX,EDX
  1847. CMP ECX,2 // if count < 2, exit
  1848. JL @END
  1849. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  1850. JL @SMALL
  1851. {--- align memory ---}
  1852. PUSH EBX
  1853. PXOR XMM4,XMM4
  1854. MOV EBX,EAX
  1855. AND EBX,15 // get aligned count
  1856. JZ @ENDALIGNING // already aligned
  1857. ADD EBX,-16
  1858. NEG EBX // get bytes to advance
  1859. JZ @ENDALIGNING // already aligned
  1860. MOV ECX,EBX
  1861. SAR ECX,2 // div with 4 to get cnt
  1862. SUB EDX,ECX
  1863. ADD EAX,4
  1864. DEC ECX
  1865. JZ @SETUPLAST // one element
  1866. @ALIGNINGLOOP:
  1867. MOVSS XMM0,DWORD PTR [EAX-4]
  1868. ADDSS XMM0,DWORD PTR [EAX]
  1869. MOVSS DWORD PTR [EAX],XMM0
  1870. ADD EAX,4
  1871. DEC ECX
  1872. JNZ @ALIGNINGLOOP
  1873. @SETUPLAST:
  1874. MOVUPS XMM4,[EAX-4]
  1875. PSLLDQ XMM4,12
  1876. PSRLDQ XMM4,12
  1877. @ENDALIGNING:
  1878. POP EBX
  1879. PUSH EBX
  1880. MOV ECX,EDX
  1881. SAR ECX,2
  1882. @LOOP:
  1883. MOVAPS XMM0,[EAX]
  1884. PXOR XMM5,XMM5
  1885. PCMPEQD XMM5,XMM0
  1886. PMOVMSKB EBX,XMM5
  1887. CMP EBX,$0000FFFF
  1888. JNE @NORMAL
  1889. PSHUFD XMM0,XMM4,0
  1890. JMP @SKIP
  1891. @NORMAL:
  1892. ADDPS XMM0,XMM4
  1893. MOVDQA XMM2,XMM0
  1894. PSLLDQ XMM2,4
  1895. ADDPS XMM0,XMM2
  1896. MOVDQA XMM2,XMM0
  1897. PSLLDQ XMM2,8
  1898. ADDPS XMM0,XMM2
  1899. MOVAPS XMM4,XMM0
  1900. PSRLDQ XMM4,12
  1901. @SKIP:
  1902. PREFETCHNTA [eax+16*16*2]
  1903. MOVAPS [EAX],XMM0
  1904. ADD EAX,16
  1905. SUB ECX,1
  1906. JNZ @LOOP
  1907. POP EBX
  1908. MOV ECX,EDX
  1909. SAR ECX,2
  1910. SHL ECX,2
  1911. SUB EDX,ECX
  1912. MOV ECX,EDX
  1913. JZ @END
  1914. @LOOP2:
  1915. MOVSS XMM0,DWORD PTR [EAX-4]
  1916. ADDSS XMM0,DWORD PTR [EAX]
  1917. MOVSS DWORD PTR [EAX],XMM0
  1918. ADD EAX,4
  1919. DEC ECX
  1920. JNZ @LOOP2
  1921. JMP @END
  1922. @SMALL:
  1923. CMP ECX,4
  1924. JL @SMALL2
  1925. SAR ECX,2
  1926. PXOR XMM4,XMM4
  1927. @LOOP3:
  1928. MOVUPS XMM0,[EAX]
  1929. ADDPS XMM0,XMM4
  1930. MOVDQA XMM2,XMM0
  1931. PSLLDQ XMM2,4
  1932. ADDPS XMM0,XMM2
  1933. MOVDQA XMM2,XMM0
  1934. PSLLDQ XMM2,8
  1935. ADDPS XMM0,XMM2
  1936. MOVAPS XMM4,XMM0
  1937. PSRLDQ XMM4,12
  1938. MOVUPS [EAX],XMM0
  1939. ADD EAX,16
  1940. SUB EDX,4
  1941. SUB ECX,1
  1942. JNZ @LOOP3
  1943. CMP EDX, 0
  1944. JZ @END
  1945. MOV ECX,EDX
  1946. JMP @LOOP4
  1947. @SMALL2:
  1948. MOV ECX,EDX
  1949. ADD EAX,4
  1950. DEC ECX
  1951. @LOOP4:
  1952. MOVSS XMM0,DWORD PTR [EAX-4]
  1953. ADDSS XMM0,DWORD PTR [EAX]
  1954. MOVSS DWORD PTR [EAX],XMM0
  1955. ADD EAX,4
  1956. DEC ECX
  1957. JNZ @LOOP4
  1958. @END:
  1959. {$elseif defined(TARGET_x64)}
  1960. CMP EDX,2 // if count < 2, exit
  1961. JL @END
  1962. MOV RAX,RCX
  1963. MOV ECX,EDX
  1964. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  1965. JL @SMALL
  1966. {--- align memory ---}
  1967. PXOR XMM4,XMM4
  1968. MOV R8D,EAX
  1969. AND R8D,15 // get aligned count
  1970. JZ @ENDALIGNING // already aligned
  1971. ADD R8D,-16
  1972. NEG R8D // get bytes to advance
  1973. JZ @ENDALIGNING // already aligned
  1974. MOV ECX,R8D
  1975. SAR ECX,2 // div with 4 to get cnt
  1976. SUB EDX,ECX
  1977. ADD RAX,4
  1978. DEC ECX
  1979. JZ @SETUPLAST // one element
  1980. @ALIGNINGLOOP:
  1981. MOVSS XMM0,DWORD PTR [RAX - 4]
  1982. ADDSS XMM0,DWORD PTR [RAX]
  1983. MOVSS DWORD PTR [RAX],XMM0
  1984. ADD RAX,4
  1985. DEC ECX
  1986. JNZ @ALIGNINGLOOP
  1987. @SETUPLAST:
  1988. MOVUPS XMM4,[RAX - 4]
  1989. PSLLDQ XMM4,12
  1990. PSRLDQ XMM4,12
  1991. @ENDALIGNING:
  1992. MOV ECX,EDX
  1993. SAR ECX,2
  1994. @LOOP:
  1995. MOVAPS XMM0,[RAX]
  1996. PXOR XMM5,XMM5
  1997. PCMPEQD XMM5,XMM0
  1998. PMOVMSKB R8D,XMM5
  1999. CMP R8D,$0000FFFF
  2000. JNE @NORMAL
  2001. PSHUFD XMM0,XMM4,0
  2002. JMP @SKIP
  2003. @NORMAL:
  2004. ADDPS XMM0,XMM4
  2005. MOVDQA XMM2,XMM0
  2006. PSLLDQ XMM2,4
  2007. ADDPS XMM0,XMM2
  2008. MOVDQA XMM2,XMM0
  2009. PSLLDQ XMM2,8
  2010. ADDPS XMM0,XMM2
  2011. MOVAPS XMM4,XMM0
  2012. PSRLDQ XMM4,12
  2013. @SKIP:
  2014. PREFETCHNTA [RAX + 32 * 2]
  2015. MOVAPS [RAX],XMM0
  2016. ADD RAX,16
  2017. SUB ECX,1
  2018. JNZ @LOOP
  2019. MOV ECX,EDX
  2020. SAR ECX,2
  2021. SHL ECX,2
  2022. SUB EDX,ECX
  2023. MOV ECX,EDX
  2024. JZ @END
  2025. @LOOP2:
  2026. MOVSS XMM0,DWORD PTR [RAX - 4]
  2027. ADDSS XMM0,DWORD PTR [RAX]
  2028. MOVSS DWORD PTR [RAX],XMM0
  2029. ADD RAX,4
  2030. DEC ECX
  2031. JNZ @LOOP2
  2032. JMP @END
  2033. @SMALL:
  2034. CMP ECX,4
  2035. JL @SMALL2
  2036. SAR ECX,2
  2037. PXOR XMM4,XMM4
  2038. @LOOP3:
  2039. MOVUPS XMM0,[RAX]
  2040. ADDPS XMM0,XMM4
  2041. MOVDQA XMM2,XMM0
  2042. PSLLDQ XMM2,4
  2043. ADDPS XMM0,XMM2
  2044. MOVDQA XMM2,XMM0
  2045. PSLLDQ XMM2,8
  2046. ADDPS XMM0,XMM2
  2047. MOVAPS XMM4,XMM0
  2048. PSRLDQ XMM4,12
  2049. MOVUPS [RAX],XMM0
  2050. ADD RAX,16
  2051. SUB EDX,4
  2052. SUB ECX,1
  2053. JNZ @LOOP3
  2054. CMP EDX, 0
  2055. JZ @END
  2056. MOV ECX,EDX
  2057. JMP @LOOP4
  2058. @SMALL2:
  2059. ADD RAX,4
  2060. DEC ECX
  2061. @LOOP4:
  2062. MOVSS XMM0,DWORD PTR [RAX - 4]
  2063. ADDSS XMM0,DWORD PTR [RAX]
  2064. MOVSS DWORD PTR [RAX],XMM0
  2065. ADD RAX,4
  2066. DEC ECX
  2067. JNZ @LOOP4
  2068. @END:
  2069. {$else}
  2070. {$error 'Missing target'}
  2071. {$ifend}
  2072. end;
  2073. procedure CumSum_SSE2_kadaif2(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  2074. asm
  2075. {$if defined(TARGET_x86)}
  2076. CMP EDX,2 // if count < 2, exit
  2077. JL @END
  2078. MOV ECX,EDX
  2079. CMP EDX,32 // if count < 32, avoid SSE2 overhead
  2080. JL @SMALL
  2081. {--- align memory ---}
  2082. PUSH EBX
  2083. PXOR XMM4,XMM4
  2084. MOV EBX,EAX
  2085. AND EBX,15 // get aligned count
  2086. JZ @ENDALIGNING // already aligned
  2087. ADD EBX,-16
  2088. NEG EBX // get bytes to advance
  2089. JZ @ENDALIGNING // already aligned
  2090. MOV ECX,EBX
  2091. SAR ECX,2 // div with 4 to get cnt
  2092. SUB EDX,ECX
  2093. ADD EAX,4
  2094. DEC ECX
  2095. JZ @SETUPLAST // one element
  2096. @ALIGNINGLOOP:
  2097. MOVSS XMM0,DWORD PTR [EAX - 4]
  2098. ADDSS XMM0,DWORD PTR [EAX]
  2099. MOVSS DWORD PTR [EAX],XMM0
  2100. ADD EAX,4
  2101. DEC ECX
  2102. JNZ @ALIGNINGLOOP
  2103. @SETUPLAST:
  2104. MOVUPS XMM4,[EAX - 4]
  2105. PSLLDQ XMM4,12
  2106. PSRLDQ XMM4,12
  2107. @ENDALIGNING:
  2108. POP EBX
  2109. PUSH EBX
  2110. MOV ECX,EDX
  2111. SAR ECX,2
  2112. @LOOP:
  2113. MOVAPS XMM0,[EAX]
  2114. PXOR XMM5,XMM5
  2115. PCMPEQD XMM5,XMM0
  2116. PMOVMSKB EBX,XMM5
  2117. CMP EBX,$0000FFFF
  2118. JNE @NORMAL
  2119. PSHUFD XMM0,XMM4,0
  2120. JMP @SKIP
  2121. @NORMAL:
  2122. ADDPS XMM0,XMM4
  2123. MOVAPS XMM2,XMM0
  2124. PSLLDQ XMM2,4
  2125. ADDPS XMM0,XMM2
  2126. MOVAPS XMM2,XMM0
  2127. PSLLDQ XMM2,8
  2128. ADDPS XMM0,XMM2
  2129. MOVAPS XMM4,XMM0
  2130. PSRLDQ XMM4,12
  2131. @SKIP:
  2132. PREFETCHNTA [EAX + 16 * 16 * 2]
  2133. MOVAPS [EAX],XMM0
  2134. ADD EAX,16
  2135. SUB ECX,1
  2136. JNZ @LOOP
  2137. POP EBX
  2138. MOV ECX,EDX
  2139. AND ECX,3
  2140. JZ @END
  2141. @LOOP2:
  2142. MOVSS XMM0,DWORD PTR [EAX - 4]
  2143. ADDSS XMM0,DWORD PTR [EAX]
  2144. MOVSS DWORD PTR [EAX],XMM0
  2145. ADD EAX,4
  2146. DEC ECX
  2147. JNZ @LOOP2
  2148. JMP @END
  2149. @SMALL:
  2150. CMP ECX,8
  2151. JL @SMALL2
  2152. SAR ECX,2
  2153. PXOR XMM4,XMM4
  2154. @LOOP3:
  2155. MOVUPS XMM0,[EAX]
  2156. ADDPS XMM0,XMM4
  2157. MOVAPS XMM2,XMM0
  2158. PSLLDQ XMM2,4
  2159. ADDPS XMM0,XMM2
  2160. MOVAPS XMM2,XMM0
  2161. PSLLDQ XMM2,8
  2162. ADDPS XMM0,XMM2
  2163. MOVAPS XMM4,XMM0
  2164. PSRLDQ XMM4,12
  2165. MOVUPS [EAX],XMM0
  2166. ADD EAX,16
  2167. SUB EDX,4
  2168. SUB ECX,1
  2169. JNZ @LOOP3
  2170. CMP EDX, 0
  2171. JZ @END
  2172. MOV ECX,EDX
  2173. JMP @LOOP4
  2174. @SMALL2:
  2175. ADD EAX,4
  2176. SUB ECX,1
  2177. @LOOP4:
  2178. MOVSS XMM0,DWORD PTR [EAX - 4]
  2179. ADDSS XMM0,DWORD PTR [EAX]
  2180. MOVSS DWORD PTR [EAX],XMM0
  2181. ADD EAX,4
  2182. SUB ECX,1
  2183. JNZ @LOOP4
  2184. @END:
  2185. {$elseif defined(TARGET_x64)}
  2186. CMP EDX,2 // if count < 2, exit
  2187. JL @END
  2188. MOV RAX,RCX
  2189. MOV ECX,EDX
  2190. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  2191. JL @SMALL
  2192. {--- align memory ---}
  2193. PXOR XMM4,XMM4
  2194. MOV R8D,EAX
  2195. AND R8D,15 // get aligned count
  2196. JZ @ENDALIGNING // already aligned
  2197. ADD R8D,-16
  2198. NEG R8D // get bytes to advance
  2199. JZ @ENDALIGNING // already aligned
  2200. MOV ECX,R8D
  2201. SAR ECX,2 // div with 4 to get cnt
  2202. SUB EDX,ECX
  2203. ADD RAX,4
  2204. DEC ECX
  2205. JZ @SETUPLAST // one element
  2206. @ALIGNINGLOOP:
  2207. MOVSS XMM0,DWORD PTR [RAX - 4]
  2208. ADDSS XMM0,DWORD PTR [RAX]
  2209. MOVSS DWORD PTR [RAX],XMM0
  2210. ADD RAX,4
  2211. DEC ECX
  2212. JNZ @ALIGNINGLOOP
  2213. @SETUPLAST:
  2214. MOVUPS XMM4,[RAX - 4]
  2215. PSLLDQ XMM4,12
  2216. PSRLDQ XMM4,12
  2217. @ENDALIGNING:
  2218. MOV ECX,EDX
  2219. SAR ECX,2
  2220. @LOOP:
  2221. MOVAPS XMM0,[RAX]
  2222. PXOR XMM5,XMM5
  2223. PCMPEQD XMM5,XMM0
  2224. PMOVMSKB R8D,XMM5
  2225. CMP R8D,$0000FFFF
  2226. JNE @NORMAL
  2227. PSHUFD XMM0,XMM4,0
  2228. JMP @SKIP
  2229. @NORMAL:
  2230. ADDPS XMM0,XMM4
  2231. MOVAPS XMM2,XMM0
  2232. PSLLDQ XMM2,4
  2233. ADDPS XMM0,XMM2
  2234. MOVAPS XMM2,XMM0
  2235. PSLLDQ XMM2,8
  2236. ADDPS XMM0,XMM2
  2237. MOVAPS XMM4,XMM0
  2238. PSRLDQ XMM4,12
  2239. @SKIP:
  2240. PREFETCHNTA [RAX + 32 * 2]
  2241. MOVAPS [RAX],XMM0
  2242. ADD RAX,16
  2243. SUB ECX,1
  2244. JNZ @LOOP
  2245. MOV ECX,EDX
  2246. AND ECX,3
  2247. JZ @END
  2248. @LOOP2:
  2249. MOVSS XMM0,DWORD PTR [RAX - 4]
  2250. ADDSS XMM0,DWORD PTR [RAX]
  2251. MOVSS DWORD PTR [RAX],XMM0
  2252. ADD RAX,4
  2253. DEC ECX
  2254. JNZ @LOOP2
  2255. JMP @END
  2256. @SMALL:
  2257. CMP ECX,8
  2258. JL @SMALL2
  2259. SAR ECX,2
  2260. PXOR XMM4,XMM4
  2261. @LOOP3:
  2262. MOVUPS XMM0,[RAX]
  2263. ADDPS XMM0,XMM4
  2264. MOVAPS XMM2,XMM0
  2265. PSLLDQ XMM2,4
  2266. ADDPS XMM0,XMM2
  2267. MOVAPS XMM2,XMM0
  2268. PSLLDQ XMM2,8
  2269. ADDPS XMM0,XMM2
  2270. MOVAPS XMM4,XMM0
  2271. PSRLDQ XMM4,12
  2272. MOVUPS [RAX],XMM0
  2273. ADD RAX,16
  2274. SUB EDX,4
  2275. SUB ECX,1
  2276. JNZ @LOOP3
  2277. CMP EDX, 0
  2278. JZ @END
  2279. MOV ECX,EDX
  2280. JMP @LOOP4
  2281. @SMALL2:
  2282. ADD RAX,4
  2283. DEC ECX
  2284. @LOOP4:
  2285. MOVSS XMM0,DWORD PTR [RAX - 4]
  2286. ADDSS XMM0,DWORD PTR [RAX]
  2287. MOVSS DWORD PTR [RAX],XMM0
  2288. ADD RAX,4
  2289. DEC ECX
  2290. JNZ @LOOP4
  2291. @END:
  2292. {$else}
  2293. {$error 'Missing target'}
  2294. {$ifend}
  2295. end;
  2296. procedure CumSum_SSE2_kadaif3(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  2297. asm
  2298. {$if defined(TARGET_x86)}
  2299. CMP EDX,2 // if count < 2, exit
  2300. JL @END
  2301. MOV ECX,EDX
  2302. CMP EDX,32 // if count < 32, avoid SSE2 overhead
  2303. JL @SMALL
  2304. {--- align memory ---}
  2305. PUSH EBX
  2306. PXOR XMM4,XMM4
  2307. MOV EBX,EAX
  2308. AND EBX,15 // get aligned count
  2309. JZ @ENDALIGNING // already aligned
  2310. ADD EBX,-16
  2311. NEG EBX // get bytes to advance
  2312. JZ @ENDALIGNING // already aligned
  2313. MOV ECX,EBX
  2314. SAR ECX,2 // div with 4 to get cnt
  2315. SUB EDX,ECX
  2316. ADD EAX,4
  2317. DEC ECX
  2318. JZ @SETUPLAST // one element (float) before aligned. skip it.
  2319. @ALIGNINGLOOP:
  2320. MOVSS XMM0,DWORD PTR [EAX - 4]
  2321. ADDSS XMM0,DWORD PTR [EAX]
  2322. MOVSS DWORD PTR [EAX],XMM0
  2323. ADD EAX,4
  2324. DEC ECX
  2325. JNZ @ALIGNINGLOOP
  2326. @SETUPLAST:
  2327. MOVUPS XMM4,[EAX - 4]
  2328. PSLLDQ XMM4,12
  2329. PSRLDQ XMM4,12
  2330. @ENDALIGNING:
  2331. POP EBX
  2332. PUSH EBX
  2333. MOV ECX,EDX
  2334. SAR ECX,2
  2335. @LOOP:
  2336. MOVAPS XMM0,[EAX]
  2337. PXOR XMM5,XMM5
  2338. PCMPEQD XMM5,XMM0
  2339. PMOVMSKB EBX,XMM5
  2340. CMP EBX,$0000FFFF
  2341. JNE @NORMAL
  2342. PSHUFD XMM0,XMM4,0
  2343. JMP @SKIP
  2344. @NORMAL:
  2345. ADDPS XMM0,XMM4
  2346. MOVAPS XMM2,XMM0
  2347. PSLLDQ XMM2,4
  2348. ADDPS XMM0,XMM2
  2349. MOVAPS XMM2,XMM0
  2350. PSLLDQ XMM2,8
  2351. ADDPS XMM0,XMM2
  2352. MOVAPS XMM4,XMM0
  2353. PSRLDQ XMM4,12
  2354. @SKIP:
  2355. PREFETCHNTA [EAX + 16 * 16 * 2]
  2356. MOVAPS [EAX],XMM0
  2357. ADD EAX,16
  2358. SUB ECX,1
  2359. JNZ @LOOP
  2360. POP EBX
  2361. MOV ECX,EDX
  2362. AND ECX,3
  2363. JZ @END
  2364. SUB EAX,4
  2365. MOVSS XMM0,DWORD PTR [EAX]
  2366. @LOOP2:
  2367. ADDSS XMM0,DWORD PTR [EAX + 4]
  2368. MOVSS DWORD PTR [EAX + 4],XMM0
  2369. ADD EAX,4
  2370. DEC ECX
  2371. JNZ @LOOP2
  2372. JMP @END
  2373. @SMALL:
  2374. MOVSS XMM0,DWORD PTR [EAX]
  2375. SUB ECX,1
  2376. @LOOP4:
  2377. ADDSS XMM0,DWORD PTR [EAX + 4]
  2378. MOVSS DWORD PTR [EAX + 4],XMM0
  2379. ADD EAX,4
  2380. SUB ECX,1
  2381. JNZ @LOOP4
  2382. @END:
  2383. {$elseif defined(TARGET_x64)}
  2384. CMP EDX,2 // if count < 2, exit
  2385. JL @END
  2386. MOV RAX,RCX
  2387. MOV ECX,EDX
  2388. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  2389. JL @SMALL
  2390. {--- align memory ---}
  2391. PXOR XMM4,XMM4
  2392. MOV R8D,EAX
  2393. AND R8D,15 // get aligned count
  2394. JZ @ENDALIGNING // already aligned
  2395. ADD R8D,-16
  2396. NEG R8D // get bytes to advance
  2397. JZ @ENDALIGNING // already aligned
  2398. MOV ECX,R8D
  2399. SAR ECX,2 // div with 4 to get cnt
  2400. SUB EDX,ECX
  2401. ADD RAX,4
  2402. DEC ECX
  2403. JZ @SETUPLAST // one element (float) before aligned. skip it.
  2404. @ALIGNINGLOOP:
  2405. MOVSS XMM0,DWORD PTR [RAX - 4]
  2406. ADDSS XMM0,DWORD PTR [RAX]
  2407. MOVSS DWORD PTR [RAX],XMM0
  2408. ADD RAX,4
  2409. DEC ECX
  2410. JNZ @ALIGNINGLOOP
  2411. @SETUPLAST:
  2412. MOVUPS XMM4,[RAX - 4]
  2413. PSLLDQ XMM4,12
  2414. PSRLDQ XMM4,12
  2415. @ENDALIGNING:
  2416. MOV ECX,EDX
  2417. SAR ECX,2
  2418. @LOOP:
  2419. MOVAPS XMM0,[RAX]
  2420. PXOR XMM5,XMM5
  2421. PCMPEQD XMM5,XMM0
  2422. PMOVMSKB R8D,XMM5
  2423. CMP R8D,$0000FFFF
  2424. JNE @NORMAL
  2425. PSHUFD XMM0,XMM4,0
  2426. JMP @SKIP
  2427. @NORMAL:
  2428. ADDPS XMM0,XMM4
  2429. MOVAPS XMM2,XMM0
  2430. PSLLDQ XMM2,4
  2431. ADDPS XMM0,XMM2
  2432. MOVAPS XMM2,XMM0
  2433. PSLLDQ XMM2,8
  2434. ADDPS XMM0,XMM2
  2435. MOVAPS XMM4,XMM0
  2436. PSRLDQ XMM4,12
  2437. @SKIP:
  2438. PREFETCHNTA [RAX + 32 * 2]
  2439. MOVAPS [RAX],XMM0
  2440. ADD RAX,16
  2441. SUB ECX,1
  2442. JNZ @LOOP
  2443. MOV ECX,EDX
  2444. AND ECX,3
  2445. JZ @END
  2446. SUB RAX,4 // result is in RAX - 4
  2447. MOVSS XMM0,DWORD PTR [RAX]
  2448. @LOOP2:
  2449. ADDSS XMM0,DWORD PTR [RAX + 4]
  2450. MOVSS DWORD PTR [RAX + 4],XMM0
  2451. ADD RAX,4
  2452. DEC ECX
  2453. JNZ @LOOP2
  2454. JMP @END
  2455. @SMALL:
  2456. MOVSS XMM0,DWORD PTR [RAX]
  2457. SUB ECX,1
  2458. @LOOP4:
  2459. ADDSS XMM0,DWORD PTR [RAX + 4]
  2460. MOVSS DWORD PTR [RAX + 4],XMM0
  2461. ADD RAX,4
  2462. SUB ECX,1
  2463. JNZ @LOOP4
  2464. @END:
  2465. {$else}
  2466. {$error 'Missing target'}
  2467. {$ifend}
  2468. end;
  2469. procedure CumSum_SSE2_kadaif4(Values: PSingleArray; Count: Integer); {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
  2470. asm
  2471. {$if defined(TARGET_x86)}
  2472. CMP EDX,2 // if count < 2, exit
  2473. JL @END
  2474. MOV ECX,EDX
  2475. CMP EDX,32 // if count < 32, avoid SSE2 overhead
  2476. JL @SMALL
  2477. SHR ECX,2
  2478. PUSH EBX
  2479. PXOR XMM4,XMM4
  2480. @LOOP:
  2481. MOVUPS XMM0,[EAX]
  2482. PXOR XMM5,XMM5
  2483. PCMPEQD XMM5,XMM0
  2484. PMOVMSKB EBX,XMM5
  2485. CMP EBX,$0000FFFF
  2486. JNE @NORMAL
  2487. PSHUFD XMM0,XMM4,0
  2488. JMP @SKIP
  2489. @NORMAL:
  2490. ADDPS XMM0,XMM4
  2491. MOVAPS XMM2,XMM0
  2492. PSLLDQ XMM2,4
  2493. ADDPS XMM0,XMM2
  2494. MOVAPS XMM2,XMM0
  2495. PSLLDQ XMM2,8
  2496. ADDPS XMM0,XMM2
  2497. MOVAPS XMM4,XMM0
  2498. PSRLDQ XMM4,12
  2499. @SKIP:
  2500. PREFETCHNTA [EAX + 16 * 16 * 2]
  2501. MOVUPS [EAX],XMM0
  2502. ADD EAX,16
  2503. SUB ECX,1
  2504. JNZ @LOOP
  2505. POP EBX
  2506. MOV ECX,EDX
  2507. AND ECX,3
  2508. JZ @END
  2509. SUB EAX,4 // result is in EAX-1
  2510. MOVSS XMM0,DWORD PTR [EAX]
  2511. JMP @LOOP4
  2512. @SMALL:
  2513. MOVSS XMM0,DWORD PTR [EAX]
  2514. SUB ECX,1
  2515. @LOOP4:
  2516. ADDSS XMM0,DWORD PTR [EAX + 4]
  2517. MOVSS DWORD PTR [EAX + 4],XMM0
  2518. ADD EAX,4
  2519. SUB ECX,1
  2520. JNZ @LOOP4
  2521. @END:
  2522. {$elseif defined(TARGET_x64)}
  2523. CMP EDX,2 // if count < 2, exit
  2524. JL @END
  2525. MOV RAX,RCX
  2526. MOV ECX,EDX
  2527. CMP ECX,32 // if count < 32, avoid SSE2 overhead
  2528. JL @SMALL
  2529. SHR ECX,2
  2530. PXOR XMM4,XMM4
  2531. @LOOP:
  2532. MOVUPS XMM0,[RAX]
  2533. PXOR XMM5,XMM5
  2534. PCMPEQD XMM5,XMM0
  2535. PMOVMSKB R8D,XMM5
  2536. CMP R8D,$0000FFFF
  2537. JNE @NORMAL
  2538. PSHUFD XMM0,XMM4,0
  2539. JMP @SKIP
  2540. @NORMAL:
  2541. ADDPS XMM0,XMM4
  2542. MOVAPS XMM2,XMM0
  2543. PSLLDQ XMM2,4
  2544. ADDPS XMM0,XMM2
  2545. MOVAPS XMM2,XMM0
  2546. PSLLDQ XMM2,8
  2547. ADDPS XMM0,XMM2
  2548. MOVAPS XMM4,XMM0
  2549. PSRLDQ XMM4,12
  2550. @SKIP:
  2551. PREFETCHNTA [RAX + 16 * 16 * 2]
  2552. MOVUPS [RAX],XMM0
  2553. ADD RAX,16
  2554. SUB ECX,1
  2555. JNZ @LOOP
  2556. MOV ECX,EDX
  2557. AND ECX,3
  2558. JZ @END
  2559. SUB RAX,4 // result is in EAX-1
  2560. MOVSS XMM0,DWORD PTR [RAX]
  2561. JMP @LOOP4
  2562. @SMALL:
  2563. MOVSS XMM0,DWORD PTR [RAX]
  2564. SUB ECX,1
  2565. @LOOP4:
  2566. ADDSS XMM0,DWORD PTR [RAX + 4]
  2567. MOVSS DWORD PTR [RAX + 4],XMM0
  2568. ADD RAX,4
  2569. SUB ECX,1
  2570. JNZ @LOOP4
  2571. @END:
  2572. {$else}
  2573. {$error 'Missing target'}
  2574. {$ifend}
  2575. end;
  2576. {$ifend (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  2577. //------------------------------------------------------------------------------
  2578. //
  2579. // Bindings
  2580. //
  2581. //------------------------------------------------------------------------------
  2582. procedure RegisterBindings;
  2583. begin
  2584. MathRegistry := NewRegistry('GR32_Math bindings');
  2585. MathRegistry.RegisterBinding(FID_CUMSUM, @@CumSum, 'CumSum');
  2586. MathRegistry.RegisterBinding(FID_FLOATMOD_F, @@FloatMod_F, 'FloatMod_F');
  2587. MathRegistry.RegisterBinding(FID_FLOATMOD_D, @@FloatMod_D, 'FloatMod_D');
  2588. MathRegistry.RegisterBinding(FID_FLOATREMAINDER_F, @@FloatRemainder_F, 'FloatRemainder_F');
  2589. MathRegistry.RegisterBinding(FID_FLOATREMAINDER_D, @@FloatRemainder_D, 'FloatRemainder_D');
  2590. MathRegistry.RegisterBinding(FID_FMOD_F, @@FMod_F, 'FMod_F');
  2591. MathRegistry.RegisterBinding(FID_FMOD_D, @@FMod_D, 'FMod_D');
  2592. // pure pascal
  2593. MathRegistry[@@CumSum].Add( @CumSum_Pas, [isPascal]).Name := 'CumSum_Pas';
  2594. MathRegistry[@@FloatMod_F].Add( @FloatMod_F_Pas, [isPascal]).Name := 'FloatMod_F_Pas';
  2595. MathRegistry[@@FloatMod_D].Add( @FloatMod_D_Pas, [isPascal]).Name := 'FloatMod_D_Pas';
  2596. MathRegistry[@@FloatRemainder_F].Add( @FloatRemainder_F_Pas, [isPascal]).Name := 'FloatRemainder_F_Pas';
  2597. MathRegistry[@@FloatRemainder_D].Add( @FloatRemainder_D_Pas, [isPascal]).Name := 'FloatRemainder_D_Pas';
  2598. MathRegistry[@@FMod_F].Add( @FMod_F_Pas, [isPascal]).Name := 'FMod_F_Pas';
  2599. MathRegistry[@@FMod_D].Add( @FMod_D_Pas, [isPascal]).Name := 'FMod_D_Pas';
  2600. {$if defined(BENCHMARK)}
  2601. MathRegistry[@@CumSum].Add( @CumSum_Pas_Simple, [isPascal]).Name := 'CumSum_Pas_Simple';
  2602. {$ifend}
  2603. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  2604. MathRegistry[@@CumSum].Add( @CumSum_SSE2_kadaif2, [isSSE2]).Name := 'CumSum_SSE2_kadaif2';
  2605. MathRegistry[@@CumSum].Add( @CumSum_SSE2_Simple, [isSSE2], BindingPriorityWorse).Name := 'CumSum_SSE2_Simple';
  2606. {$if defined(BENCHMARK)}
  2607. MathRegistry[@@CumSum].Add( @CumSum_SSE2, [isSSE2]).Name := 'CumSum_SSE2';
  2608. MathRegistry[@@CumSum].Add( @CumSum_SSE2_kadaif1, [isSSE2]).Name := 'CumSum_SSE2_kadaif1';
  2609. MathRegistry[@@CumSum].Add( @CumSum_SSE2_kadaif3, [isSSE2]).Name := 'CumSum_SSE2_kadaif3';
  2610. MathRegistry[@@CumSum].Add( @CumSum_SSE2_kadaif4, [isSSE2]).Name := 'CumSum_SSE2_kadaif4';
  2611. {$ifend}
  2612. MathRegistry[@@FloatMod_F].Add( @FloatMod_F_SSE41, [isSSE41]).Name := 'FloatMod_F_SSE41';
  2613. MathRegistry[@@FloatMod_D].Add( @FloatMod_D_SSE41, [isSSE41]).Name := 'FloatMod_D_SSE41';
  2614. MathRegistry[@@FloatRemainder_F].Add( @FloatRemainder_F_SSE41, [isSSE41]).Name := 'FloatRemainder_F_SSE41';
  2615. MathRegistry[@@FloatRemainder_D].Add( @FloatRemainder_D_SSE41, [isSSE41]).Name := 'FloatRemainder_D_SSE41';
  2616. MathRegistry[@@FMod_F].Add( @FMod_F_SSE2, [isSSE2]).Name := 'FMod_F_SSE2';
  2617. MathRegistry[@@FMod_F].Add( @FMod_F_SSE41, [isSSE41]).Name := 'FMod_F_SSE41';
  2618. MathRegistry[@@FMod_D].Add( @FMod_D_SSE2, [isSSE2]).Name := 'FMod_D_SSE2';
  2619. MathRegistry[@@FMod_D].Add( @FMod_D_SSE41, [isSSE41]).Name := 'FMod_D_SSE41';
  2620. // The regular CumSum SIMD 64-bit implementations are very slow on certain
  2621. // old CPUs (Sandy Bridge and presumably also Ivy Bridge) so we need to
  2622. // penalize them so they don't get selected by the rebind.
  2623. //
  2624. // - On Sandy Bridge, 64-bit, the Pure Pascal version is faster than the
  2625. // optimized SSE2 version.
  2626. //
  2627. // - On Sandy Bridge, 32-bit, the simple SSE2 version is faster than the
  2628. // optimized SSE2 version.
  2629. //
  2630. // We could detect Sandy- and Ivy Bridge by their model numbers (42 and 58)
  2631. // but instead we use the AVX2 feature flag since they were the last models
  2632. // without AVX2.
  2633. //
  2634. // Also, instead of altering the priority of the SIMD implementation we
  2635. // instead improve the priority of the replacement implementation.
  2636. if (not (isAVX2 in CPU.InstructionSupport)) then
  2637. MathRegistry[@@CumSum].FindImplementation(@CumSum_SSE2_Simple).Priority := BindingPriorityBetter;
  2638. {$ifend}
  2639. MathRegistry.RebindAll;
  2640. end;
  2641. //------------------------------------------------------------------------------
  2642. initialization
  2643. RegisterBindings;
  2644. end.