chacha-x86_64.pl 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005
  1. #! /usr/bin/env perl
  2. # Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License 2.0 (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. #
  9. # ====================================================================
  10. # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
  11. # project. The module is, however, dual licensed under OpenSSL and
  12. # CRYPTOGAMS licenses depending on where you obtain it. For further
  13. # details see http://www.openssl.org/~appro/cryptogams/.
  14. # ====================================================================
  15. #
  16. # November 2014
  17. #
  18. # ChaCha20 for x86_64.
  19. #
  20. # December 2016
  21. #
  22. # Add AVX512F code path.
  23. #
  24. # December 2017
  25. #
  26. # Add AVX512VL code path.
  27. #
  28. # Performance in cycles per byte out of large buffer.
  29. #
  30. # IALU/gcc 4.8(i) 1x/2xSSSE3(ii) 4xSSSE3 NxAVX(v)
  31. #
  32. # P4 9.48/+99% - -
  33. # Core2 7.83/+55% 7.90/5.76 4.35
  34. # Westmere 7.19/+50% 5.60/4.50 3.00
  35. # Sandy Bridge 8.31/+42% 5.45/4.00 2.72
  36. # Ivy Bridge 6.71/+46% 5.40/? 2.41
  37. # Haswell 5.92/+43% 5.20/3.45 2.42 1.23
  38. # Skylake[-X] 5.87/+39% 4.70/3.22 2.31 1.19[0.80(vi)]
  39. # Silvermont 12.0/+33% 7.75/6.90 7.03(iii)
  40. # Knights L 11.7/- ? 9.60(iii) 0.80
  41. # Goldmont 10.6/+17% 5.10/3.52 3.28
  42. # Sledgehammer 7.28/+52% - -
  43. # Bulldozer 9.66/+28% 9.85/5.35(iv) 3.06(iv)
  44. # Ryzen 5.96/+50% 5.19/3.00 2.40 2.09
  45. # VIA Nano 10.5/+46% 6.72/6.88 6.05
  46. #
  47. # (i) compared to older gcc 3.x one can observe >2x improvement on
  48. # most platforms;
  49. # (ii) 2xSSSE3 is code path optimized specifically for 128 bytes used
  50. # by chacha20_poly1305_tls_cipher, results are EVP-free;
  51. # (iii) this is not optimal result for Atom because of MSROM
  52. # limitations, SSE2 can do better, but gain is considered too
  53. # low to justify the [maintenance] effort;
  54. # (iv) Bulldozer actually executes 4xXOP code path that delivers 2.20
  55. # and 4.85 for 128-byte inputs;
  56. # (v) 8xAVX2, 8xAVX512VL or 16xAVX512F, whichever best applicable;
  57. # (vi) even though Skylake-X can execute AVX512F code and deliver 0.57
  58. # cpb in single thread, the corresponding capability is suppressed;
  59. $flavour = shift;
  60. $output = shift;
  61. if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
  62. $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
  63. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  64. ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
  65. ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
  66. die "can't locate x86_64-xlate.pl";
  67. if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
  68. =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
  69. $avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25);
  70. }
  71. if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
  72. `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) {
  73. $avx = ($1>=2.09) + ($1>=2.10) + ($1>=2.12);
  74. $avx += 1 if ($1==2.11 && $2>=8);
  75. }
  76. if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
  77. `ml64 2>&1` =~ /Version ([0-9]+)\./) {
  78. $avx = ($1>=10) + ($1>=11);
  79. }
  80. if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
  81. $avx = ($2>=3.0) + ($2>3.0);
  82. }
  83. open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
  84. *STDOUT=*OUT;
  85. # input parameter block
  86. ($out,$inp,$len,$key,$counter)=("%rdi","%rsi","%rdx","%rcx","%r8");
  87. $code.=<<___;
  88. .text
  89. .extern OPENSSL_ia32cap_P
  90. .align 64
  91. .Lzero:
  92. .long 0,0,0,0
  93. .Lone:
  94. .long 1,0,0,0
  95. .Linc:
  96. .long 0,1,2,3
  97. .Lfour:
  98. .long 4,4,4,4
  99. .Lincy:
  100. .long 0,2,4,6,1,3,5,7
  101. .Leight:
  102. .long 8,8,8,8,8,8,8,8
  103. .Lrot16:
  104. .byte 0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd
  105. .Lrot24:
  106. .byte 0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe
  107. .Ltwoy:
  108. .long 2,0,0,0, 2,0,0,0
  109. .align 64
  110. .Lzeroz:
  111. .long 0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0
  112. .Lfourz:
  113. .long 4,0,0,0, 4,0,0,0, 4,0,0,0, 4,0,0,0
  114. .Lincz:
  115. .long 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  116. .Lsixteen:
  117. .long 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16
  118. .Lsigma:
  119. .asciz "expand 32-byte k"
  120. .asciz "ChaCha20 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
  121. ___
  122. sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
  123. { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
  124. my $arg = pop;
  125. $arg = "\$$arg" if ($arg*1 eq $arg);
  126. $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
  127. }
  128. @x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),
  129. "%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
  130. @t=("%esi","%edi");
  131. sub ROUND { # critical path is 24 cycles per round
  132. my ($a0,$b0,$c0,$d0)=@_;
  133. my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
  134. my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
  135. my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
  136. my ($xc,$xc_)=map("\"$_\"",@t);
  137. my @x=map("\"$_\"",@x);
  138. # Consider order in which variables are addressed by their
  139. # index:
  140. #
  141. # a b c d
  142. #
  143. # 0 4 8 12 < even round
  144. # 1 5 9 13
  145. # 2 6 10 14
  146. # 3 7 11 15
  147. # 0 5 10 15 < odd round
  148. # 1 6 11 12
  149. # 2 7 8 13
  150. # 3 4 9 14
  151. #
  152. # 'a', 'b' and 'd's are permanently allocated in registers,
  153. # @x[0..7,12..15], while 'c's are maintained in memory. If
  154. # you observe 'c' column, you'll notice that pair of 'c's is
  155. # invariant between rounds. This means that we have to reload
  156. # them once per round, in the middle. This is why you'll see
  157. # bunch of 'c' stores and loads in the middle, but none in
  158. # the beginning or end.
  159. # Normally instructions would be interleaved to favour in-order
  160. # execution. Generally out-of-order cores manage it gracefully,
  161. # but not this time for some reason. As in-order execution
  162. # cores are dying breed, old Atom is the only one around,
  163. # instructions are left uninterleaved. Besides, Atom is better
  164. # off executing 1xSSSE3 code anyway...
  165. (
  166. "&add (@x[$a0],@x[$b0])", # Q1
  167. "&xor (@x[$d0],@x[$a0])",
  168. "&rol (@x[$d0],16)",
  169. "&add (@x[$a1],@x[$b1])", # Q2
  170. "&xor (@x[$d1],@x[$a1])",
  171. "&rol (@x[$d1],16)",
  172. "&add ($xc,@x[$d0])",
  173. "&xor (@x[$b0],$xc)",
  174. "&rol (@x[$b0],12)",
  175. "&add ($xc_,@x[$d1])",
  176. "&xor (@x[$b1],$xc_)",
  177. "&rol (@x[$b1],12)",
  178. "&add (@x[$a0],@x[$b0])",
  179. "&xor (@x[$d0],@x[$a0])",
  180. "&rol (@x[$d0],8)",
  181. "&add (@x[$a1],@x[$b1])",
  182. "&xor (@x[$d1],@x[$a1])",
  183. "&rol (@x[$d1],8)",
  184. "&add ($xc,@x[$d0])",
  185. "&xor (@x[$b0],$xc)",
  186. "&rol (@x[$b0],7)",
  187. "&add ($xc_,@x[$d1])",
  188. "&xor (@x[$b1],$xc_)",
  189. "&rol (@x[$b1],7)",
  190. "&mov (\"4*$c0(%rsp)\",$xc)", # reload pair of 'c's
  191. "&mov (\"4*$c1(%rsp)\",$xc_)",
  192. "&mov ($xc,\"4*$c2(%rsp)\")",
  193. "&mov ($xc_,\"4*$c3(%rsp)\")",
  194. "&add (@x[$a2],@x[$b2])", # Q3
  195. "&xor (@x[$d2],@x[$a2])",
  196. "&rol (@x[$d2],16)",
  197. "&add (@x[$a3],@x[$b3])", # Q4
  198. "&xor (@x[$d3],@x[$a3])",
  199. "&rol (@x[$d3],16)",
  200. "&add ($xc,@x[$d2])",
  201. "&xor (@x[$b2],$xc)",
  202. "&rol (@x[$b2],12)",
  203. "&add ($xc_,@x[$d3])",
  204. "&xor (@x[$b3],$xc_)",
  205. "&rol (@x[$b3],12)",
  206. "&add (@x[$a2],@x[$b2])",
  207. "&xor (@x[$d2],@x[$a2])",
  208. "&rol (@x[$d2],8)",
  209. "&add (@x[$a3],@x[$b3])",
  210. "&xor (@x[$d3],@x[$a3])",
  211. "&rol (@x[$d3],8)",
  212. "&add ($xc,@x[$d2])",
  213. "&xor (@x[$b2],$xc)",
  214. "&rol (@x[$b2],7)",
  215. "&add ($xc_,@x[$d3])",
  216. "&xor (@x[$b3],$xc_)",
  217. "&rol (@x[$b3],7)"
  218. );
  219. }
  220. ########################################################################
  221. # Generic code path that handles all lengths on pre-SSSE3 processors.
  222. $code.=<<___;
  223. .globl ChaCha20_ctr32
  224. .type ChaCha20_ctr32,\@function,5
  225. .align 64
  226. ChaCha20_ctr32:
  227. .cfi_startproc
  228. cmp \$0,$len
  229. je .Lno_data
  230. mov OPENSSL_ia32cap_P+4(%rip),%r10
  231. ___
  232. $code.=<<___ if ($avx>2);
  233. bt \$48,%r10 # check for AVX512F
  234. jc .LChaCha20_avx512
  235. test %r10,%r10 # check for AVX512VL
  236. js .LChaCha20_avx512vl
  237. ___
  238. $code.=<<___;
  239. test \$`1<<(41-32)`,%r10d
  240. jnz .LChaCha20_ssse3
  241. push %rbx
  242. .cfi_push %rbx
  243. push %rbp
  244. .cfi_push %rbp
  245. push %r12
  246. .cfi_push %r12
  247. push %r13
  248. .cfi_push %r13
  249. push %r14
  250. .cfi_push %r14
  251. push %r15
  252. .cfi_push %r15
  253. sub \$64+24,%rsp
  254. .cfi_adjust_cfa_offset 64+24
  255. .Lctr32_body:
  256. #movdqa .Lsigma(%rip),%xmm0
  257. movdqu ($key),%xmm1
  258. movdqu 16($key),%xmm2
  259. movdqu ($counter),%xmm3
  260. movdqa .Lone(%rip),%xmm4
  261. #movdqa %xmm0,4*0(%rsp) # key[0]
  262. movdqa %xmm1,4*4(%rsp) # key[1]
  263. movdqa %xmm2,4*8(%rsp) # key[2]
  264. movdqa %xmm3,4*12(%rsp) # key[3]
  265. mov $len,%rbp # reassign $len
  266. jmp .Loop_outer
  267. .align 32
  268. .Loop_outer:
  269. mov \$0x61707865,@x[0] # 'expa'
  270. mov \$0x3320646e,@x[1] # 'nd 3'
  271. mov \$0x79622d32,@x[2] # '2-by'
  272. mov \$0x6b206574,@x[3] # 'te k'
  273. mov 4*4(%rsp),@x[4]
  274. mov 4*5(%rsp),@x[5]
  275. mov 4*6(%rsp),@x[6]
  276. mov 4*7(%rsp),@x[7]
  277. movd %xmm3,@x[12]
  278. mov 4*13(%rsp),@x[13]
  279. mov 4*14(%rsp),@x[14]
  280. mov 4*15(%rsp),@x[15]
  281. mov %rbp,64+0(%rsp) # save len
  282. mov \$10,%ebp
  283. mov $inp,64+8(%rsp) # save inp
  284. movq %xmm2,%rsi # "@x[8]"
  285. mov $out,64+16(%rsp) # save out
  286. mov %rsi,%rdi
  287. shr \$32,%rdi # "@x[9]"
  288. jmp .Loop
  289. .align 32
  290. .Loop:
  291. ___
  292. foreach (&ROUND (0, 4, 8,12)) { eval; }
  293. foreach (&ROUND (0, 5,10,15)) { eval; }
  294. &dec ("%ebp");
  295. &jnz (".Loop");
  296. $code.=<<___;
  297. mov @t[1],4*9(%rsp) # modulo-scheduled
  298. mov @t[0],4*8(%rsp)
  299. mov 64(%rsp),%rbp # load len
  300. movdqa %xmm2,%xmm1
  301. mov 64+8(%rsp),$inp # load inp
  302. paddd %xmm4,%xmm3 # increment counter
  303. mov 64+16(%rsp),$out # load out
  304. add \$0x61707865,@x[0] # 'expa'
  305. add \$0x3320646e,@x[1] # 'nd 3'
  306. add \$0x79622d32,@x[2] # '2-by'
  307. add \$0x6b206574,@x[3] # 'te k'
  308. add 4*4(%rsp),@x[4]
  309. add 4*5(%rsp),@x[5]
  310. add 4*6(%rsp),@x[6]
  311. add 4*7(%rsp),@x[7]
  312. add 4*12(%rsp),@x[12]
  313. add 4*13(%rsp),@x[13]
  314. add 4*14(%rsp),@x[14]
  315. add 4*15(%rsp),@x[15]
  316. paddd 4*8(%rsp),%xmm1
  317. cmp \$64,%rbp
  318. jb .Ltail
  319. xor 4*0($inp),@x[0] # xor with input
  320. xor 4*1($inp),@x[1]
  321. xor 4*2($inp),@x[2]
  322. xor 4*3($inp),@x[3]
  323. xor 4*4($inp),@x[4]
  324. xor 4*5($inp),@x[5]
  325. xor 4*6($inp),@x[6]
  326. xor 4*7($inp),@x[7]
  327. movdqu 4*8($inp),%xmm0
  328. xor 4*12($inp),@x[12]
  329. xor 4*13($inp),@x[13]
  330. xor 4*14($inp),@x[14]
  331. xor 4*15($inp),@x[15]
  332. lea 4*16($inp),$inp # inp+=64
  333. pxor %xmm1,%xmm0
  334. movdqa %xmm2,4*8(%rsp)
  335. movd %xmm3,4*12(%rsp)
  336. mov @x[0],4*0($out) # write output
  337. mov @x[1],4*1($out)
  338. mov @x[2],4*2($out)
  339. mov @x[3],4*3($out)
  340. mov @x[4],4*4($out)
  341. mov @x[5],4*5($out)
  342. mov @x[6],4*6($out)
  343. mov @x[7],4*7($out)
  344. movdqu %xmm0,4*8($out)
  345. mov @x[12],4*12($out)
  346. mov @x[13],4*13($out)
  347. mov @x[14],4*14($out)
  348. mov @x[15],4*15($out)
  349. lea 4*16($out),$out # out+=64
  350. sub \$64,%rbp
  351. jnz .Loop_outer
  352. jmp .Ldone
  353. .align 16
  354. .Ltail:
  355. mov @x[0],4*0(%rsp)
  356. mov @x[1],4*1(%rsp)
  357. xor %rbx,%rbx
  358. mov @x[2],4*2(%rsp)
  359. mov @x[3],4*3(%rsp)
  360. mov @x[4],4*4(%rsp)
  361. mov @x[5],4*5(%rsp)
  362. mov @x[6],4*6(%rsp)
  363. mov @x[7],4*7(%rsp)
  364. movdqa %xmm1,4*8(%rsp)
  365. mov @x[12],4*12(%rsp)
  366. mov @x[13],4*13(%rsp)
  367. mov @x[14],4*14(%rsp)
  368. mov @x[15],4*15(%rsp)
  369. .Loop_tail:
  370. movzb ($inp,%rbx),%eax
  371. movzb (%rsp,%rbx),%edx
  372. lea 1(%rbx),%rbx
  373. xor %edx,%eax
  374. mov %al,-1($out,%rbx)
  375. dec %rbp
  376. jnz .Loop_tail
  377. .Ldone:
  378. lea 64+24+48(%rsp),%rsi
  379. .cfi_def_cfa %rsi,8
  380. mov -48(%rsi),%r15
  381. .cfi_restore %r15
  382. mov -40(%rsi),%r14
  383. .cfi_restore %r14
  384. mov -32(%rsi),%r13
  385. .cfi_restore %r13
  386. mov -24(%rsi),%r12
  387. .cfi_restore %r12
  388. mov -16(%rsi),%rbp
  389. .cfi_restore %rbp
  390. mov -8(%rsi),%rbx
  391. .cfi_restore %rbx
  392. lea (%rsi),%rsp
  393. .cfi_def_cfa_register %rsp
  394. .Lno_data:
  395. ret
  396. .cfi_endproc
  397. .size ChaCha20_ctr32,.-ChaCha20_ctr32
  398. ___
  399. ########################################################################
  400. # SSSE3 code path that handles shorter lengths
  401. {
  402. my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(0..7));
  403. sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
  404. &paddd ($a,$b);
  405. &pxor ($d,$a);
  406. &pshufb ($d,$rot16);
  407. &paddd ($c,$d);
  408. &pxor ($b,$c);
  409. &movdqa ($t,$b);
  410. &psrld ($b,20);
  411. &pslld ($t,12);
  412. &por ($b,$t);
  413. &paddd ($a,$b);
  414. &pxor ($d,$a);
  415. &pshufb ($d,$rot24);
  416. &paddd ($c,$d);
  417. &pxor ($b,$c);
  418. &movdqa ($t,$b);
  419. &psrld ($b,25);
  420. &pslld ($t,7);
  421. &por ($b,$t);
  422. }
  423. my $xframe = $win64 ? 32+8 : 8;
  424. $code.=<<___;
  425. .type ChaCha20_ssse3,\@function,5
  426. .align 32
  427. ChaCha20_ssse3:
  428. .cfi_startproc
  429. .LChaCha20_ssse3:
  430. mov %rsp,%r9 # frame pointer
  431. .cfi_def_cfa_register %r9
  432. ___
  433. $code.=<<___ if ($avx);
  434. test \$`1<<(43-32)`,%r10d
  435. jnz .LChaCha20_4xop # XOP is fastest even if we use 1/4
  436. ___
  437. $code.=<<___;
  438. cmp \$128,$len # we might throw away some data,
  439. je .LChaCha20_128
  440. ja .LChaCha20_4x # but overall it won't be slower
  441. .Ldo_sse3_after_all:
  442. sub \$64+$xframe,%rsp
  443. ___
  444. $code.=<<___ if ($win64);
  445. movaps %xmm6,-0x28(%r9)
  446. movaps %xmm7,-0x18(%r9)
  447. .Lssse3_body:
  448. ___
  449. $code.=<<___;
  450. movdqa .Lsigma(%rip),$a
  451. movdqu ($key),$b
  452. movdqu 16($key),$c
  453. movdqu ($counter),$d
  454. movdqa .Lrot16(%rip),$rot16
  455. movdqa .Lrot24(%rip),$rot24
  456. movdqa $a,0x00(%rsp)
  457. movdqa $b,0x10(%rsp)
  458. movdqa $c,0x20(%rsp)
  459. movdqa $d,0x30(%rsp)
  460. mov \$10,$counter # reuse $counter
  461. jmp .Loop_ssse3
  462. .align 32
  463. .Loop_outer_ssse3:
  464. movdqa .Lone(%rip),$d
  465. movdqa 0x00(%rsp),$a
  466. movdqa 0x10(%rsp),$b
  467. movdqa 0x20(%rsp),$c
  468. paddd 0x30(%rsp),$d
  469. mov \$10,$counter
  470. movdqa $d,0x30(%rsp)
  471. jmp .Loop_ssse3
  472. .align 32
  473. .Loop_ssse3:
  474. ___
  475. &SSSE3ROUND();
  476. &pshufd ($c,$c,0b01001110);
  477. &pshufd ($b,$b,0b00111001);
  478. &pshufd ($d,$d,0b10010011);
  479. &nop ();
  480. &SSSE3ROUND();
  481. &pshufd ($c,$c,0b01001110);
  482. &pshufd ($b,$b,0b10010011);
  483. &pshufd ($d,$d,0b00111001);
  484. &dec ($counter);
  485. &jnz (".Loop_ssse3");
  486. $code.=<<___;
  487. paddd 0x00(%rsp),$a
  488. paddd 0x10(%rsp),$b
  489. paddd 0x20(%rsp),$c
  490. paddd 0x30(%rsp),$d
  491. cmp \$64,$len
  492. jb .Ltail_ssse3
  493. movdqu 0x00($inp),$t
  494. movdqu 0x10($inp),$t1
  495. pxor $t,$a # xor with input
  496. movdqu 0x20($inp),$t
  497. pxor $t1,$b
  498. movdqu 0x30($inp),$t1
  499. lea 0x40($inp),$inp # inp+=64
  500. pxor $t,$c
  501. pxor $t1,$d
  502. movdqu $a,0x00($out) # write output
  503. movdqu $b,0x10($out)
  504. movdqu $c,0x20($out)
  505. movdqu $d,0x30($out)
  506. lea 0x40($out),$out # out+=64
  507. sub \$64,$len
  508. jnz .Loop_outer_ssse3
  509. jmp .Ldone_ssse3
  510. .align 16
  511. .Ltail_ssse3:
  512. movdqa $a,0x00(%rsp)
  513. movdqa $b,0x10(%rsp)
  514. movdqa $c,0x20(%rsp)
  515. movdqa $d,0x30(%rsp)
  516. xor $counter,$counter
  517. .Loop_tail_ssse3:
  518. movzb ($inp,$counter),%eax
  519. movzb (%rsp,$counter),%ecx
  520. lea 1($counter),$counter
  521. xor %ecx,%eax
  522. mov %al,-1($out,$counter)
  523. dec $len
  524. jnz .Loop_tail_ssse3
  525. .Ldone_ssse3:
  526. ___
  527. $code.=<<___ if ($win64);
  528. movaps -0x28(%r9),%xmm6
  529. movaps -0x18(%r9),%xmm7
  530. ___
  531. $code.=<<___;
  532. lea (%r9),%rsp
  533. .cfi_def_cfa_register %rsp
  534. .Lssse3_epilogue:
  535. ret
  536. .cfi_endproc
  537. .size ChaCha20_ssse3,.-ChaCha20_ssse3
  538. ___
  539. }
  540. ########################################################################
  541. # SSSE3 code path that handles 128-byte inputs
  542. {
  543. my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(8,9,2..7));
  544. my ($a1,$b1,$c1,$d1)=map("%xmm$_",(10,11,0,1));
  545. sub SSSE3ROUND_2x {
  546. &paddd ($a,$b);
  547. &pxor ($d,$a);
  548. &paddd ($a1,$b1);
  549. &pxor ($d1,$a1);
  550. &pshufb ($d,$rot16);
  551. &pshufb($d1,$rot16);
  552. &paddd ($c,$d);
  553. &paddd ($c1,$d1);
  554. &pxor ($b,$c);
  555. &pxor ($b1,$c1);
  556. &movdqa ($t,$b);
  557. &psrld ($b,20);
  558. &movdqa($t1,$b1);
  559. &pslld ($t,12);
  560. &psrld ($b1,20);
  561. &por ($b,$t);
  562. &pslld ($t1,12);
  563. &por ($b1,$t1);
  564. &paddd ($a,$b);
  565. &pxor ($d,$a);
  566. &paddd ($a1,$b1);
  567. &pxor ($d1,$a1);
  568. &pshufb ($d,$rot24);
  569. &pshufb($d1,$rot24);
  570. &paddd ($c,$d);
  571. &paddd ($c1,$d1);
  572. &pxor ($b,$c);
  573. &pxor ($b1,$c1);
  574. &movdqa ($t,$b);
  575. &psrld ($b,25);
  576. &movdqa($t1,$b1);
  577. &pslld ($t,7);
  578. &psrld ($b1,25);
  579. &por ($b,$t);
  580. &pslld ($t1,7);
  581. &por ($b1,$t1);
  582. }
  583. my $xframe = $win64 ? 0x68 : 8;
  584. $code.=<<___;
  585. .type ChaCha20_128,\@function,5
  586. .align 32
  587. ChaCha20_128:
  588. .cfi_startproc
  589. .LChaCha20_128:
  590. mov %rsp,%r9 # frame pointer
  591. .cfi_def_cfa_register %r9
  592. sub \$64+$xframe,%rsp
  593. ___
  594. $code.=<<___ if ($win64);
  595. movaps %xmm6,-0x68(%r9)
  596. movaps %xmm7,-0x58(%r9)
  597. movaps %xmm8,-0x48(%r9)
  598. movaps %xmm9,-0x38(%r9)
  599. movaps %xmm10,-0x28(%r9)
  600. movaps %xmm11,-0x18(%r9)
  601. .L128_body:
  602. ___
  603. $code.=<<___;
  604. movdqa .Lsigma(%rip),$a
  605. movdqu ($key),$b
  606. movdqu 16($key),$c
  607. movdqu ($counter),$d
  608. movdqa .Lone(%rip),$d1
  609. movdqa .Lrot16(%rip),$rot16
  610. movdqa .Lrot24(%rip),$rot24
  611. movdqa $a,$a1
  612. movdqa $a,0x00(%rsp)
  613. movdqa $b,$b1
  614. movdqa $b,0x10(%rsp)
  615. movdqa $c,$c1
  616. movdqa $c,0x20(%rsp)
  617. paddd $d,$d1
  618. movdqa $d,0x30(%rsp)
  619. mov \$10,$counter # reuse $counter
  620. jmp .Loop_128
  621. .align 32
  622. .Loop_128:
  623. ___
  624. &SSSE3ROUND_2x();
  625. &pshufd ($c,$c,0b01001110);
  626. &pshufd ($b,$b,0b00111001);
  627. &pshufd ($d,$d,0b10010011);
  628. &pshufd ($c1,$c1,0b01001110);
  629. &pshufd ($b1,$b1,0b00111001);
  630. &pshufd ($d1,$d1,0b10010011);
  631. &SSSE3ROUND_2x();
  632. &pshufd ($c,$c,0b01001110);
  633. &pshufd ($b,$b,0b10010011);
  634. &pshufd ($d,$d,0b00111001);
  635. &pshufd ($c1,$c1,0b01001110);
  636. &pshufd ($b1,$b1,0b10010011);
  637. &pshufd ($d1,$d1,0b00111001);
  638. &dec ($counter);
  639. &jnz (".Loop_128");
  640. $code.=<<___;
  641. paddd 0x00(%rsp),$a
  642. paddd 0x10(%rsp),$b
  643. paddd 0x20(%rsp),$c
  644. paddd 0x30(%rsp),$d
  645. paddd .Lone(%rip),$d1
  646. paddd 0x00(%rsp),$a1
  647. paddd 0x10(%rsp),$b1
  648. paddd 0x20(%rsp),$c1
  649. paddd 0x30(%rsp),$d1
  650. movdqu 0x00($inp),$t
  651. movdqu 0x10($inp),$t1
  652. pxor $t,$a # xor with input
  653. movdqu 0x20($inp),$t
  654. pxor $t1,$b
  655. movdqu 0x30($inp),$t1
  656. pxor $t,$c
  657. movdqu 0x40($inp),$t
  658. pxor $t1,$d
  659. movdqu 0x50($inp),$t1
  660. pxor $t,$a1
  661. movdqu 0x60($inp),$t
  662. pxor $t1,$b1
  663. movdqu 0x70($inp),$t1
  664. pxor $t,$c1
  665. pxor $t1,$d1
  666. movdqu $a,0x00($out) # write output
  667. movdqu $b,0x10($out)
  668. movdqu $c,0x20($out)
  669. movdqu $d,0x30($out)
  670. movdqu $a1,0x40($out)
  671. movdqu $b1,0x50($out)
  672. movdqu $c1,0x60($out)
  673. movdqu $d1,0x70($out)
  674. ___
  675. $code.=<<___ if ($win64);
  676. movaps -0x68(%r9),%xmm6
  677. movaps -0x58(%r9),%xmm7
  678. movaps -0x48(%r9),%xmm8
  679. movaps -0x38(%r9),%xmm9
  680. movaps -0x28(%r9),%xmm10
  681. movaps -0x18(%r9),%xmm11
  682. ___
  683. $code.=<<___;
  684. lea (%r9),%rsp
  685. .cfi_def_cfa_register %rsp
  686. .L128_epilogue:
  687. ret
  688. .cfi_endproc
  689. .size ChaCha20_128,.-ChaCha20_128
  690. ___
  691. }
  692. ########################################################################
  693. # SSSE3 code path that handles longer messages.
  694. {
  695. # assign variables to favor Atom front-end
  696. my ($xd0,$xd1,$xd2,$xd3, $xt0,$xt1,$xt2,$xt3,
  697. $xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3)=map("%xmm$_",(0..15));
  698. my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  699. "%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
  700. sub SSSE3_lane_ROUND {
  701. my ($a0,$b0,$c0,$d0)=@_;
  702. my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
  703. my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
  704. my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
  705. my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
  706. my @x=map("\"$_\"",@xx);
  707. # Consider order in which variables are addressed by their
  708. # index:
  709. #
  710. # a b c d
  711. #
  712. # 0 4 8 12 < even round
  713. # 1 5 9 13
  714. # 2 6 10 14
  715. # 3 7 11 15
  716. # 0 5 10 15 < odd round
  717. # 1 6 11 12
  718. # 2 7 8 13
  719. # 3 4 9 14
  720. #
  721. # 'a', 'b' and 'd's are permanently allocated in registers,
  722. # @x[0..7,12..15], while 'c's are maintained in memory. If
  723. # you observe 'c' column, you'll notice that pair of 'c's is
  724. # invariant between rounds. This means that we have to reload
  725. # them once per round, in the middle. This is why you'll see
  726. # bunch of 'c' stores and loads in the middle, but none in
  727. # the beginning or end.
  728. (
  729. "&paddd (@x[$a0],@x[$b0])", # Q1
  730. "&paddd (@x[$a1],@x[$b1])", # Q2
  731. "&pxor (@x[$d0],@x[$a0])",
  732. "&pxor (@x[$d1],@x[$a1])",
  733. "&pshufb (@x[$d0],$t1)",
  734. "&pshufb (@x[$d1],$t1)",
  735. "&paddd ($xc,@x[$d0])",
  736. "&paddd ($xc_,@x[$d1])",
  737. "&pxor (@x[$b0],$xc)",
  738. "&pxor (@x[$b1],$xc_)",
  739. "&movdqa ($t0,@x[$b0])",
  740. "&pslld (@x[$b0],12)",
  741. "&psrld ($t0,20)",
  742. "&movdqa ($t1,@x[$b1])",
  743. "&pslld (@x[$b1],12)",
  744. "&por (@x[$b0],$t0)",
  745. "&psrld ($t1,20)",
  746. "&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
  747. "&por (@x[$b1],$t1)",
  748. "&paddd (@x[$a0],@x[$b0])",
  749. "&paddd (@x[$a1],@x[$b1])",
  750. "&pxor (@x[$d0],@x[$a0])",
  751. "&pxor (@x[$d1],@x[$a1])",
  752. "&pshufb (@x[$d0],$t0)",
  753. "&pshufb (@x[$d1],$t0)",
  754. "&paddd ($xc,@x[$d0])",
  755. "&paddd ($xc_,@x[$d1])",
  756. "&pxor (@x[$b0],$xc)",
  757. "&pxor (@x[$b1],$xc_)",
  758. "&movdqa ($t1,@x[$b0])",
  759. "&pslld (@x[$b0],7)",
  760. "&psrld ($t1,25)",
  761. "&movdqa ($t0,@x[$b1])",
  762. "&pslld (@x[$b1],7)",
  763. "&por (@x[$b0],$t1)",
  764. "&psrld ($t0,25)",
  765. "&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
  766. "&por (@x[$b1],$t0)",
  767. "&movdqa (\"`16*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
  768. "&movdqa (\"`16*($c1-8)`(%rsp)\",$xc_)",
  769. "&movdqa ($xc,\"`16*($c2-8)`(%rsp)\")",
  770. "&movdqa ($xc_,\"`16*($c3-8)`(%rsp)\")",
  771. "&paddd (@x[$a2],@x[$b2])", # Q3
  772. "&paddd (@x[$a3],@x[$b3])", # Q4
  773. "&pxor (@x[$d2],@x[$a2])",
  774. "&pxor (@x[$d3],@x[$a3])",
  775. "&pshufb (@x[$d2],$t1)",
  776. "&pshufb (@x[$d3],$t1)",
  777. "&paddd ($xc,@x[$d2])",
  778. "&paddd ($xc_,@x[$d3])",
  779. "&pxor (@x[$b2],$xc)",
  780. "&pxor (@x[$b3],$xc_)",
  781. "&movdqa ($t0,@x[$b2])",
  782. "&pslld (@x[$b2],12)",
  783. "&psrld ($t0,20)",
  784. "&movdqa ($t1,@x[$b3])",
  785. "&pslld (@x[$b3],12)",
  786. "&por (@x[$b2],$t0)",
  787. "&psrld ($t1,20)",
  788. "&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
  789. "&por (@x[$b3],$t1)",
  790. "&paddd (@x[$a2],@x[$b2])",
  791. "&paddd (@x[$a3],@x[$b3])",
  792. "&pxor (@x[$d2],@x[$a2])",
  793. "&pxor (@x[$d3],@x[$a3])",
  794. "&pshufb (@x[$d2],$t0)",
  795. "&pshufb (@x[$d3],$t0)",
  796. "&paddd ($xc,@x[$d2])",
  797. "&paddd ($xc_,@x[$d3])",
  798. "&pxor (@x[$b2],$xc)",
  799. "&pxor (@x[$b3],$xc_)",
  800. "&movdqa ($t1,@x[$b2])",
  801. "&pslld (@x[$b2],7)",
  802. "&psrld ($t1,25)",
  803. "&movdqa ($t0,@x[$b3])",
  804. "&pslld (@x[$b3],7)",
  805. "&por (@x[$b2],$t1)",
  806. "&psrld ($t0,25)",
  807. "&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
  808. "&por (@x[$b3],$t0)"
  809. );
  810. }
  811. my $xframe = $win64 ? 0xa8 : 8;
  812. $code.=<<___;
  813. .type ChaCha20_4x,\@function,5
  814. .align 32
  815. ChaCha20_4x:
  816. .cfi_startproc
  817. .LChaCha20_4x:
  818. mov %rsp,%r9 # frame pointer
  819. .cfi_def_cfa_register %r9
  820. mov %r10,%r11
  821. ___
  822. $code.=<<___ if ($avx>1);
  823. shr \$32,%r10 # OPENSSL_ia32cap_P+8
  824. test \$`1<<5`,%r10 # test AVX2
  825. jnz .LChaCha20_8x
  826. ___
  827. $code.=<<___;
  828. cmp \$192,$len
  829. ja .Lproceed4x
  830. and \$`1<<26|1<<22`,%r11 # isolate XSAVE+MOVBE
  831. cmp \$`1<<22`,%r11 # check for MOVBE without XSAVE
  832. je .Ldo_sse3_after_all # to detect Atom
  833. .Lproceed4x:
  834. sub \$0x140+$xframe,%rsp
  835. ___
  836. ################ stack layout
  837. # +0x00 SIMD equivalent of @x[8-12]
  838. # ...
  839. # +0x40 constant copy of key[0-2] smashed by lanes
  840. # ...
  841. # +0x100 SIMD counters (with nonce smashed by lanes)
  842. # ...
  843. # +0x140
  844. $code.=<<___ if ($win64);
  845. movaps %xmm6,-0xa8(%r9)
  846. movaps %xmm7,-0x98(%r9)
  847. movaps %xmm8,-0x88(%r9)
  848. movaps %xmm9,-0x78(%r9)
  849. movaps %xmm10,-0x68(%r9)
  850. movaps %xmm11,-0x58(%r9)
  851. movaps %xmm12,-0x48(%r9)
  852. movaps %xmm13,-0x38(%r9)
  853. movaps %xmm14,-0x28(%r9)
  854. movaps %xmm15,-0x18(%r9)
  855. .L4x_body:
  856. ___
  857. $code.=<<___;
  858. movdqa .Lsigma(%rip),$xa3 # key[0]
  859. movdqu ($key),$xb3 # key[1]
  860. movdqu 16($key),$xt3 # key[2]
  861. movdqu ($counter),$xd3 # key[3]
  862. lea 0x100(%rsp),%rcx # size optimization
  863. lea .Lrot16(%rip),%r10
  864. lea .Lrot24(%rip),%r11
  865. pshufd \$0x00,$xa3,$xa0 # smash key by lanes...
  866. pshufd \$0x55,$xa3,$xa1
  867. movdqa $xa0,0x40(%rsp) # ... and offload
  868. pshufd \$0xaa,$xa3,$xa2
  869. movdqa $xa1,0x50(%rsp)
  870. pshufd \$0xff,$xa3,$xa3
  871. movdqa $xa2,0x60(%rsp)
  872. movdqa $xa3,0x70(%rsp)
  873. pshufd \$0x00,$xb3,$xb0
  874. pshufd \$0x55,$xb3,$xb1
  875. movdqa $xb0,0x80-0x100(%rcx)
  876. pshufd \$0xaa,$xb3,$xb2
  877. movdqa $xb1,0x90-0x100(%rcx)
  878. pshufd \$0xff,$xb3,$xb3
  879. movdqa $xb2,0xa0-0x100(%rcx)
  880. movdqa $xb3,0xb0-0x100(%rcx)
  881. pshufd \$0x00,$xt3,$xt0 # "$xc0"
  882. pshufd \$0x55,$xt3,$xt1 # "$xc1"
  883. movdqa $xt0,0xc0-0x100(%rcx)
  884. pshufd \$0xaa,$xt3,$xt2 # "$xc2"
  885. movdqa $xt1,0xd0-0x100(%rcx)
  886. pshufd \$0xff,$xt3,$xt3 # "$xc3"
  887. movdqa $xt2,0xe0-0x100(%rcx)
  888. movdqa $xt3,0xf0-0x100(%rcx)
  889. pshufd \$0x00,$xd3,$xd0
  890. pshufd \$0x55,$xd3,$xd1
  891. paddd .Linc(%rip),$xd0 # don't save counters yet
  892. pshufd \$0xaa,$xd3,$xd2
  893. movdqa $xd1,0x110-0x100(%rcx)
  894. pshufd \$0xff,$xd3,$xd3
  895. movdqa $xd2,0x120-0x100(%rcx)
  896. movdqa $xd3,0x130-0x100(%rcx)
  897. jmp .Loop_enter4x
  898. .align 32
  899. .Loop_outer4x:
  900. movdqa 0x40(%rsp),$xa0 # re-load smashed key
  901. movdqa 0x50(%rsp),$xa1
  902. movdqa 0x60(%rsp),$xa2
  903. movdqa 0x70(%rsp),$xa3
  904. movdqa 0x80-0x100(%rcx),$xb0
  905. movdqa 0x90-0x100(%rcx),$xb1
  906. movdqa 0xa0-0x100(%rcx),$xb2
  907. movdqa 0xb0-0x100(%rcx),$xb3
  908. movdqa 0xc0-0x100(%rcx),$xt0 # "$xc0"
  909. movdqa 0xd0-0x100(%rcx),$xt1 # "$xc1"
  910. movdqa 0xe0-0x100(%rcx),$xt2 # "$xc2"
  911. movdqa 0xf0-0x100(%rcx),$xt3 # "$xc3"
  912. movdqa 0x100-0x100(%rcx),$xd0
  913. movdqa 0x110-0x100(%rcx),$xd1
  914. movdqa 0x120-0x100(%rcx),$xd2
  915. movdqa 0x130-0x100(%rcx),$xd3
  916. paddd .Lfour(%rip),$xd0 # next SIMD counters
  917. .Loop_enter4x:
  918. movdqa $xt2,0x20(%rsp) # SIMD equivalent of "@x[10]"
  919. movdqa $xt3,0x30(%rsp) # SIMD equivalent of "@x[11]"
  920. movdqa (%r10),$xt3 # .Lrot16(%rip)
  921. mov \$10,%eax
  922. movdqa $xd0,0x100-0x100(%rcx) # save SIMD counters
  923. jmp .Loop4x
  924. .align 32
  925. .Loop4x:
  926. ___
  927. foreach (&SSSE3_lane_ROUND(0, 4, 8,12)) { eval; }
  928. foreach (&SSSE3_lane_ROUND(0, 5,10,15)) { eval; }
  929. $code.=<<___;
  930. dec %eax
  931. jnz .Loop4x
  932. paddd 0x40(%rsp),$xa0 # accumulate key material
  933. paddd 0x50(%rsp),$xa1
  934. paddd 0x60(%rsp),$xa2
  935. paddd 0x70(%rsp),$xa3
  936. movdqa $xa0,$xt2 # "de-interlace" data
  937. punpckldq $xa1,$xa0
  938. movdqa $xa2,$xt3
  939. punpckldq $xa3,$xa2
  940. punpckhdq $xa1,$xt2
  941. punpckhdq $xa3,$xt3
  942. movdqa $xa0,$xa1
  943. punpcklqdq $xa2,$xa0 # "a0"
  944. movdqa $xt2,$xa3
  945. punpcklqdq $xt3,$xt2 # "a2"
  946. punpckhqdq $xa2,$xa1 # "a1"
  947. punpckhqdq $xt3,$xa3 # "a3"
  948. ___
  949. ($xa2,$xt2)=($xt2,$xa2);
  950. $code.=<<___;
  951. paddd 0x80-0x100(%rcx),$xb0
  952. paddd 0x90-0x100(%rcx),$xb1
  953. paddd 0xa0-0x100(%rcx),$xb2
  954. paddd 0xb0-0x100(%rcx),$xb3
  955. movdqa $xa0,0x00(%rsp) # offload $xaN
  956. movdqa $xa1,0x10(%rsp)
  957. movdqa 0x20(%rsp),$xa0 # "xc2"
  958. movdqa 0x30(%rsp),$xa1 # "xc3"
  959. movdqa $xb0,$xt2
  960. punpckldq $xb1,$xb0
  961. movdqa $xb2,$xt3
  962. punpckldq $xb3,$xb2
  963. punpckhdq $xb1,$xt2
  964. punpckhdq $xb3,$xt3
  965. movdqa $xb0,$xb1
  966. punpcklqdq $xb2,$xb0 # "b0"
  967. movdqa $xt2,$xb3
  968. punpcklqdq $xt3,$xt2 # "b2"
  969. punpckhqdq $xb2,$xb1 # "b1"
  970. punpckhqdq $xt3,$xb3 # "b3"
  971. ___
  972. ($xb2,$xt2)=($xt2,$xb2);
  973. my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
  974. $code.=<<___;
  975. paddd 0xc0-0x100(%rcx),$xc0
  976. paddd 0xd0-0x100(%rcx),$xc1
  977. paddd 0xe0-0x100(%rcx),$xc2
  978. paddd 0xf0-0x100(%rcx),$xc3
  979. movdqa $xa2,0x20(%rsp) # keep offloading $xaN
  980. movdqa $xa3,0x30(%rsp)
  981. movdqa $xc0,$xt2
  982. punpckldq $xc1,$xc0
  983. movdqa $xc2,$xt3
  984. punpckldq $xc3,$xc2
  985. punpckhdq $xc1,$xt2
  986. punpckhdq $xc3,$xt3
  987. movdqa $xc0,$xc1
  988. punpcklqdq $xc2,$xc0 # "c0"
  989. movdqa $xt2,$xc3
  990. punpcklqdq $xt3,$xt2 # "c2"
  991. punpckhqdq $xc2,$xc1 # "c1"
  992. punpckhqdq $xt3,$xc3 # "c3"
  993. ___
  994. ($xc2,$xt2)=($xt2,$xc2);
  995. ($xt0,$xt1)=($xa2,$xa3); # use $xaN as temporary
  996. $code.=<<___;
  997. paddd 0x100-0x100(%rcx),$xd0
  998. paddd 0x110-0x100(%rcx),$xd1
  999. paddd 0x120-0x100(%rcx),$xd2
  1000. paddd 0x130-0x100(%rcx),$xd3
  1001. movdqa $xd0,$xt2
  1002. punpckldq $xd1,$xd0
  1003. movdqa $xd2,$xt3
  1004. punpckldq $xd3,$xd2
  1005. punpckhdq $xd1,$xt2
  1006. punpckhdq $xd3,$xt3
  1007. movdqa $xd0,$xd1
  1008. punpcklqdq $xd2,$xd0 # "d0"
  1009. movdqa $xt2,$xd3
  1010. punpcklqdq $xt3,$xt2 # "d2"
  1011. punpckhqdq $xd2,$xd1 # "d1"
  1012. punpckhqdq $xt3,$xd3 # "d3"
  1013. ___
  1014. ($xd2,$xt2)=($xt2,$xd2);
  1015. $code.=<<___;
  1016. cmp \$64*4,$len
  1017. jb .Ltail4x
  1018. movdqu 0x00($inp),$xt0 # xor with input
  1019. movdqu 0x10($inp),$xt1
  1020. movdqu 0x20($inp),$xt2
  1021. movdqu 0x30($inp),$xt3
  1022. pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
  1023. pxor $xb0,$xt1
  1024. pxor $xc0,$xt2
  1025. pxor $xd0,$xt3
  1026. movdqu $xt0,0x00($out)
  1027. movdqu 0x40($inp),$xt0
  1028. movdqu $xt1,0x10($out)
  1029. movdqu 0x50($inp),$xt1
  1030. movdqu $xt2,0x20($out)
  1031. movdqu 0x60($inp),$xt2
  1032. movdqu $xt3,0x30($out)
  1033. movdqu 0x70($inp),$xt3
  1034. lea 0x80($inp),$inp # size optimization
  1035. pxor 0x10(%rsp),$xt0
  1036. pxor $xb1,$xt1
  1037. pxor $xc1,$xt2
  1038. pxor $xd1,$xt3
  1039. movdqu $xt0,0x40($out)
  1040. movdqu 0x00($inp),$xt0
  1041. movdqu $xt1,0x50($out)
  1042. movdqu 0x10($inp),$xt1
  1043. movdqu $xt2,0x60($out)
  1044. movdqu 0x20($inp),$xt2
  1045. movdqu $xt3,0x70($out)
  1046. lea 0x80($out),$out # size optimization
  1047. movdqu 0x30($inp),$xt3
  1048. pxor 0x20(%rsp),$xt0
  1049. pxor $xb2,$xt1
  1050. pxor $xc2,$xt2
  1051. pxor $xd2,$xt3
  1052. movdqu $xt0,0x00($out)
  1053. movdqu 0x40($inp),$xt0
  1054. movdqu $xt1,0x10($out)
  1055. movdqu 0x50($inp),$xt1
  1056. movdqu $xt2,0x20($out)
  1057. movdqu 0x60($inp),$xt2
  1058. movdqu $xt3,0x30($out)
  1059. movdqu 0x70($inp),$xt3
  1060. lea 0x80($inp),$inp # inp+=64*4
  1061. pxor 0x30(%rsp),$xt0
  1062. pxor $xb3,$xt1
  1063. pxor $xc3,$xt2
  1064. pxor $xd3,$xt3
  1065. movdqu $xt0,0x40($out)
  1066. movdqu $xt1,0x50($out)
  1067. movdqu $xt2,0x60($out)
  1068. movdqu $xt3,0x70($out)
  1069. lea 0x80($out),$out # out+=64*4
  1070. sub \$64*4,$len
  1071. jnz .Loop_outer4x
  1072. jmp .Ldone4x
  1073. .Ltail4x:
  1074. cmp \$192,$len
  1075. jae .L192_or_more4x
  1076. cmp \$128,$len
  1077. jae .L128_or_more4x
  1078. cmp \$64,$len
  1079. jae .L64_or_more4x
  1080. #movdqa 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
  1081. xor %r10,%r10
  1082. #movdqa $xt0,0x00(%rsp)
  1083. movdqa $xb0,0x10(%rsp)
  1084. movdqa $xc0,0x20(%rsp)
  1085. movdqa $xd0,0x30(%rsp)
  1086. jmp .Loop_tail4x
  1087. .align 32
  1088. .L64_or_more4x:
  1089. movdqu 0x00($inp),$xt0 # xor with input
  1090. movdqu 0x10($inp),$xt1
  1091. movdqu 0x20($inp),$xt2
  1092. movdqu 0x30($inp),$xt3
  1093. pxor 0x00(%rsp),$xt0 # $xaxN is offloaded, remember?
  1094. pxor $xb0,$xt1
  1095. pxor $xc0,$xt2
  1096. pxor $xd0,$xt3
  1097. movdqu $xt0,0x00($out)
  1098. movdqu $xt1,0x10($out)
  1099. movdqu $xt2,0x20($out)
  1100. movdqu $xt3,0x30($out)
  1101. je .Ldone4x
  1102. movdqa 0x10(%rsp),$xt0 # $xaN is offloaded, remember?
  1103. lea 0x40($inp),$inp # inp+=64*1
  1104. xor %r10,%r10
  1105. movdqa $xt0,0x00(%rsp)
  1106. movdqa $xb1,0x10(%rsp)
  1107. lea 0x40($out),$out # out+=64*1
  1108. movdqa $xc1,0x20(%rsp)
  1109. sub \$64,$len # len-=64*1
  1110. movdqa $xd1,0x30(%rsp)
  1111. jmp .Loop_tail4x
  1112. .align 32
  1113. .L128_or_more4x:
  1114. movdqu 0x00($inp),$xt0 # xor with input
  1115. movdqu 0x10($inp),$xt1
  1116. movdqu 0x20($inp),$xt2
  1117. movdqu 0x30($inp),$xt3
  1118. pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
  1119. pxor $xb0,$xt1
  1120. pxor $xc0,$xt2
  1121. pxor $xd0,$xt3
  1122. movdqu $xt0,0x00($out)
  1123. movdqu 0x40($inp),$xt0
  1124. movdqu $xt1,0x10($out)
  1125. movdqu 0x50($inp),$xt1
  1126. movdqu $xt2,0x20($out)
  1127. movdqu 0x60($inp),$xt2
  1128. movdqu $xt3,0x30($out)
  1129. movdqu 0x70($inp),$xt3
  1130. pxor 0x10(%rsp),$xt0
  1131. pxor $xb1,$xt1
  1132. pxor $xc1,$xt2
  1133. pxor $xd1,$xt3
  1134. movdqu $xt0,0x40($out)
  1135. movdqu $xt1,0x50($out)
  1136. movdqu $xt2,0x60($out)
  1137. movdqu $xt3,0x70($out)
  1138. je .Ldone4x
  1139. movdqa 0x20(%rsp),$xt0 # $xaN is offloaded, remember?
  1140. lea 0x80($inp),$inp # inp+=64*2
  1141. xor %r10,%r10
  1142. movdqa $xt0,0x00(%rsp)
  1143. movdqa $xb2,0x10(%rsp)
  1144. lea 0x80($out),$out # out+=64*2
  1145. movdqa $xc2,0x20(%rsp)
  1146. sub \$128,$len # len-=64*2
  1147. movdqa $xd2,0x30(%rsp)
  1148. jmp .Loop_tail4x
  1149. .align 32
  1150. .L192_or_more4x:
  1151. movdqu 0x00($inp),$xt0 # xor with input
  1152. movdqu 0x10($inp),$xt1
  1153. movdqu 0x20($inp),$xt2
  1154. movdqu 0x30($inp),$xt3
  1155. pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
  1156. pxor $xb0,$xt1
  1157. pxor $xc0,$xt2
  1158. pxor $xd0,$xt3
  1159. movdqu $xt0,0x00($out)
  1160. movdqu 0x40($inp),$xt0
  1161. movdqu $xt1,0x10($out)
  1162. movdqu 0x50($inp),$xt1
  1163. movdqu $xt2,0x20($out)
  1164. movdqu 0x60($inp),$xt2
  1165. movdqu $xt3,0x30($out)
  1166. movdqu 0x70($inp),$xt3
  1167. lea 0x80($inp),$inp # size optimization
  1168. pxor 0x10(%rsp),$xt0
  1169. pxor $xb1,$xt1
  1170. pxor $xc1,$xt2
  1171. pxor $xd1,$xt3
  1172. movdqu $xt0,0x40($out)
  1173. movdqu 0x00($inp),$xt0
  1174. movdqu $xt1,0x50($out)
  1175. movdqu 0x10($inp),$xt1
  1176. movdqu $xt2,0x60($out)
  1177. movdqu 0x20($inp),$xt2
  1178. movdqu $xt3,0x70($out)
  1179. lea 0x80($out),$out # size optimization
  1180. movdqu 0x30($inp),$xt3
  1181. pxor 0x20(%rsp),$xt0
  1182. pxor $xb2,$xt1
  1183. pxor $xc2,$xt2
  1184. pxor $xd2,$xt3
  1185. movdqu $xt0,0x00($out)
  1186. movdqu $xt1,0x10($out)
  1187. movdqu $xt2,0x20($out)
  1188. movdqu $xt3,0x30($out)
  1189. je .Ldone4x
  1190. movdqa 0x30(%rsp),$xt0 # $xaN is offloaded, remember?
  1191. lea 0x40($inp),$inp # inp+=64*3
  1192. xor %r10,%r10
  1193. movdqa $xt0,0x00(%rsp)
  1194. movdqa $xb3,0x10(%rsp)
  1195. lea 0x40($out),$out # out+=64*3
  1196. movdqa $xc3,0x20(%rsp)
  1197. sub \$192,$len # len-=64*3
  1198. movdqa $xd3,0x30(%rsp)
  1199. .Loop_tail4x:
  1200. movzb ($inp,%r10),%eax
  1201. movzb (%rsp,%r10),%ecx
  1202. lea 1(%r10),%r10
  1203. xor %ecx,%eax
  1204. mov %al,-1($out,%r10)
  1205. dec $len
  1206. jnz .Loop_tail4x
  1207. .Ldone4x:
  1208. ___
  1209. $code.=<<___ if ($win64);
  1210. movaps -0xa8(%r9),%xmm6
  1211. movaps -0x98(%r9),%xmm7
  1212. movaps -0x88(%r9),%xmm8
  1213. movaps -0x78(%r9),%xmm9
  1214. movaps -0x68(%r9),%xmm10
  1215. movaps -0x58(%r9),%xmm11
  1216. movaps -0x48(%r9),%xmm12
  1217. movaps -0x38(%r9),%xmm13
  1218. movaps -0x28(%r9),%xmm14
  1219. movaps -0x18(%r9),%xmm15
  1220. ___
  1221. $code.=<<___;
  1222. lea (%r9),%rsp
  1223. .cfi_def_cfa_register %rsp
  1224. .L4x_epilogue:
  1225. ret
  1226. .cfi_endproc
  1227. .size ChaCha20_4x,.-ChaCha20_4x
  1228. ___
  1229. }
  1230. ########################################################################
  1231. # XOP code path that handles all lengths.
  1232. if ($avx) {
  1233. # There is some "anomaly" observed depending on instructions' size or
  1234. # alignment. If you look closely at below code you'll notice that
  1235. # sometimes argument order varies. The order affects instruction
  1236. # encoding by making it larger, and such fiddling gives 5% performance
  1237. # improvement. This is on FX-4100...
  1238. my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
  1239. $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%xmm$_",(0..15));
  1240. my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  1241. $xt0,$xt1,$xt2,$xt3, $xd0,$xd1,$xd2,$xd3);
  1242. sub XOP_lane_ROUND {
  1243. my ($a0,$b0,$c0,$d0)=@_;
  1244. my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
  1245. my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
  1246. my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
  1247. my @x=map("\"$_\"",@xx);
  1248. (
  1249. "&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
  1250. "&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
  1251. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
  1252. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
  1253. "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
  1254. "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
  1255. "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
  1256. "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
  1257. "&vprotd (@x[$d0],@x[$d0],16)",
  1258. "&vprotd (@x[$d1],@x[$d1],16)",
  1259. "&vprotd (@x[$d2],@x[$d2],16)",
  1260. "&vprotd (@x[$d3],@x[$d3],16)",
  1261. "&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
  1262. "&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
  1263. "&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
  1264. "&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
  1265. "&vpxor (@x[$b0],@x[$c0],@x[$b0])",
  1266. "&vpxor (@x[$b1],@x[$c1],@x[$b1])",
  1267. "&vpxor (@x[$b2],@x[$b2],@x[$c2])", # flip
  1268. "&vpxor (@x[$b3],@x[$b3],@x[$c3])", # flip
  1269. "&vprotd (@x[$b0],@x[$b0],12)",
  1270. "&vprotd (@x[$b1],@x[$b1],12)",
  1271. "&vprotd (@x[$b2],@x[$b2],12)",
  1272. "&vprotd (@x[$b3],@x[$b3],12)",
  1273. "&vpaddd (@x[$a0],@x[$b0],@x[$a0])", # flip
  1274. "&vpaddd (@x[$a1],@x[$b1],@x[$a1])", # flip
  1275. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
  1276. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
  1277. "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
  1278. "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
  1279. "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
  1280. "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
  1281. "&vprotd (@x[$d0],@x[$d0],8)",
  1282. "&vprotd (@x[$d1],@x[$d1],8)",
  1283. "&vprotd (@x[$d2],@x[$d2],8)",
  1284. "&vprotd (@x[$d3],@x[$d3],8)",
  1285. "&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
  1286. "&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
  1287. "&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
  1288. "&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
  1289. "&vpxor (@x[$b0],@x[$c0],@x[$b0])",
  1290. "&vpxor (@x[$b1],@x[$c1],@x[$b1])",
  1291. "&vpxor (@x[$b2],@x[$b2],@x[$c2])", # flip
  1292. "&vpxor (@x[$b3],@x[$b3],@x[$c3])", # flip
  1293. "&vprotd (@x[$b0],@x[$b0],7)",
  1294. "&vprotd (@x[$b1],@x[$b1],7)",
  1295. "&vprotd (@x[$b2],@x[$b2],7)",
  1296. "&vprotd (@x[$b3],@x[$b3],7)"
  1297. );
  1298. }
  1299. my $xframe = $win64 ? 0xa8 : 8;
  1300. $code.=<<___;
  1301. .type ChaCha20_4xop,\@function,5
  1302. .align 32
  1303. ChaCha20_4xop:
  1304. .cfi_startproc
  1305. .LChaCha20_4xop:
  1306. mov %rsp,%r9 # frame pointer
  1307. .cfi_def_cfa_register %r9
  1308. sub \$0x140+$xframe,%rsp
  1309. ___
  1310. ################ stack layout
  1311. # +0x00 SIMD equivalent of @x[8-12]
  1312. # ...
  1313. # +0x40 constant copy of key[0-2] smashed by lanes
  1314. # ...
  1315. # +0x100 SIMD counters (with nonce smashed by lanes)
  1316. # ...
  1317. # +0x140
  1318. $code.=<<___ if ($win64);
  1319. movaps %xmm6,-0xa8(%r9)
  1320. movaps %xmm7,-0x98(%r9)
  1321. movaps %xmm8,-0x88(%r9)
  1322. movaps %xmm9,-0x78(%r9)
  1323. movaps %xmm10,-0x68(%r9)
  1324. movaps %xmm11,-0x58(%r9)
  1325. movaps %xmm12,-0x48(%r9)
  1326. movaps %xmm13,-0x38(%r9)
  1327. movaps %xmm14,-0x28(%r9)
  1328. movaps %xmm15,-0x18(%r9)
  1329. .L4xop_body:
  1330. ___
  1331. $code.=<<___;
  1332. vzeroupper
  1333. vmovdqa .Lsigma(%rip),$xa3 # key[0]
  1334. vmovdqu ($key),$xb3 # key[1]
  1335. vmovdqu 16($key),$xt3 # key[2]
  1336. vmovdqu ($counter),$xd3 # key[3]
  1337. lea 0x100(%rsp),%rcx # size optimization
  1338. vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
  1339. vpshufd \$0x55,$xa3,$xa1
  1340. vmovdqa $xa0,0x40(%rsp) # ... and offload
  1341. vpshufd \$0xaa,$xa3,$xa2
  1342. vmovdqa $xa1,0x50(%rsp)
  1343. vpshufd \$0xff,$xa3,$xa3
  1344. vmovdqa $xa2,0x60(%rsp)
  1345. vmovdqa $xa3,0x70(%rsp)
  1346. vpshufd \$0x00,$xb3,$xb0
  1347. vpshufd \$0x55,$xb3,$xb1
  1348. vmovdqa $xb0,0x80-0x100(%rcx)
  1349. vpshufd \$0xaa,$xb3,$xb2
  1350. vmovdqa $xb1,0x90-0x100(%rcx)
  1351. vpshufd \$0xff,$xb3,$xb3
  1352. vmovdqa $xb2,0xa0-0x100(%rcx)
  1353. vmovdqa $xb3,0xb0-0x100(%rcx)
  1354. vpshufd \$0x00,$xt3,$xt0 # "$xc0"
  1355. vpshufd \$0x55,$xt3,$xt1 # "$xc1"
  1356. vmovdqa $xt0,0xc0-0x100(%rcx)
  1357. vpshufd \$0xaa,$xt3,$xt2 # "$xc2"
  1358. vmovdqa $xt1,0xd0-0x100(%rcx)
  1359. vpshufd \$0xff,$xt3,$xt3 # "$xc3"
  1360. vmovdqa $xt2,0xe0-0x100(%rcx)
  1361. vmovdqa $xt3,0xf0-0x100(%rcx)
  1362. vpshufd \$0x00,$xd3,$xd0
  1363. vpshufd \$0x55,$xd3,$xd1
  1364. vpaddd .Linc(%rip),$xd0,$xd0 # don't save counters yet
  1365. vpshufd \$0xaa,$xd3,$xd2
  1366. vmovdqa $xd1,0x110-0x100(%rcx)
  1367. vpshufd \$0xff,$xd3,$xd3
  1368. vmovdqa $xd2,0x120-0x100(%rcx)
  1369. vmovdqa $xd3,0x130-0x100(%rcx)
  1370. jmp .Loop_enter4xop
  1371. .align 32
  1372. .Loop_outer4xop:
  1373. vmovdqa 0x40(%rsp),$xa0 # re-load smashed key
  1374. vmovdqa 0x50(%rsp),$xa1
  1375. vmovdqa 0x60(%rsp),$xa2
  1376. vmovdqa 0x70(%rsp),$xa3
  1377. vmovdqa 0x80-0x100(%rcx),$xb0
  1378. vmovdqa 0x90-0x100(%rcx),$xb1
  1379. vmovdqa 0xa0-0x100(%rcx),$xb2
  1380. vmovdqa 0xb0-0x100(%rcx),$xb3
  1381. vmovdqa 0xc0-0x100(%rcx),$xt0 # "$xc0"
  1382. vmovdqa 0xd0-0x100(%rcx),$xt1 # "$xc1"
  1383. vmovdqa 0xe0-0x100(%rcx),$xt2 # "$xc2"
  1384. vmovdqa 0xf0-0x100(%rcx),$xt3 # "$xc3"
  1385. vmovdqa 0x100-0x100(%rcx),$xd0
  1386. vmovdqa 0x110-0x100(%rcx),$xd1
  1387. vmovdqa 0x120-0x100(%rcx),$xd2
  1388. vmovdqa 0x130-0x100(%rcx),$xd3
  1389. vpaddd .Lfour(%rip),$xd0,$xd0 # next SIMD counters
  1390. .Loop_enter4xop:
  1391. mov \$10,%eax
  1392. vmovdqa $xd0,0x100-0x100(%rcx) # save SIMD counters
  1393. jmp .Loop4xop
  1394. .align 32
  1395. .Loop4xop:
  1396. ___
  1397. foreach (&XOP_lane_ROUND(0, 4, 8,12)) { eval; }
  1398. foreach (&XOP_lane_ROUND(0, 5,10,15)) { eval; }
  1399. $code.=<<___;
  1400. dec %eax
  1401. jnz .Loop4xop
  1402. vpaddd 0x40(%rsp),$xa0,$xa0 # accumulate key material
  1403. vpaddd 0x50(%rsp),$xa1,$xa1
  1404. vpaddd 0x60(%rsp),$xa2,$xa2
  1405. vpaddd 0x70(%rsp),$xa3,$xa3
  1406. vmovdqa $xt2,0x20(%rsp) # offload $xc2,3
  1407. vmovdqa $xt3,0x30(%rsp)
  1408. vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
  1409. vpunpckldq $xa3,$xa2,$xt3
  1410. vpunpckhdq $xa1,$xa0,$xa0
  1411. vpunpckhdq $xa3,$xa2,$xa2
  1412. vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
  1413. vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
  1414. vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
  1415. vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
  1416. ___
  1417. ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
  1418. $code.=<<___;
  1419. vpaddd 0x80-0x100(%rcx),$xb0,$xb0
  1420. vpaddd 0x90-0x100(%rcx),$xb1,$xb1
  1421. vpaddd 0xa0-0x100(%rcx),$xb2,$xb2
  1422. vpaddd 0xb0-0x100(%rcx),$xb3,$xb3
  1423. vmovdqa $xa0,0x00(%rsp) # offload $xa0,1
  1424. vmovdqa $xa1,0x10(%rsp)
  1425. vmovdqa 0x20(%rsp),$xa0 # "xc2"
  1426. vmovdqa 0x30(%rsp),$xa1 # "xc3"
  1427. vpunpckldq $xb1,$xb0,$xt2
  1428. vpunpckldq $xb3,$xb2,$xt3
  1429. vpunpckhdq $xb1,$xb0,$xb0
  1430. vpunpckhdq $xb3,$xb2,$xb2
  1431. vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
  1432. vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
  1433. vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
  1434. vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
  1435. ___
  1436. ($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
  1437. my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
  1438. $code.=<<___;
  1439. vpaddd 0xc0-0x100(%rcx),$xc0,$xc0
  1440. vpaddd 0xd0-0x100(%rcx),$xc1,$xc1
  1441. vpaddd 0xe0-0x100(%rcx),$xc2,$xc2
  1442. vpaddd 0xf0-0x100(%rcx),$xc3,$xc3
  1443. vpunpckldq $xc1,$xc0,$xt2
  1444. vpunpckldq $xc3,$xc2,$xt3
  1445. vpunpckhdq $xc1,$xc0,$xc0
  1446. vpunpckhdq $xc3,$xc2,$xc2
  1447. vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
  1448. vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
  1449. vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
  1450. vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
  1451. ___
  1452. ($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
  1453. $code.=<<___;
  1454. vpaddd 0x100-0x100(%rcx),$xd0,$xd0
  1455. vpaddd 0x110-0x100(%rcx),$xd1,$xd1
  1456. vpaddd 0x120-0x100(%rcx),$xd2,$xd2
  1457. vpaddd 0x130-0x100(%rcx),$xd3,$xd3
  1458. vpunpckldq $xd1,$xd0,$xt2
  1459. vpunpckldq $xd3,$xd2,$xt3
  1460. vpunpckhdq $xd1,$xd0,$xd0
  1461. vpunpckhdq $xd3,$xd2,$xd2
  1462. vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
  1463. vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
  1464. vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
  1465. vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
  1466. ___
  1467. ($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
  1468. ($xa0,$xa1)=($xt2,$xt3);
  1469. $code.=<<___;
  1470. vmovdqa 0x00(%rsp),$xa0 # restore $xa0,1
  1471. vmovdqa 0x10(%rsp),$xa1
  1472. cmp \$64*4,$len
  1473. jb .Ltail4xop
  1474. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  1475. vpxor 0x10($inp),$xb0,$xb0
  1476. vpxor 0x20($inp),$xc0,$xc0
  1477. vpxor 0x30($inp),$xd0,$xd0
  1478. vpxor 0x40($inp),$xa1,$xa1
  1479. vpxor 0x50($inp),$xb1,$xb1
  1480. vpxor 0x60($inp),$xc1,$xc1
  1481. vpxor 0x70($inp),$xd1,$xd1
  1482. lea 0x80($inp),$inp # size optimization
  1483. vpxor 0x00($inp),$xa2,$xa2
  1484. vpxor 0x10($inp),$xb2,$xb2
  1485. vpxor 0x20($inp),$xc2,$xc2
  1486. vpxor 0x30($inp),$xd2,$xd2
  1487. vpxor 0x40($inp),$xa3,$xa3
  1488. vpxor 0x50($inp),$xb3,$xb3
  1489. vpxor 0x60($inp),$xc3,$xc3
  1490. vpxor 0x70($inp),$xd3,$xd3
  1491. lea 0x80($inp),$inp # inp+=64*4
  1492. vmovdqu $xa0,0x00($out)
  1493. vmovdqu $xb0,0x10($out)
  1494. vmovdqu $xc0,0x20($out)
  1495. vmovdqu $xd0,0x30($out)
  1496. vmovdqu $xa1,0x40($out)
  1497. vmovdqu $xb1,0x50($out)
  1498. vmovdqu $xc1,0x60($out)
  1499. vmovdqu $xd1,0x70($out)
  1500. lea 0x80($out),$out # size optimization
  1501. vmovdqu $xa2,0x00($out)
  1502. vmovdqu $xb2,0x10($out)
  1503. vmovdqu $xc2,0x20($out)
  1504. vmovdqu $xd2,0x30($out)
  1505. vmovdqu $xa3,0x40($out)
  1506. vmovdqu $xb3,0x50($out)
  1507. vmovdqu $xc3,0x60($out)
  1508. vmovdqu $xd3,0x70($out)
  1509. lea 0x80($out),$out # out+=64*4
  1510. sub \$64*4,$len
  1511. jnz .Loop_outer4xop
  1512. jmp .Ldone4xop
  1513. .align 32
  1514. .Ltail4xop:
  1515. cmp \$192,$len
  1516. jae .L192_or_more4xop
  1517. cmp \$128,$len
  1518. jae .L128_or_more4xop
  1519. cmp \$64,$len
  1520. jae .L64_or_more4xop
  1521. xor %r10,%r10
  1522. vmovdqa $xa0,0x00(%rsp)
  1523. vmovdqa $xb0,0x10(%rsp)
  1524. vmovdqa $xc0,0x20(%rsp)
  1525. vmovdqa $xd0,0x30(%rsp)
  1526. jmp .Loop_tail4xop
  1527. .align 32
  1528. .L64_or_more4xop:
  1529. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  1530. vpxor 0x10($inp),$xb0,$xb0
  1531. vpxor 0x20($inp),$xc0,$xc0
  1532. vpxor 0x30($inp),$xd0,$xd0
  1533. vmovdqu $xa0,0x00($out)
  1534. vmovdqu $xb0,0x10($out)
  1535. vmovdqu $xc0,0x20($out)
  1536. vmovdqu $xd0,0x30($out)
  1537. je .Ldone4xop
  1538. lea 0x40($inp),$inp # inp+=64*1
  1539. vmovdqa $xa1,0x00(%rsp)
  1540. xor %r10,%r10
  1541. vmovdqa $xb1,0x10(%rsp)
  1542. lea 0x40($out),$out # out+=64*1
  1543. vmovdqa $xc1,0x20(%rsp)
  1544. sub \$64,$len # len-=64*1
  1545. vmovdqa $xd1,0x30(%rsp)
  1546. jmp .Loop_tail4xop
  1547. .align 32
  1548. .L128_or_more4xop:
  1549. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  1550. vpxor 0x10($inp),$xb0,$xb0
  1551. vpxor 0x20($inp),$xc0,$xc0
  1552. vpxor 0x30($inp),$xd0,$xd0
  1553. vpxor 0x40($inp),$xa1,$xa1
  1554. vpxor 0x50($inp),$xb1,$xb1
  1555. vpxor 0x60($inp),$xc1,$xc1
  1556. vpxor 0x70($inp),$xd1,$xd1
  1557. vmovdqu $xa0,0x00($out)
  1558. vmovdqu $xb0,0x10($out)
  1559. vmovdqu $xc0,0x20($out)
  1560. vmovdqu $xd0,0x30($out)
  1561. vmovdqu $xa1,0x40($out)
  1562. vmovdqu $xb1,0x50($out)
  1563. vmovdqu $xc1,0x60($out)
  1564. vmovdqu $xd1,0x70($out)
  1565. je .Ldone4xop
  1566. lea 0x80($inp),$inp # inp+=64*2
  1567. vmovdqa $xa2,0x00(%rsp)
  1568. xor %r10,%r10
  1569. vmovdqa $xb2,0x10(%rsp)
  1570. lea 0x80($out),$out # out+=64*2
  1571. vmovdqa $xc2,0x20(%rsp)
  1572. sub \$128,$len # len-=64*2
  1573. vmovdqa $xd2,0x30(%rsp)
  1574. jmp .Loop_tail4xop
  1575. .align 32
  1576. .L192_or_more4xop:
  1577. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  1578. vpxor 0x10($inp),$xb0,$xb0
  1579. vpxor 0x20($inp),$xc0,$xc0
  1580. vpxor 0x30($inp),$xd0,$xd0
  1581. vpxor 0x40($inp),$xa1,$xa1
  1582. vpxor 0x50($inp),$xb1,$xb1
  1583. vpxor 0x60($inp),$xc1,$xc1
  1584. vpxor 0x70($inp),$xd1,$xd1
  1585. lea 0x80($inp),$inp # size optimization
  1586. vpxor 0x00($inp),$xa2,$xa2
  1587. vpxor 0x10($inp),$xb2,$xb2
  1588. vpxor 0x20($inp),$xc2,$xc2
  1589. vpxor 0x30($inp),$xd2,$xd2
  1590. vmovdqu $xa0,0x00($out)
  1591. vmovdqu $xb0,0x10($out)
  1592. vmovdqu $xc0,0x20($out)
  1593. vmovdqu $xd0,0x30($out)
  1594. vmovdqu $xa1,0x40($out)
  1595. vmovdqu $xb1,0x50($out)
  1596. vmovdqu $xc1,0x60($out)
  1597. vmovdqu $xd1,0x70($out)
  1598. lea 0x80($out),$out # size optimization
  1599. vmovdqu $xa2,0x00($out)
  1600. vmovdqu $xb2,0x10($out)
  1601. vmovdqu $xc2,0x20($out)
  1602. vmovdqu $xd2,0x30($out)
  1603. je .Ldone4xop
  1604. lea 0x40($inp),$inp # inp+=64*3
  1605. vmovdqa $xa3,0x00(%rsp)
  1606. xor %r10,%r10
  1607. vmovdqa $xb3,0x10(%rsp)
  1608. lea 0x40($out),$out # out+=64*3
  1609. vmovdqa $xc3,0x20(%rsp)
  1610. sub \$192,$len # len-=64*3
  1611. vmovdqa $xd3,0x30(%rsp)
  1612. .Loop_tail4xop:
  1613. movzb ($inp,%r10),%eax
  1614. movzb (%rsp,%r10),%ecx
  1615. lea 1(%r10),%r10
  1616. xor %ecx,%eax
  1617. mov %al,-1($out,%r10)
  1618. dec $len
  1619. jnz .Loop_tail4xop
  1620. .Ldone4xop:
  1621. vzeroupper
  1622. ___
  1623. $code.=<<___ if ($win64);
  1624. movaps -0xa8(%r9),%xmm6
  1625. movaps -0x98(%r9),%xmm7
  1626. movaps -0x88(%r9),%xmm8
  1627. movaps -0x78(%r9),%xmm9
  1628. movaps -0x68(%r9),%xmm10
  1629. movaps -0x58(%r9),%xmm11
  1630. movaps -0x48(%r9),%xmm12
  1631. movaps -0x38(%r9),%xmm13
  1632. movaps -0x28(%r9),%xmm14
  1633. movaps -0x18(%r9),%xmm15
  1634. ___
  1635. $code.=<<___;
  1636. lea (%r9),%rsp
  1637. .cfi_def_cfa_register %rsp
  1638. .L4xop_epilogue:
  1639. ret
  1640. .cfi_endproc
  1641. .size ChaCha20_4xop,.-ChaCha20_4xop
  1642. ___
  1643. }
  1644. ########################################################################
  1645. # AVX2 code path
  1646. if ($avx>1) {
  1647. my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
  1648. $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%ymm$_",(0..15));
  1649. my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  1650. "%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
  1651. sub AVX2_lane_ROUND {
  1652. my ($a0,$b0,$c0,$d0)=@_;
  1653. my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
  1654. my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
  1655. my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
  1656. my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
  1657. my @x=map("\"$_\"",@xx);
  1658. # Consider order in which variables are addressed by their
  1659. # index:
  1660. #
  1661. # a b c d
  1662. #
  1663. # 0 4 8 12 < even round
  1664. # 1 5 9 13
  1665. # 2 6 10 14
  1666. # 3 7 11 15
  1667. # 0 5 10 15 < odd round
  1668. # 1 6 11 12
  1669. # 2 7 8 13
  1670. # 3 4 9 14
  1671. #
  1672. # 'a', 'b' and 'd's are permanently allocated in registers,
  1673. # @x[0..7,12..15], while 'c's are maintained in memory. If
  1674. # you observe 'c' column, you'll notice that pair of 'c's is
  1675. # invariant between rounds. This means that we have to reload
  1676. # them once per round, in the middle. This is why you'll see
  1677. # bunch of 'c' stores and loads in the middle, but none in
  1678. # the beginning or end.
  1679. (
  1680. "&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
  1681. "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
  1682. "&vpshufb (@x[$d0],@x[$d0],$t1)",
  1683. "&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
  1684. "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
  1685. "&vpshufb (@x[$d1],@x[$d1],$t1)",
  1686. "&vpaddd ($xc,$xc,@x[$d0])",
  1687. "&vpxor (@x[$b0],$xc,@x[$b0])",
  1688. "&vpslld ($t0,@x[$b0],12)",
  1689. "&vpsrld (@x[$b0],@x[$b0],20)",
  1690. "&vpor (@x[$b0],$t0,@x[$b0])",
  1691. "&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
  1692. "&vpaddd ($xc_,$xc_,@x[$d1])",
  1693. "&vpxor (@x[$b1],$xc_,@x[$b1])",
  1694. "&vpslld ($t1,@x[$b1],12)",
  1695. "&vpsrld (@x[$b1],@x[$b1],20)",
  1696. "&vpor (@x[$b1],$t1,@x[$b1])",
  1697. "&vpaddd (@x[$a0],@x[$a0],@x[$b0])",
  1698. "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
  1699. "&vpshufb (@x[$d0],@x[$d0],$t0)",
  1700. "&vpaddd (@x[$a1],@x[$a1],@x[$b1])",
  1701. "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
  1702. "&vpshufb (@x[$d1],@x[$d1],$t0)",
  1703. "&vpaddd ($xc,$xc,@x[$d0])",
  1704. "&vpxor (@x[$b0],$xc,@x[$b0])",
  1705. "&vpslld ($t1,@x[$b0],7)",
  1706. "&vpsrld (@x[$b0],@x[$b0],25)",
  1707. "&vpor (@x[$b0],$t1,@x[$b0])",
  1708. "&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
  1709. "&vpaddd ($xc_,$xc_,@x[$d1])",
  1710. "&vpxor (@x[$b1],$xc_,@x[$b1])",
  1711. "&vpslld ($t0,@x[$b1],7)",
  1712. "&vpsrld (@x[$b1],@x[$b1],25)",
  1713. "&vpor (@x[$b1],$t0,@x[$b1])",
  1714. "&vmovdqa (\"`32*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
  1715. "&vmovdqa (\"`32*($c1-8)`(%rsp)\",$xc_)",
  1716. "&vmovdqa ($xc,\"`32*($c2-8)`(%rsp)\")",
  1717. "&vmovdqa ($xc_,\"`32*($c3-8)`(%rsp)\")",
  1718. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
  1719. "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
  1720. "&vpshufb (@x[$d2],@x[$d2],$t1)",
  1721. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
  1722. "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
  1723. "&vpshufb (@x[$d3],@x[$d3],$t1)",
  1724. "&vpaddd ($xc,$xc,@x[$d2])",
  1725. "&vpxor (@x[$b2],$xc,@x[$b2])",
  1726. "&vpslld ($t0,@x[$b2],12)",
  1727. "&vpsrld (@x[$b2],@x[$b2],20)",
  1728. "&vpor (@x[$b2],$t0,@x[$b2])",
  1729. "&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
  1730. "&vpaddd ($xc_,$xc_,@x[$d3])",
  1731. "&vpxor (@x[$b3],$xc_,@x[$b3])",
  1732. "&vpslld ($t1,@x[$b3],12)",
  1733. "&vpsrld (@x[$b3],@x[$b3],20)",
  1734. "&vpor (@x[$b3],$t1,@x[$b3])",
  1735. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
  1736. "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
  1737. "&vpshufb (@x[$d2],@x[$d2],$t0)",
  1738. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
  1739. "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
  1740. "&vpshufb (@x[$d3],@x[$d3],$t0)",
  1741. "&vpaddd ($xc,$xc,@x[$d2])",
  1742. "&vpxor (@x[$b2],$xc,@x[$b2])",
  1743. "&vpslld ($t1,@x[$b2],7)",
  1744. "&vpsrld (@x[$b2],@x[$b2],25)",
  1745. "&vpor (@x[$b2],$t1,@x[$b2])",
  1746. "&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
  1747. "&vpaddd ($xc_,$xc_,@x[$d3])",
  1748. "&vpxor (@x[$b3],$xc_,@x[$b3])",
  1749. "&vpslld ($t0,@x[$b3],7)",
  1750. "&vpsrld (@x[$b3],@x[$b3],25)",
  1751. "&vpor (@x[$b3],$t0,@x[$b3])"
  1752. );
  1753. }
  1754. my $xframe = $win64 ? 0xa8 : 8;
  1755. $code.=<<___;
  1756. .type ChaCha20_8x,\@function,5
  1757. .align 32
  1758. ChaCha20_8x:
  1759. .cfi_startproc
  1760. .LChaCha20_8x:
  1761. mov %rsp,%r9 # frame register
  1762. .cfi_def_cfa_register %r9
  1763. sub \$0x280+$xframe,%rsp
  1764. and \$-32,%rsp
  1765. ___
  1766. $code.=<<___ if ($win64);
  1767. movaps %xmm6,-0xa8(%r9)
  1768. movaps %xmm7,-0x98(%r9)
  1769. movaps %xmm8,-0x88(%r9)
  1770. movaps %xmm9,-0x78(%r9)
  1771. movaps %xmm10,-0x68(%r9)
  1772. movaps %xmm11,-0x58(%r9)
  1773. movaps %xmm12,-0x48(%r9)
  1774. movaps %xmm13,-0x38(%r9)
  1775. movaps %xmm14,-0x28(%r9)
  1776. movaps %xmm15,-0x18(%r9)
  1777. .L8x_body:
  1778. ___
  1779. $code.=<<___;
  1780. vzeroupper
  1781. ################ stack layout
  1782. # +0x00 SIMD equivalent of @x[8-12]
  1783. # ...
  1784. # +0x80 constant copy of key[0-2] smashed by lanes
  1785. # ...
  1786. # +0x200 SIMD counters (with nonce smashed by lanes)
  1787. # ...
  1788. # +0x280
  1789. vbroadcasti128 .Lsigma(%rip),$xa3 # key[0]
  1790. vbroadcasti128 ($key),$xb3 # key[1]
  1791. vbroadcasti128 16($key),$xt3 # key[2]
  1792. vbroadcasti128 ($counter),$xd3 # key[3]
  1793. lea 0x100(%rsp),%rcx # size optimization
  1794. lea 0x200(%rsp),%rax # size optimization
  1795. lea .Lrot16(%rip),%r10
  1796. lea .Lrot24(%rip),%r11
  1797. vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
  1798. vpshufd \$0x55,$xa3,$xa1
  1799. vmovdqa $xa0,0x80-0x100(%rcx) # ... and offload
  1800. vpshufd \$0xaa,$xa3,$xa2
  1801. vmovdqa $xa1,0xa0-0x100(%rcx)
  1802. vpshufd \$0xff,$xa3,$xa3
  1803. vmovdqa $xa2,0xc0-0x100(%rcx)
  1804. vmovdqa $xa3,0xe0-0x100(%rcx)
  1805. vpshufd \$0x00,$xb3,$xb0
  1806. vpshufd \$0x55,$xb3,$xb1
  1807. vmovdqa $xb0,0x100-0x100(%rcx)
  1808. vpshufd \$0xaa,$xb3,$xb2
  1809. vmovdqa $xb1,0x120-0x100(%rcx)
  1810. vpshufd \$0xff,$xb3,$xb3
  1811. vmovdqa $xb2,0x140-0x100(%rcx)
  1812. vmovdqa $xb3,0x160-0x100(%rcx)
  1813. vpshufd \$0x00,$xt3,$xt0 # "xc0"
  1814. vpshufd \$0x55,$xt3,$xt1 # "xc1"
  1815. vmovdqa $xt0,0x180-0x200(%rax)
  1816. vpshufd \$0xaa,$xt3,$xt2 # "xc2"
  1817. vmovdqa $xt1,0x1a0-0x200(%rax)
  1818. vpshufd \$0xff,$xt3,$xt3 # "xc3"
  1819. vmovdqa $xt2,0x1c0-0x200(%rax)
  1820. vmovdqa $xt3,0x1e0-0x200(%rax)
  1821. vpshufd \$0x00,$xd3,$xd0
  1822. vpshufd \$0x55,$xd3,$xd1
  1823. vpaddd .Lincy(%rip),$xd0,$xd0 # don't save counters yet
  1824. vpshufd \$0xaa,$xd3,$xd2
  1825. vmovdqa $xd1,0x220-0x200(%rax)
  1826. vpshufd \$0xff,$xd3,$xd3
  1827. vmovdqa $xd2,0x240-0x200(%rax)
  1828. vmovdqa $xd3,0x260-0x200(%rax)
  1829. jmp .Loop_enter8x
  1830. .align 32
  1831. .Loop_outer8x:
  1832. vmovdqa 0x80-0x100(%rcx),$xa0 # re-load smashed key
  1833. vmovdqa 0xa0-0x100(%rcx),$xa1
  1834. vmovdqa 0xc0-0x100(%rcx),$xa2
  1835. vmovdqa 0xe0-0x100(%rcx),$xa3
  1836. vmovdqa 0x100-0x100(%rcx),$xb0
  1837. vmovdqa 0x120-0x100(%rcx),$xb1
  1838. vmovdqa 0x140-0x100(%rcx),$xb2
  1839. vmovdqa 0x160-0x100(%rcx),$xb3
  1840. vmovdqa 0x180-0x200(%rax),$xt0 # "xc0"
  1841. vmovdqa 0x1a0-0x200(%rax),$xt1 # "xc1"
  1842. vmovdqa 0x1c0-0x200(%rax),$xt2 # "xc2"
  1843. vmovdqa 0x1e0-0x200(%rax),$xt3 # "xc3"
  1844. vmovdqa 0x200-0x200(%rax),$xd0
  1845. vmovdqa 0x220-0x200(%rax),$xd1
  1846. vmovdqa 0x240-0x200(%rax),$xd2
  1847. vmovdqa 0x260-0x200(%rax),$xd3
  1848. vpaddd .Leight(%rip),$xd0,$xd0 # next SIMD counters
  1849. .Loop_enter8x:
  1850. vmovdqa $xt2,0x40(%rsp) # SIMD equivalent of "@x[10]"
  1851. vmovdqa $xt3,0x60(%rsp) # SIMD equivalent of "@x[11]"
  1852. vbroadcasti128 (%r10),$xt3
  1853. vmovdqa $xd0,0x200-0x200(%rax) # save SIMD counters
  1854. mov \$10,%eax
  1855. jmp .Loop8x
  1856. .align 32
  1857. .Loop8x:
  1858. ___
  1859. foreach (&AVX2_lane_ROUND(0, 4, 8,12)) { eval; }
  1860. foreach (&AVX2_lane_ROUND(0, 5,10,15)) { eval; }
  1861. $code.=<<___;
  1862. dec %eax
  1863. jnz .Loop8x
  1864. lea 0x200(%rsp),%rax # size optimization
  1865. vpaddd 0x80-0x100(%rcx),$xa0,$xa0 # accumulate key
  1866. vpaddd 0xa0-0x100(%rcx),$xa1,$xa1
  1867. vpaddd 0xc0-0x100(%rcx),$xa2,$xa2
  1868. vpaddd 0xe0-0x100(%rcx),$xa3,$xa3
  1869. vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
  1870. vpunpckldq $xa3,$xa2,$xt3
  1871. vpunpckhdq $xa1,$xa0,$xa0
  1872. vpunpckhdq $xa3,$xa2,$xa2
  1873. vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
  1874. vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
  1875. vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
  1876. vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
  1877. ___
  1878. ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
  1879. $code.=<<___;
  1880. vpaddd 0x100-0x100(%rcx),$xb0,$xb0
  1881. vpaddd 0x120-0x100(%rcx),$xb1,$xb1
  1882. vpaddd 0x140-0x100(%rcx),$xb2,$xb2
  1883. vpaddd 0x160-0x100(%rcx),$xb3,$xb3
  1884. vpunpckldq $xb1,$xb0,$xt2
  1885. vpunpckldq $xb3,$xb2,$xt3
  1886. vpunpckhdq $xb1,$xb0,$xb0
  1887. vpunpckhdq $xb3,$xb2,$xb2
  1888. vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
  1889. vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
  1890. vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
  1891. vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
  1892. ___
  1893. ($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
  1894. $code.=<<___;
  1895. vperm2i128 \$0x20,$xb0,$xa0,$xt3 # "de-interlace" further
  1896. vperm2i128 \$0x31,$xb0,$xa0,$xb0
  1897. vperm2i128 \$0x20,$xb1,$xa1,$xa0
  1898. vperm2i128 \$0x31,$xb1,$xa1,$xb1
  1899. vperm2i128 \$0x20,$xb2,$xa2,$xa1
  1900. vperm2i128 \$0x31,$xb2,$xa2,$xb2
  1901. vperm2i128 \$0x20,$xb3,$xa3,$xa2
  1902. vperm2i128 \$0x31,$xb3,$xa3,$xb3
  1903. ___
  1904. ($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
  1905. my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
  1906. $code.=<<___;
  1907. vmovdqa $xa0,0x00(%rsp) # offload $xaN
  1908. vmovdqa $xa1,0x20(%rsp)
  1909. vmovdqa 0x40(%rsp),$xc2 # $xa0
  1910. vmovdqa 0x60(%rsp),$xc3 # $xa1
  1911. vpaddd 0x180-0x200(%rax),$xc0,$xc0
  1912. vpaddd 0x1a0-0x200(%rax),$xc1,$xc1
  1913. vpaddd 0x1c0-0x200(%rax),$xc2,$xc2
  1914. vpaddd 0x1e0-0x200(%rax),$xc3,$xc3
  1915. vpunpckldq $xc1,$xc0,$xt2
  1916. vpunpckldq $xc3,$xc2,$xt3
  1917. vpunpckhdq $xc1,$xc0,$xc0
  1918. vpunpckhdq $xc3,$xc2,$xc2
  1919. vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
  1920. vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
  1921. vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
  1922. vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
  1923. ___
  1924. ($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
  1925. $code.=<<___;
  1926. vpaddd 0x200-0x200(%rax),$xd0,$xd0
  1927. vpaddd 0x220-0x200(%rax),$xd1,$xd1
  1928. vpaddd 0x240-0x200(%rax),$xd2,$xd2
  1929. vpaddd 0x260-0x200(%rax),$xd3,$xd3
  1930. vpunpckldq $xd1,$xd0,$xt2
  1931. vpunpckldq $xd3,$xd2,$xt3
  1932. vpunpckhdq $xd1,$xd0,$xd0
  1933. vpunpckhdq $xd3,$xd2,$xd2
  1934. vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
  1935. vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
  1936. vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
  1937. vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
  1938. ___
  1939. ($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
  1940. $code.=<<___;
  1941. vperm2i128 \$0x20,$xd0,$xc0,$xt3 # "de-interlace" further
  1942. vperm2i128 \$0x31,$xd0,$xc0,$xd0
  1943. vperm2i128 \$0x20,$xd1,$xc1,$xc0
  1944. vperm2i128 \$0x31,$xd1,$xc1,$xd1
  1945. vperm2i128 \$0x20,$xd2,$xc2,$xc1
  1946. vperm2i128 \$0x31,$xd2,$xc2,$xd2
  1947. vperm2i128 \$0x20,$xd3,$xc3,$xc2
  1948. vperm2i128 \$0x31,$xd3,$xc3,$xd3
  1949. ___
  1950. ($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
  1951. ($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
  1952. ($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
  1953. ($xa0,$xa1)=($xt2,$xt3);
  1954. $code.=<<___;
  1955. vmovdqa 0x00(%rsp),$xa0 # $xaN was offloaded, remember?
  1956. vmovdqa 0x20(%rsp),$xa1
  1957. cmp \$64*8,$len
  1958. jb .Ltail8x
  1959. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  1960. vpxor 0x20($inp),$xb0,$xb0
  1961. vpxor 0x40($inp),$xc0,$xc0
  1962. vpxor 0x60($inp),$xd0,$xd0
  1963. lea 0x80($inp),$inp # size optimization
  1964. vmovdqu $xa0,0x00($out)
  1965. vmovdqu $xb0,0x20($out)
  1966. vmovdqu $xc0,0x40($out)
  1967. vmovdqu $xd0,0x60($out)
  1968. lea 0x80($out),$out # size optimization
  1969. vpxor 0x00($inp),$xa1,$xa1
  1970. vpxor 0x20($inp),$xb1,$xb1
  1971. vpxor 0x40($inp),$xc1,$xc1
  1972. vpxor 0x60($inp),$xd1,$xd1
  1973. lea 0x80($inp),$inp # size optimization
  1974. vmovdqu $xa1,0x00($out)
  1975. vmovdqu $xb1,0x20($out)
  1976. vmovdqu $xc1,0x40($out)
  1977. vmovdqu $xd1,0x60($out)
  1978. lea 0x80($out),$out # size optimization
  1979. vpxor 0x00($inp),$xa2,$xa2
  1980. vpxor 0x20($inp),$xb2,$xb2
  1981. vpxor 0x40($inp),$xc2,$xc2
  1982. vpxor 0x60($inp),$xd2,$xd2
  1983. lea 0x80($inp),$inp # size optimization
  1984. vmovdqu $xa2,0x00($out)
  1985. vmovdqu $xb2,0x20($out)
  1986. vmovdqu $xc2,0x40($out)
  1987. vmovdqu $xd2,0x60($out)
  1988. lea 0x80($out),$out # size optimization
  1989. vpxor 0x00($inp),$xa3,$xa3
  1990. vpxor 0x20($inp),$xb3,$xb3
  1991. vpxor 0x40($inp),$xc3,$xc3
  1992. vpxor 0x60($inp),$xd3,$xd3
  1993. lea 0x80($inp),$inp # size optimization
  1994. vmovdqu $xa3,0x00($out)
  1995. vmovdqu $xb3,0x20($out)
  1996. vmovdqu $xc3,0x40($out)
  1997. vmovdqu $xd3,0x60($out)
  1998. lea 0x80($out),$out # size optimization
  1999. sub \$64*8,$len
  2000. jnz .Loop_outer8x
  2001. jmp .Ldone8x
  2002. .Ltail8x:
  2003. cmp \$448,$len
  2004. jae .L448_or_more8x
  2005. cmp \$384,$len
  2006. jae .L384_or_more8x
  2007. cmp \$320,$len
  2008. jae .L320_or_more8x
  2009. cmp \$256,$len
  2010. jae .L256_or_more8x
  2011. cmp \$192,$len
  2012. jae .L192_or_more8x
  2013. cmp \$128,$len
  2014. jae .L128_or_more8x
  2015. cmp \$64,$len
  2016. jae .L64_or_more8x
  2017. xor %r10,%r10
  2018. vmovdqa $xa0,0x00(%rsp)
  2019. vmovdqa $xb0,0x20(%rsp)
  2020. jmp .Loop_tail8x
  2021. .align 32
  2022. .L64_or_more8x:
  2023. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2024. vpxor 0x20($inp),$xb0,$xb0
  2025. vmovdqu $xa0,0x00($out)
  2026. vmovdqu $xb0,0x20($out)
  2027. je .Ldone8x
  2028. lea 0x40($inp),$inp # inp+=64*1
  2029. xor %r10,%r10
  2030. vmovdqa $xc0,0x00(%rsp)
  2031. lea 0x40($out),$out # out+=64*1
  2032. sub \$64,$len # len-=64*1
  2033. vmovdqa $xd0,0x20(%rsp)
  2034. jmp .Loop_tail8x
  2035. .align 32
  2036. .L128_or_more8x:
  2037. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2038. vpxor 0x20($inp),$xb0,$xb0
  2039. vpxor 0x40($inp),$xc0,$xc0
  2040. vpxor 0x60($inp),$xd0,$xd0
  2041. vmovdqu $xa0,0x00($out)
  2042. vmovdqu $xb0,0x20($out)
  2043. vmovdqu $xc0,0x40($out)
  2044. vmovdqu $xd0,0x60($out)
  2045. je .Ldone8x
  2046. lea 0x80($inp),$inp # inp+=64*2
  2047. xor %r10,%r10
  2048. vmovdqa $xa1,0x00(%rsp)
  2049. lea 0x80($out),$out # out+=64*2
  2050. sub \$128,$len # len-=64*2
  2051. vmovdqa $xb1,0x20(%rsp)
  2052. jmp .Loop_tail8x
  2053. .align 32
  2054. .L192_or_more8x:
  2055. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2056. vpxor 0x20($inp),$xb0,$xb0
  2057. vpxor 0x40($inp),$xc0,$xc0
  2058. vpxor 0x60($inp),$xd0,$xd0
  2059. vpxor 0x80($inp),$xa1,$xa1
  2060. vpxor 0xa0($inp),$xb1,$xb1
  2061. vmovdqu $xa0,0x00($out)
  2062. vmovdqu $xb0,0x20($out)
  2063. vmovdqu $xc0,0x40($out)
  2064. vmovdqu $xd0,0x60($out)
  2065. vmovdqu $xa1,0x80($out)
  2066. vmovdqu $xb1,0xa0($out)
  2067. je .Ldone8x
  2068. lea 0xc0($inp),$inp # inp+=64*3
  2069. xor %r10,%r10
  2070. vmovdqa $xc1,0x00(%rsp)
  2071. lea 0xc0($out),$out # out+=64*3
  2072. sub \$192,$len # len-=64*3
  2073. vmovdqa $xd1,0x20(%rsp)
  2074. jmp .Loop_tail8x
  2075. .align 32
  2076. .L256_or_more8x:
  2077. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2078. vpxor 0x20($inp),$xb0,$xb0
  2079. vpxor 0x40($inp),$xc0,$xc0
  2080. vpxor 0x60($inp),$xd0,$xd0
  2081. vpxor 0x80($inp),$xa1,$xa1
  2082. vpxor 0xa0($inp),$xb1,$xb1
  2083. vpxor 0xc0($inp),$xc1,$xc1
  2084. vpxor 0xe0($inp),$xd1,$xd1
  2085. vmovdqu $xa0,0x00($out)
  2086. vmovdqu $xb0,0x20($out)
  2087. vmovdqu $xc0,0x40($out)
  2088. vmovdqu $xd0,0x60($out)
  2089. vmovdqu $xa1,0x80($out)
  2090. vmovdqu $xb1,0xa0($out)
  2091. vmovdqu $xc1,0xc0($out)
  2092. vmovdqu $xd1,0xe0($out)
  2093. je .Ldone8x
  2094. lea 0x100($inp),$inp # inp+=64*4
  2095. xor %r10,%r10
  2096. vmovdqa $xa2,0x00(%rsp)
  2097. lea 0x100($out),$out # out+=64*4
  2098. sub \$256,$len # len-=64*4
  2099. vmovdqa $xb2,0x20(%rsp)
  2100. jmp .Loop_tail8x
  2101. .align 32
  2102. .L320_or_more8x:
  2103. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2104. vpxor 0x20($inp),$xb0,$xb0
  2105. vpxor 0x40($inp),$xc0,$xc0
  2106. vpxor 0x60($inp),$xd0,$xd0
  2107. vpxor 0x80($inp),$xa1,$xa1
  2108. vpxor 0xa0($inp),$xb1,$xb1
  2109. vpxor 0xc0($inp),$xc1,$xc1
  2110. vpxor 0xe0($inp),$xd1,$xd1
  2111. vpxor 0x100($inp),$xa2,$xa2
  2112. vpxor 0x120($inp),$xb2,$xb2
  2113. vmovdqu $xa0,0x00($out)
  2114. vmovdqu $xb0,0x20($out)
  2115. vmovdqu $xc0,0x40($out)
  2116. vmovdqu $xd0,0x60($out)
  2117. vmovdqu $xa1,0x80($out)
  2118. vmovdqu $xb1,0xa0($out)
  2119. vmovdqu $xc1,0xc0($out)
  2120. vmovdqu $xd1,0xe0($out)
  2121. vmovdqu $xa2,0x100($out)
  2122. vmovdqu $xb2,0x120($out)
  2123. je .Ldone8x
  2124. lea 0x140($inp),$inp # inp+=64*5
  2125. xor %r10,%r10
  2126. vmovdqa $xc2,0x00(%rsp)
  2127. lea 0x140($out),$out # out+=64*5
  2128. sub \$320,$len # len-=64*5
  2129. vmovdqa $xd2,0x20(%rsp)
  2130. jmp .Loop_tail8x
  2131. .align 32
  2132. .L384_or_more8x:
  2133. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2134. vpxor 0x20($inp),$xb0,$xb0
  2135. vpxor 0x40($inp),$xc0,$xc0
  2136. vpxor 0x60($inp),$xd0,$xd0
  2137. vpxor 0x80($inp),$xa1,$xa1
  2138. vpxor 0xa0($inp),$xb1,$xb1
  2139. vpxor 0xc0($inp),$xc1,$xc1
  2140. vpxor 0xe0($inp),$xd1,$xd1
  2141. vpxor 0x100($inp),$xa2,$xa2
  2142. vpxor 0x120($inp),$xb2,$xb2
  2143. vpxor 0x140($inp),$xc2,$xc2
  2144. vpxor 0x160($inp),$xd2,$xd2
  2145. vmovdqu $xa0,0x00($out)
  2146. vmovdqu $xb0,0x20($out)
  2147. vmovdqu $xc0,0x40($out)
  2148. vmovdqu $xd0,0x60($out)
  2149. vmovdqu $xa1,0x80($out)
  2150. vmovdqu $xb1,0xa0($out)
  2151. vmovdqu $xc1,0xc0($out)
  2152. vmovdqu $xd1,0xe0($out)
  2153. vmovdqu $xa2,0x100($out)
  2154. vmovdqu $xb2,0x120($out)
  2155. vmovdqu $xc2,0x140($out)
  2156. vmovdqu $xd2,0x160($out)
  2157. je .Ldone8x
  2158. lea 0x180($inp),$inp # inp+=64*6
  2159. xor %r10,%r10
  2160. vmovdqa $xa3,0x00(%rsp)
  2161. lea 0x180($out),$out # out+=64*6
  2162. sub \$384,$len # len-=64*6
  2163. vmovdqa $xb3,0x20(%rsp)
  2164. jmp .Loop_tail8x
  2165. .align 32
  2166. .L448_or_more8x:
  2167. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  2168. vpxor 0x20($inp),$xb0,$xb0
  2169. vpxor 0x40($inp),$xc0,$xc0
  2170. vpxor 0x60($inp),$xd0,$xd0
  2171. vpxor 0x80($inp),$xa1,$xa1
  2172. vpxor 0xa0($inp),$xb1,$xb1
  2173. vpxor 0xc0($inp),$xc1,$xc1
  2174. vpxor 0xe0($inp),$xd1,$xd1
  2175. vpxor 0x100($inp),$xa2,$xa2
  2176. vpxor 0x120($inp),$xb2,$xb2
  2177. vpxor 0x140($inp),$xc2,$xc2
  2178. vpxor 0x160($inp),$xd2,$xd2
  2179. vpxor 0x180($inp),$xa3,$xa3
  2180. vpxor 0x1a0($inp),$xb3,$xb3
  2181. vmovdqu $xa0,0x00($out)
  2182. vmovdqu $xb0,0x20($out)
  2183. vmovdqu $xc0,0x40($out)
  2184. vmovdqu $xd0,0x60($out)
  2185. vmovdqu $xa1,0x80($out)
  2186. vmovdqu $xb1,0xa0($out)
  2187. vmovdqu $xc1,0xc0($out)
  2188. vmovdqu $xd1,0xe0($out)
  2189. vmovdqu $xa2,0x100($out)
  2190. vmovdqu $xb2,0x120($out)
  2191. vmovdqu $xc2,0x140($out)
  2192. vmovdqu $xd2,0x160($out)
  2193. vmovdqu $xa3,0x180($out)
  2194. vmovdqu $xb3,0x1a0($out)
  2195. je .Ldone8x
  2196. lea 0x1c0($inp),$inp # inp+=64*7
  2197. xor %r10,%r10
  2198. vmovdqa $xc3,0x00(%rsp)
  2199. lea 0x1c0($out),$out # out+=64*7
  2200. sub \$448,$len # len-=64*7
  2201. vmovdqa $xd3,0x20(%rsp)
  2202. .Loop_tail8x:
  2203. movzb ($inp,%r10),%eax
  2204. movzb (%rsp,%r10),%ecx
  2205. lea 1(%r10),%r10
  2206. xor %ecx,%eax
  2207. mov %al,-1($out,%r10)
  2208. dec $len
  2209. jnz .Loop_tail8x
  2210. .Ldone8x:
  2211. vzeroall
  2212. ___
  2213. $code.=<<___ if ($win64);
  2214. movaps -0xa8(%r9),%xmm6
  2215. movaps -0x98(%r9),%xmm7
  2216. movaps -0x88(%r9),%xmm8
  2217. movaps -0x78(%r9),%xmm9
  2218. movaps -0x68(%r9),%xmm10
  2219. movaps -0x58(%r9),%xmm11
  2220. movaps -0x48(%r9),%xmm12
  2221. movaps -0x38(%r9),%xmm13
  2222. movaps -0x28(%r9),%xmm14
  2223. movaps -0x18(%r9),%xmm15
  2224. ___
  2225. $code.=<<___;
  2226. lea (%r9),%rsp
  2227. .cfi_def_cfa_register %rsp
  2228. .L8x_epilogue:
  2229. ret
  2230. .cfi_endproc
  2231. .size ChaCha20_8x,.-ChaCha20_8x
  2232. ___
  2233. }
  2234. ########################################################################
  2235. # AVX512 code paths
  2236. if ($avx>2) {
  2237. # This one handles shorter inputs...
  2238. my ($a,$b,$c,$d, $a_,$b_,$c_,$d_,$fourz) = map("%zmm$_",(0..3,16..20));
  2239. my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
  2240. sub vpxord() # size optimization
  2241. { my $opcode = "vpxor"; # adhere to vpxor when possible
  2242. foreach (@_) {
  2243. if (/%([zy])mm([0-9]+)/ && ($1 eq "z" || $2>=16)) {
  2244. $opcode = "vpxord";
  2245. last;
  2246. }
  2247. }
  2248. $code .= "\t$opcode\t".join(',',reverse @_)."\n";
  2249. }
  2250. sub AVX512ROUND { # critical path is 14 "SIMD ticks" per round
  2251. &vpaddd ($a,$a,$b);
  2252. &vpxord ($d,$d,$a);
  2253. &vprold ($d,$d,16);
  2254. &vpaddd ($c,$c,$d);
  2255. &vpxord ($b,$b,$c);
  2256. &vprold ($b,$b,12);
  2257. &vpaddd ($a,$a,$b);
  2258. &vpxord ($d,$d,$a);
  2259. &vprold ($d,$d,8);
  2260. &vpaddd ($c,$c,$d);
  2261. &vpxord ($b,$b,$c);
  2262. &vprold ($b,$b,7);
  2263. }
  2264. my $xframe = $win64 ? 32+8 : 8;
  2265. $code.=<<___;
  2266. .type ChaCha20_avx512,\@function,5
  2267. .align 32
  2268. ChaCha20_avx512:
  2269. .cfi_startproc
  2270. .LChaCha20_avx512:
  2271. mov %rsp,%r9 # frame pointer
  2272. .cfi_def_cfa_register %r9
  2273. cmp \$512,$len
  2274. ja .LChaCha20_16x
  2275. sub \$64+$xframe,%rsp
  2276. ___
  2277. $code.=<<___ if ($win64);
  2278. movaps %xmm6,-0x28(%r9)
  2279. movaps %xmm7,-0x18(%r9)
  2280. .Lavx512_body:
  2281. ___
  2282. $code.=<<___;
  2283. vbroadcasti32x4 .Lsigma(%rip),$a
  2284. vbroadcasti32x4 ($key),$b
  2285. vbroadcasti32x4 16($key),$c
  2286. vbroadcasti32x4 ($counter),$d
  2287. vmovdqa32 $a,$a_
  2288. vmovdqa32 $b,$b_
  2289. vmovdqa32 $c,$c_
  2290. vpaddd .Lzeroz(%rip),$d,$d
  2291. vmovdqa32 .Lfourz(%rip),$fourz
  2292. mov \$10,$counter # reuse $counter
  2293. vmovdqa32 $d,$d_
  2294. jmp .Loop_avx512
  2295. .align 16
  2296. .Loop_outer_avx512:
  2297. vmovdqa32 $a_,$a
  2298. vmovdqa32 $b_,$b
  2299. vmovdqa32 $c_,$c
  2300. vpaddd $fourz,$d_,$d
  2301. mov \$10,$counter
  2302. vmovdqa32 $d,$d_
  2303. jmp .Loop_avx512
  2304. .align 32
  2305. .Loop_avx512:
  2306. ___
  2307. &AVX512ROUND();
  2308. &vpshufd ($c,$c,0b01001110);
  2309. &vpshufd ($b,$b,0b00111001);
  2310. &vpshufd ($d,$d,0b10010011);
  2311. &AVX512ROUND();
  2312. &vpshufd ($c,$c,0b01001110);
  2313. &vpshufd ($b,$b,0b10010011);
  2314. &vpshufd ($d,$d,0b00111001);
  2315. &dec ($counter);
  2316. &jnz (".Loop_avx512");
  2317. $code.=<<___;
  2318. vpaddd $a_,$a,$a
  2319. vpaddd $b_,$b,$b
  2320. vpaddd $c_,$c,$c
  2321. vpaddd $d_,$d,$d
  2322. sub \$64,$len
  2323. jb .Ltail64_avx512
  2324. vpxor 0x00($inp),%x#$a,$t0 # xor with input
  2325. vpxor 0x10($inp),%x#$b,$t1
  2326. vpxor 0x20($inp),%x#$c,$t2
  2327. vpxor 0x30($inp),%x#$d,$t3
  2328. lea 0x40($inp),$inp # inp+=64
  2329. vmovdqu $t0,0x00($out) # write output
  2330. vmovdqu $t1,0x10($out)
  2331. vmovdqu $t2,0x20($out)
  2332. vmovdqu $t3,0x30($out)
  2333. lea 0x40($out),$out # out+=64
  2334. jz .Ldone_avx512
  2335. vextracti32x4 \$1,$a,$t0
  2336. vextracti32x4 \$1,$b,$t1
  2337. vextracti32x4 \$1,$c,$t2
  2338. vextracti32x4 \$1,$d,$t3
  2339. sub \$64,$len
  2340. jb .Ltail_avx512
  2341. vpxor 0x00($inp),$t0,$t0 # xor with input
  2342. vpxor 0x10($inp),$t1,$t1
  2343. vpxor 0x20($inp),$t2,$t2
  2344. vpxor 0x30($inp),$t3,$t3
  2345. lea 0x40($inp),$inp # inp+=64
  2346. vmovdqu $t0,0x00($out) # write output
  2347. vmovdqu $t1,0x10($out)
  2348. vmovdqu $t2,0x20($out)
  2349. vmovdqu $t3,0x30($out)
  2350. lea 0x40($out),$out # out+=64
  2351. jz .Ldone_avx512
  2352. vextracti32x4 \$2,$a,$t0
  2353. vextracti32x4 \$2,$b,$t1
  2354. vextracti32x4 \$2,$c,$t2
  2355. vextracti32x4 \$2,$d,$t3
  2356. sub \$64,$len
  2357. jb .Ltail_avx512
  2358. vpxor 0x00($inp),$t0,$t0 # xor with input
  2359. vpxor 0x10($inp),$t1,$t1
  2360. vpxor 0x20($inp),$t2,$t2
  2361. vpxor 0x30($inp),$t3,$t3
  2362. lea 0x40($inp),$inp # inp+=64
  2363. vmovdqu $t0,0x00($out) # write output
  2364. vmovdqu $t1,0x10($out)
  2365. vmovdqu $t2,0x20($out)
  2366. vmovdqu $t3,0x30($out)
  2367. lea 0x40($out),$out # out+=64
  2368. jz .Ldone_avx512
  2369. vextracti32x4 \$3,$a,$t0
  2370. vextracti32x4 \$3,$b,$t1
  2371. vextracti32x4 \$3,$c,$t2
  2372. vextracti32x4 \$3,$d,$t3
  2373. sub \$64,$len
  2374. jb .Ltail_avx512
  2375. vpxor 0x00($inp),$t0,$t0 # xor with input
  2376. vpxor 0x10($inp),$t1,$t1
  2377. vpxor 0x20($inp),$t2,$t2
  2378. vpxor 0x30($inp),$t3,$t3
  2379. lea 0x40($inp),$inp # inp+=64
  2380. vmovdqu $t0,0x00($out) # write output
  2381. vmovdqu $t1,0x10($out)
  2382. vmovdqu $t2,0x20($out)
  2383. vmovdqu $t3,0x30($out)
  2384. lea 0x40($out),$out # out+=64
  2385. jnz .Loop_outer_avx512
  2386. jmp .Ldone_avx512
  2387. .align 16
  2388. .Ltail64_avx512:
  2389. vmovdqa %x#$a,0x00(%rsp)
  2390. vmovdqa %x#$b,0x10(%rsp)
  2391. vmovdqa %x#$c,0x20(%rsp)
  2392. vmovdqa %x#$d,0x30(%rsp)
  2393. add \$64,$len
  2394. jmp .Loop_tail_avx512
  2395. .align 16
  2396. .Ltail_avx512:
  2397. vmovdqa $t0,0x00(%rsp)
  2398. vmovdqa $t1,0x10(%rsp)
  2399. vmovdqa $t2,0x20(%rsp)
  2400. vmovdqa $t3,0x30(%rsp)
  2401. add \$64,$len
  2402. .Loop_tail_avx512:
  2403. movzb ($inp,$counter),%eax
  2404. movzb (%rsp,$counter),%ecx
  2405. lea 1($counter),$counter
  2406. xor %ecx,%eax
  2407. mov %al,-1($out,$counter)
  2408. dec $len
  2409. jnz .Loop_tail_avx512
  2410. vmovdqu32 $a_,0x00(%rsp)
  2411. .Ldone_avx512:
  2412. vzeroall
  2413. ___
  2414. $code.=<<___ if ($win64);
  2415. movaps -0x28(%r9),%xmm6
  2416. movaps -0x18(%r9),%xmm7
  2417. ___
  2418. $code.=<<___;
  2419. lea (%r9),%rsp
  2420. .cfi_def_cfa_register %rsp
  2421. .Lavx512_epilogue:
  2422. ret
  2423. .cfi_endproc
  2424. .size ChaCha20_avx512,.-ChaCha20_avx512
  2425. ___
  2426. map(s/%z/%y/, $a,$b,$c,$d, $a_,$b_,$c_,$d_,$fourz);
  2427. $code.=<<___;
  2428. .type ChaCha20_avx512vl,\@function,5
  2429. .align 32
  2430. ChaCha20_avx512vl:
  2431. .cfi_startproc
  2432. .LChaCha20_avx512vl:
  2433. mov %rsp,%r9 # frame pointer
  2434. .cfi_def_cfa_register %r9
  2435. cmp \$128,$len
  2436. ja .LChaCha20_8xvl
  2437. sub \$64+$xframe,%rsp
  2438. ___
  2439. $code.=<<___ if ($win64);
  2440. movaps %xmm6,-0x28(%r9)
  2441. movaps %xmm7,-0x18(%r9)
  2442. .Lavx512vl_body:
  2443. ___
  2444. $code.=<<___;
  2445. vbroadcasti128 .Lsigma(%rip),$a
  2446. vbroadcasti128 ($key),$b
  2447. vbroadcasti128 16($key),$c
  2448. vbroadcasti128 ($counter),$d
  2449. vmovdqa32 $a,$a_
  2450. vmovdqa32 $b,$b_
  2451. vmovdqa32 $c,$c_
  2452. vpaddd .Lzeroz(%rip),$d,$d
  2453. vmovdqa32 .Ltwoy(%rip),$fourz
  2454. mov \$10,$counter # reuse $counter
  2455. vmovdqa32 $d,$d_
  2456. jmp .Loop_avx512vl
  2457. .align 16
  2458. .Loop_outer_avx512vl:
  2459. vmovdqa32 $c_,$c
  2460. vpaddd $fourz,$d_,$d
  2461. mov \$10,$counter
  2462. vmovdqa32 $d,$d_
  2463. jmp .Loop_avx512vl
  2464. .align 32
  2465. .Loop_avx512vl:
  2466. ___
  2467. &AVX512ROUND();
  2468. &vpshufd ($c,$c,0b01001110);
  2469. &vpshufd ($b,$b,0b00111001);
  2470. &vpshufd ($d,$d,0b10010011);
  2471. &AVX512ROUND();
  2472. &vpshufd ($c,$c,0b01001110);
  2473. &vpshufd ($b,$b,0b10010011);
  2474. &vpshufd ($d,$d,0b00111001);
  2475. &dec ($counter);
  2476. &jnz (".Loop_avx512vl");
  2477. $code.=<<___;
  2478. vpaddd $a_,$a,$a
  2479. vpaddd $b_,$b,$b
  2480. vpaddd $c_,$c,$c
  2481. vpaddd $d_,$d,$d
  2482. sub \$64,$len
  2483. jb .Ltail64_avx512vl
  2484. vpxor 0x00($inp),%x#$a,$t0 # xor with input
  2485. vpxor 0x10($inp),%x#$b,$t1
  2486. vpxor 0x20($inp),%x#$c,$t2
  2487. vpxor 0x30($inp),%x#$d,$t3
  2488. lea 0x40($inp),$inp # inp+=64
  2489. vmovdqu $t0,0x00($out) # write output
  2490. vmovdqu $t1,0x10($out)
  2491. vmovdqu $t2,0x20($out)
  2492. vmovdqu $t3,0x30($out)
  2493. lea 0x40($out),$out # out+=64
  2494. jz .Ldone_avx512vl
  2495. vextracti128 \$1,$a,$t0
  2496. vextracti128 \$1,$b,$t1
  2497. vextracti128 \$1,$c,$t2
  2498. vextracti128 \$1,$d,$t3
  2499. sub \$64,$len
  2500. jb .Ltail_avx512vl
  2501. vpxor 0x00($inp),$t0,$t0 # xor with input
  2502. vpxor 0x10($inp),$t1,$t1
  2503. vpxor 0x20($inp),$t2,$t2
  2504. vpxor 0x30($inp),$t3,$t3
  2505. lea 0x40($inp),$inp # inp+=64
  2506. vmovdqu $t0,0x00($out) # write output
  2507. vmovdqu $t1,0x10($out)
  2508. vmovdqu $t2,0x20($out)
  2509. vmovdqu $t3,0x30($out)
  2510. lea 0x40($out),$out # out+=64
  2511. vmovdqa32 $a_,$a
  2512. vmovdqa32 $b_,$b
  2513. jnz .Loop_outer_avx512vl
  2514. jmp .Ldone_avx512vl
  2515. .align 16
  2516. .Ltail64_avx512vl:
  2517. vmovdqa %x#$a,0x00(%rsp)
  2518. vmovdqa %x#$b,0x10(%rsp)
  2519. vmovdqa %x#$c,0x20(%rsp)
  2520. vmovdqa %x#$d,0x30(%rsp)
  2521. add \$64,$len
  2522. jmp .Loop_tail_avx512vl
  2523. .align 16
  2524. .Ltail_avx512vl:
  2525. vmovdqa $t0,0x00(%rsp)
  2526. vmovdqa $t1,0x10(%rsp)
  2527. vmovdqa $t2,0x20(%rsp)
  2528. vmovdqa $t3,0x30(%rsp)
  2529. add \$64,$len
  2530. .Loop_tail_avx512vl:
  2531. movzb ($inp,$counter),%eax
  2532. movzb (%rsp,$counter),%ecx
  2533. lea 1($counter),$counter
  2534. xor %ecx,%eax
  2535. mov %al,-1($out,$counter)
  2536. dec $len
  2537. jnz .Loop_tail_avx512vl
  2538. vmovdqu32 $a_,0x00(%rsp)
  2539. vmovdqu32 $a_,0x20(%rsp)
  2540. .Ldone_avx512vl:
  2541. vzeroall
  2542. ___
  2543. $code.=<<___ if ($win64);
  2544. movaps -0x28(%r9),%xmm6
  2545. movaps -0x18(%r9),%xmm7
  2546. ___
  2547. $code.=<<___;
  2548. lea (%r9),%rsp
  2549. .cfi_def_cfa_register %rsp
  2550. .Lavx512vl_epilogue:
  2551. ret
  2552. .cfi_endproc
  2553. .size ChaCha20_avx512vl,.-ChaCha20_avx512vl
  2554. ___
  2555. }
  2556. if ($avx>2) {
  2557. # This one handles longer inputs...
  2558. my ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  2559. $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3)=map("%zmm$_",(0..15));
  2560. my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  2561. $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3);
  2562. my @key=map("%zmm$_",(16..31));
  2563. my ($xt0,$xt1,$xt2,$xt3)=@key[0..3];
  2564. sub AVX512_lane_ROUND {
  2565. my ($a0,$b0,$c0,$d0)=@_;
  2566. my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
  2567. my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
  2568. my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
  2569. my @x=map("\"$_\"",@xx);
  2570. (
  2571. "&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
  2572. "&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
  2573. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
  2574. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
  2575. "&vpxord (@x[$d0],@x[$d0],@x[$a0])",
  2576. "&vpxord (@x[$d1],@x[$d1],@x[$a1])",
  2577. "&vpxord (@x[$d2],@x[$d2],@x[$a2])",
  2578. "&vpxord (@x[$d3],@x[$d3],@x[$a3])",
  2579. "&vprold (@x[$d0],@x[$d0],16)",
  2580. "&vprold (@x[$d1],@x[$d1],16)",
  2581. "&vprold (@x[$d2],@x[$d2],16)",
  2582. "&vprold (@x[$d3],@x[$d3],16)",
  2583. "&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
  2584. "&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
  2585. "&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
  2586. "&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
  2587. "&vpxord (@x[$b0],@x[$b0],@x[$c0])",
  2588. "&vpxord (@x[$b1],@x[$b1],@x[$c1])",
  2589. "&vpxord (@x[$b2],@x[$b2],@x[$c2])",
  2590. "&vpxord (@x[$b3],@x[$b3],@x[$c3])",
  2591. "&vprold (@x[$b0],@x[$b0],12)",
  2592. "&vprold (@x[$b1],@x[$b1],12)",
  2593. "&vprold (@x[$b2],@x[$b2],12)",
  2594. "&vprold (@x[$b3],@x[$b3],12)",
  2595. "&vpaddd (@x[$a0],@x[$a0],@x[$b0])",
  2596. "&vpaddd (@x[$a1],@x[$a1],@x[$b1])",
  2597. "&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
  2598. "&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
  2599. "&vpxord (@x[$d0],@x[$d0],@x[$a0])",
  2600. "&vpxord (@x[$d1],@x[$d1],@x[$a1])",
  2601. "&vpxord (@x[$d2],@x[$d2],@x[$a2])",
  2602. "&vpxord (@x[$d3],@x[$d3],@x[$a3])",
  2603. "&vprold (@x[$d0],@x[$d0],8)",
  2604. "&vprold (@x[$d1],@x[$d1],8)",
  2605. "&vprold (@x[$d2],@x[$d2],8)",
  2606. "&vprold (@x[$d3],@x[$d3],8)",
  2607. "&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
  2608. "&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
  2609. "&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
  2610. "&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
  2611. "&vpxord (@x[$b0],@x[$b0],@x[$c0])",
  2612. "&vpxord (@x[$b1],@x[$b1],@x[$c1])",
  2613. "&vpxord (@x[$b2],@x[$b2],@x[$c2])",
  2614. "&vpxord (@x[$b3],@x[$b3],@x[$c3])",
  2615. "&vprold (@x[$b0],@x[$b0],7)",
  2616. "&vprold (@x[$b1],@x[$b1],7)",
  2617. "&vprold (@x[$b2],@x[$b2],7)",
  2618. "&vprold (@x[$b3],@x[$b3],7)"
  2619. );
  2620. }
  2621. my $xframe = $win64 ? 0xa8 : 8;
  2622. $code.=<<___;
  2623. .type ChaCha20_16x,\@function,5
  2624. .align 32
  2625. ChaCha20_16x:
  2626. .cfi_startproc
  2627. .LChaCha20_16x:
  2628. mov %rsp,%r9 # frame register
  2629. .cfi_def_cfa_register %r9
  2630. sub \$64+$xframe,%rsp
  2631. and \$-64,%rsp
  2632. ___
  2633. $code.=<<___ if ($win64);
  2634. movaps %xmm6,-0xa8(%r9)
  2635. movaps %xmm7,-0x98(%r9)
  2636. movaps %xmm8,-0x88(%r9)
  2637. movaps %xmm9,-0x78(%r9)
  2638. movaps %xmm10,-0x68(%r9)
  2639. movaps %xmm11,-0x58(%r9)
  2640. movaps %xmm12,-0x48(%r9)
  2641. movaps %xmm13,-0x38(%r9)
  2642. movaps %xmm14,-0x28(%r9)
  2643. movaps %xmm15,-0x18(%r9)
  2644. .L16x_body:
  2645. ___
  2646. $code.=<<___;
  2647. vzeroupper
  2648. lea .Lsigma(%rip),%r10
  2649. vbroadcasti32x4 (%r10),$xa3 # key[0]
  2650. vbroadcasti32x4 ($key),$xb3 # key[1]
  2651. vbroadcasti32x4 16($key),$xc3 # key[2]
  2652. vbroadcasti32x4 ($counter),$xd3 # key[3]
  2653. vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
  2654. vpshufd \$0x55,$xa3,$xa1
  2655. vpshufd \$0xaa,$xa3,$xa2
  2656. vpshufd \$0xff,$xa3,$xa3
  2657. vmovdqa64 $xa0,@key[0]
  2658. vmovdqa64 $xa1,@key[1]
  2659. vmovdqa64 $xa2,@key[2]
  2660. vmovdqa64 $xa3,@key[3]
  2661. vpshufd \$0x00,$xb3,$xb0
  2662. vpshufd \$0x55,$xb3,$xb1
  2663. vpshufd \$0xaa,$xb3,$xb2
  2664. vpshufd \$0xff,$xb3,$xb3
  2665. vmovdqa64 $xb0,@key[4]
  2666. vmovdqa64 $xb1,@key[5]
  2667. vmovdqa64 $xb2,@key[6]
  2668. vmovdqa64 $xb3,@key[7]
  2669. vpshufd \$0x00,$xc3,$xc0
  2670. vpshufd \$0x55,$xc3,$xc1
  2671. vpshufd \$0xaa,$xc3,$xc2
  2672. vpshufd \$0xff,$xc3,$xc3
  2673. vmovdqa64 $xc0,@key[8]
  2674. vmovdqa64 $xc1,@key[9]
  2675. vmovdqa64 $xc2,@key[10]
  2676. vmovdqa64 $xc3,@key[11]
  2677. vpshufd \$0x00,$xd3,$xd0
  2678. vpshufd \$0x55,$xd3,$xd1
  2679. vpshufd \$0xaa,$xd3,$xd2
  2680. vpshufd \$0xff,$xd3,$xd3
  2681. vpaddd .Lincz(%rip),$xd0,$xd0 # don't save counters yet
  2682. vmovdqa64 $xd0,@key[12]
  2683. vmovdqa64 $xd1,@key[13]
  2684. vmovdqa64 $xd2,@key[14]
  2685. vmovdqa64 $xd3,@key[15]
  2686. mov \$10,%eax
  2687. jmp .Loop16x
  2688. .align 32
  2689. .Loop_outer16x:
  2690. vpbroadcastd 0(%r10),$xa0 # reload key
  2691. vpbroadcastd 4(%r10),$xa1
  2692. vpbroadcastd 8(%r10),$xa2
  2693. vpbroadcastd 12(%r10),$xa3
  2694. vpaddd .Lsixteen(%rip),@key[12],@key[12] # next SIMD counters
  2695. vmovdqa64 @key[4],$xb0
  2696. vmovdqa64 @key[5],$xb1
  2697. vmovdqa64 @key[6],$xb2
  2698. vmovdqa64 @key[7],$xb3
  2699. vmovdqa64 @key[8],$xc0
  2700. vmovdqa64 @key[9],$xc1
  2701. vmovdqa64 @key[10],$xc2
  2702. vmovdqa64 @key[11],$xc3
  2703. vmovdqa64 @key[12],$xd0
  2704. vmovdqa64 @key[13],$xd1
  2705. vmovdqa64 @key[14],$xd2
  2706. vmovdqa64 @key[15],$xd3
  2707. vmovdqa64 $xa0,@key[0]
  2708. vmovdqa64 $xa1,@key[1]
  2709. vmovdqa64 $xa2,@key[2]
  2710. vmovdqa64 $xa3,@key[3]
  2711. mov \$10,%eax
  2712. jmp .Loop16x
  2713. .align 32
  2714. .Loop16x:
  2715. ___
  2716. foreach (&AVX512_lane_ROUND(0, 4, 8,12)) { eval; }
  2717. foreach (&AVX512_lane_ROUND(0, 5,10,15)) { eval; }
  2718. $code.=<<___;
  2719. dec %eax
  2720. jnz .Loop16x
  2721. vpaddd @key[0],$xa0,$xa0 # accumulate key
  2722. vpaddd @key[1],$xa1,$xa1
  2723. vpaddd @key[2],$xa2,$xa2
  2724. vpaddd @key[3],$xa3,$xa3
  2725. vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
  2726. vpunpckldq $xa3,$xa2,$xt3
  2727. vpunpckhdq $xa1,$xa0,$xa0
  2728. vpunpckhdq $xa3,$xa2,$xa2
  2729. vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
  2730. vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
  2731. vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
  2732. vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
  2733. ___
  2734. ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
  2735. $code.=<<___;
  2736. vpaddd @key[4],$xb0,$xb0
  2737. vpaddd @key[5],$xb1,$xb1
  2738. vpaddd @key[6],$xb2,$xb2
  2739. vpaddd @key[7],$xb3,$xb3
  2740. vpunpckldq $xb1,$xb0,$xt2
  2741. vpunpckldq $xb3,$xb2,$xt3
  2742. vpunpckhdq $xb1,$xb0,$xb0
  2743. vpunpckhdq $xb3,$xb2,$xb2
  2744. vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
  2745. vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
  2746. vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
  2747. vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
  2748. ___
  2749. ($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
  2750. $code.=<<___;
  2751. vshufi32x4 \$0x44,$xb0,$xa0,$xt3 # "de-interlace" further
  2752. vshufi32x4 \$0xee,$xb0,$xa0,$xb0
  2753. vshufi32x4 \$0x44,$xb1,$xa1,$xa0
  2754. vshufi32x4 \$0xee,$xb1,$xa1,$xb1
  2755. vshufi32x4 \$0x44,$xb2,$xa2,$xa1
  2756. vshufi32x4 \$0xee,$xb2,$xa2,$xb2
  2757. vshufi32x4 \$0x44,$xb3,$xa3,$xa2
  2758. vshufi32x4 \$0xee,$xb3,$xa3,$xb3
  2759. ___
  2760. ($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
  2761. $code.=<<___;
  2762. vpaddd @key[8],$xc0,$xc0
  2763. vpaddd @key[9],$xc1,$xc1
  2764. vpaddd @key[10],$xc2,$xc2
  2765. vpaddd @key[11],$xc3,$xc3
  2766. vpunpckldq $xc1,$xc0,$xt2
  2767. vpunpckldq $xc3,$xc2,$xt3
  2768. vpunpckhdq $xc1,$xc0,$xc0
  2769. vpunpckhdq $xc3,$xc2,$xc2
  2770. vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
  2771. vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
  2772. vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
  2773. vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
  2774. ___
  2775. ($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
  2776. $code.=<<___;
  2777. vpaddd @key[12],$xd0,$xd0
  2778. vpaddd @key[13],$xd1,$xd1
  2779. vpaddd @key[14],$xd2,$xd2
  2780. vpaddd @key[15],$xd3,$xd3
  2781. vpunpckldq $xd1,$xd0,$xt2
  2782. vpunpckldq $xd3,$xd2,$xt3
  2783. vpunpckhdq $xd1,$xd0,$xd0
  2784. vpunpckhdq $xd3,$xd2,$xd2
  2785. vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
  2786. vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
  2787. vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
  2788. vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
  2789. ___
  2790. ($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
  2791. $code.=<<___;
  2792. vshufi32x4 \$0x44,$xd0,$xc0,$xt3 # "de-interlace" further
  2793. vshufi32x4 \$0xee,$xd0,$xc0,$xd0
  2794. vshufi32x4 \$0x44,$xd1,$xc1,$xc0
  2795. vshufi32x4 \$0xee,$xd1,$xc1,$xd1
  2796. vshufi32x4 \$0x44,$xd2,$xc2,$xc1
  2797. vshufi32x4 \$0xee,$xd2,$xc2,$xd2
  2798. vshufi32x4 \$0x44,$xd3,$xc3,$xc2
  2799. vshufi32x4 \$0xee,$xd3,$xc3,$xd3
  2800. ___
  2801. ($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
  2802. $code.=<<___;
  2803. vshufi32x4 \$0x88,$xc0,$xa0,$xt0 # "de-interlace" further
  2804. vshufi32x4 \$0xdd,$xc0,$xa0,$xa0
  2805. vshufi32x4 \$0x88,$xd0,$xb0,$xc0
  2806. vshufi32x4 \$0xdd,$xd0,$xb0,$xd0
  2807. vshufi32x4 \$0x88,$xc1,$xa1,$xt1
  2808. vshufi32x4 \$0xdd,$xc1,$xa1,$xa1
  2809. vshufi32x4 \$0x88,$xd1,$xb1,$xc1
  2810. vshufi32x4 \$0xdd,$xd1,$xb1,$xd1
  2811. vshufi32x4 \$0x88,$xc2,$xa2,$xt2
  2812. vshufi32x4 \$0xdd,$xc2,$xa2,$xa2
  2813. vshufi32x4 \$0x88,$xd2,$xb2,$xc2
  2814. vshufi32x4 \$0xdd,$xd2,$xb2,$xd2
  2815. vshufi32x4 \$0x88,$xc3,$xa3,$xt3
  2816. vshufi32x4 \$0xdd,$xc3,$xa3,$xa3
  2817. vshufi32x4 \$0x88,$xd3,$xb3,$xc3
  2818. vshufi32x4 \$0xdd,$xd3,$xb3,$xd3
  2819. ___
  2820. ($xa0,$xa1,$xa2,$xa3,$xb0,$xb1,$xb2,$xb3)=
  2821. ($xt0,$xt1,$xt2,$xt3,$xa0,$xa1,$xa2,$xa3);
  2822. ($xa0,$xb0,$xc0,$xd0, $xa1,$xb1,$xc1,$xd1,
  2823. $xa2,$xb2,$xc2,$xd2, $xa3,$xb3,$xc3,$xd3) =
  2824. ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  2825. $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3);
  2826. $code.=<<___;
  2827. cmp \$64*16,$len
  2828. jb .Ltail16x
  2829. vpxord 0x00($inp),$xa0,$xa0 # xor with input
  2830. vpxord 0x40($inp),$xb0,$xb0
  2831. vpxord 0x80($inp),$xc0,$xc0
  2832. vpxord 0xc0($inp),$xd0,$xd0
  2833. vmovdqu32 $xa0,0x00($out)
  2834. vmovdqu32 $xb0,0x40($out)
  2835. vmovdqu32 $xc0,0x80($out)
  2836. vmovdqu32 $xd0,0xc0($out)
  2837. vpxord 0x100($inp),$xa1,$xa1
  2838. vpxord 0x140($inp),$xb1,$xb1
  2839. vpxord 0x180($inp),$xc1,$xc1
  2840. vpxord 0x1c0($inp),$xd1,$xd1
  2841. vmovdqu32 $xa1,0x100($out)
  2842. vmovdqu32 $xb1,0x140($out)
  2843. vmovdqu32 $xc1,0x180($out)
  2844. vmovdqu32 $xd1,0x1c0($out)
  2845. vpxord 0x200($inp),$xa2,$xa2
  2846. vpxord 0x240($inp),$xb2,$xb2
  2847. vpxord 0x280($inp),$xc2,$xc2
  2848. vpxord 0x2c0($inp),$xd2,$xd2
  2849. vmovdqu32 $xa2,0x200($out)
  2850. vmovdqu32 $xb2,0x240($out)
  2851. vmovdqu32 $xc2,0x280($out)
  2852. vmovdqu32 $xd2,0x2c0($out)
  2853. vpxord 0x300($inp),$xa3,$xa3
  2854. vpxord 0x340($inp),$xb3,$xb3
  2855. vpxord 0x380($inp),$xc3,$xc3
  2856. vpxord 0x3c0($inp),$xd3,$xd3
  2857. lea 0x400($inp),$inp
  2858. vmovdqu32 $xa3,0x300($out)
  2859. vmovdqu32 $xb3,0x340($out)
  2860. vmovdqu32 $xc3,0x380($out)
  2861. vmovdqu32 $xd3,0x3c0($out)
  2862. lea 0x400($out),$out
  2863. sub \$64*16,$len
  2864. jnz .Loop_outer16x
  2865. jmp .Ldone16x
  2866. .align 32
  2867. .Ltail16x:
  2868. xor %r10,%r10
  2869. sub $inp,$out
  2870. cmp \$64*1,$len
  2871. jb .Less_than_64_16x
  2872. vpxord ($inp),$xa0,$xa0 # xor with input
  2873. vmovdqu32 $xa0,($out,$inp)
  2874. je .Ldone16x
  2875. vmovdqa32 $xb0,$xa0
  2876. lea 64($inp),$inp
  2877. cmp \$64*2,$len
  2878. jb .Less_than_64_16x
  2879. vpxord ($inp),$xb0,$xb0
  2880. vmovdqu32 $xb0,($out,$inp)
  2881. je .Ldone16x
  2882. vmovdqa32 $xc0,$xa0
  2883. lea 64($inp),$inp
  2884. cmp \$64*3,$len
  2885. jb .Less_than_64_16x
  2886. vpxord ($inp),$xc0,$xc0
  2887. vmovdqu32 $xc0,($out,$inp)
  2888. je .Ldone16x
  2889. vmovdqa32 $xd0,$xa0
  2890. lea 64($inp),$inp
  2891. cmp \$64*4,$len
  2892. jb .Less_than_64_16x
  2893. vpxord ($inp),$xd0,$xd0
  2894. vmovdqu32 $xd0,($out,$inp)
  2895. je .Ldone16x
  2896. vmovdqa32 $xa1,$xa0
  2897. lea 64($inp),$inp
  2898. cmp \$64*5,$len
  2899. jb .Less_than_64_16x
  2900. vpxord ($inp),$xa1,$xa1
  2901. vmovdqu32 $xa1,($out,$inp)
  2902. je .Ldone16x
  2903. vmovdqa32 $xb1,$xa0
  2904. lea 64($inp),$inp
  2905. cmp \$64*6,$len
  2906. jb .Less_than_64_16x
  2907. vpxord ($inp),$xb1,$xb1
  2908. vmovdqu32 $xb1,($out,$inp)
  2909. je .Ldone16x
  2910. vmovdqa32 $xc1,$xa0
  2911. lea 64($inp),$inp
  2912. cmp \$64*7,$len
  2913. jb .Less_than_64_16x
  2914. vpxord ($inp),$xc1,$xc1
  2915. vmovdqu32 $xc1,($out,$inp)
  2916. je .Ldone16x
  2917. vmovdqa32 $xd1,$xa0
  2918. lea 64($inp),$inp
  2919. cmp \$64*8,$len
  2920. jb .Less_than_64_16x
  2921. vpxord ($inp),$xd1,$xd1
  2922. vmovdqu32 $xd1,($out,$inp)
  2923. je .Ldone16x
  2924. vmovdqa32 $xa2,$xa0
  2925. lea 64($inp),$inp
  2926. cmp \$64*9,$len
  2927. jb .Less_than_64_16x
  2928. vpxord ($inp),$xa2,$xa2
  2929. vmovdqu32 $xa2,($out,$inp)
  2930. je .Ldone16x
  2931. vmovdqa32 $xb2,$xa0
  2932. lea 64($inp),$inp
  2933. cmp \$64*10,$len
  2934. jb .Less_than_64_16x
  2935. vpxord ($inp),$xb2,$xb2
  2936. vmovdqu32 $xb2,($out,$inp)
  2937. je .Ldone16x
  2938. vmovdqa32 $xc2,$xa0
  2939. lea 64($inp),$inp
  2940. cmp \$64*11,$len
  2941. jb .Less_than_64_16x
  2942. vpxord ($inp),$xc2,$xc2
  2943. vmovdqu32 $xc2,($out,$inp)
  2944. je .Ldone16x
  2945. vmovdqa32 $xd2,$xa0
  2946. lea 64($inp),$inp
  2947. cmp \$64*12,$len
  2948. jb .Less_than_64_16x
  2949. vpxord ($inp),$xd2,$xd2
  2950. vmovdqu32 $xd2,($out,$inp)
  2951. je .Ldone16x
  2952. vmovdqa32 $xa3,$xa0
  2953. lea 64($inp),$inp
  2954. cmp \$64*13,$len
  2955. jb .Less_than_64_16x
  2956. vpxord ($inp),$xa3,$xa3
  2957. vmovdqu32 $xa3,($out,$inp)
  2958. je .Ldone16x
  2959. vmovdqa32 $xb3,$xa0
  2960. lea 64($inp),$inp
  2961. cmp \$64*14,$len
  2962. jb .Less_than_64_16x
  2963. vpxord ($inp),$xb3,$xb3
  2964. vmovdqu32 $xb3,($out,$inp)
  2965. je .Ldone16x
  2966. vmovdqa32 $xc3,$xa0
  2967. lea 64($inp),$inp
  2968. cmp \$64*15,$len
  2969. jb .Less_than_64_16x
  2970. vpxord ($inp),$xc3,$xc3
  2971. vmovdqu32 $xc3,($out,$inp)
  2972. je .Ldone16x
  2973. vmovdqa32 $xd3,$xa0
  2974. lea 64($inp),$inp
  2975. .Less_than_64_16x:
  2976. vmovdqa32 $xa0,0x00(%rsp)
  2977. lea ($out,$inp),$out
  2978. and \$63,$len
  2979. .Loop_tail16x:
  2980. movzb ($inp,%r10),%eax
  2981. movzb (%rsp,%r10),%ecx
  2982. lea 1(%r10),%r10
  2983. xor %ecx,%eax
  2984. mov %al,-1($out,%r10)
  2985. dec $len
  2986. jnz .Loop_tail16x
  2987. vpxord $xa0,$xa0,$xa0
  2988. vmovdqa32 $xa0,0(%rsp)
  2989. .Ldone16x:
  2990. vzeroall
  2991. ___
  2992. $code.=<<___ if ($win64);
  2993. movaps -0xa8(%r9),%xmm6
  2994. movaps -0x98(%r9),%xmm7
  2995. movaps -0x88(%r9),%xmm8
  2996. movaps -0x78(%r9),%xmm9
  2997. movaps -0x68(%r9),%xmm10
  2998. movaps -0x58(%r9),%xmm11
  2999. movaps -0x48(%r9),%xmm12
  3000. movaps -0x38(%r9),%xmm13
  3001. movaps -0x28(%r9),%xmm14
  3002. movaps -0x18(%r9),%xmm15
  3003. ___
  3004. $code.=<<___;
  3005. lea (%r9),%rsp
  3006. .cfi_def_cfa_register %rsp
  3007. .L16x_epilogue:
  3008. ret
  3009. .cfi_endproc
  3010. .size ChaCha20_16x,.-ChaCha20_16x
  3011. ___
  3012. # switch to %ymm domain
  3013. ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  3014. $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3)=map("%ymm$_",(0..15));
  3015. @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
  3016. $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3);
  3017. @key=map("%ymm$_",(16..31));
  3018. ($xt0,$xt1,$xt2,$xt3)=@key[0..3];
  3019. $code.=<<___;
  3020. .type ChaCha20_8xvl,\@function,5
  3021. .align 32
  3022. ChaCha20_8xvl:
  3023. .cfi_startproc
  3024. .LChaCha20_8xvl:
  3025. mov %rsp,%r9 # frame register
  3026. .cfi_def_cfa_register %r9
  3027. sub \$64+$xframe,%rsp
  3028. and \$-64,%rsp
  3029. ___
  3030. $code.=<<___ if ($win64);
  3031. movaps %xmm6,-0xa8(%r9)
  3032. movaps %xmm7,-0x98(%r9)
  3033. movaps %xmm8,-0x88(%r9)
  3034. movaps %xmm9,-0x78(%r9)
  3035. movaps %xmm10,-0x68(%r9)
  3036. movaps %xmm11,-0x58(%r9)
  3037. movaps %xmm12,-0x48(%r9)
  3038. movaps %xmm13,-0x38(%r9)
  3039. movaps %xmm14,-0x28(%r9)
  3040. movaps %xmm15,-0x18(%r9)
  3041. .L8xvl_body:
  3042. ___
  3043. $code.=<<___;
  3044. vzeroupper
  3045. lea .Lsigma(%rip),%r10
  3046. vbroadcasti128 (%r10),$xa3 # key[0]
  3047. vbroadcasti128 ($key),$xb3 # key[1]
  3048. vbroadcasti128 16($key),$xc3 # key[2]
  3049. vbroadcasti128 ($counter),$xd3 # key[3]
  3050. vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
  3051. vpshufd \$0x55,$xa3,$xa1
  3052. vpshufd \$0xaa,$xa3,$xa2
  3053. vpshufd \$0xff,$xa3,$xa3
  3054. vmovdqa64 $xa0,@key[0]
  3055. vmovdqa64 $xa1,@key[1]
  3056. vmovdqa64 $xa2,@key[2]
  3057. vmovdqa64 $xa3,@key[3]
  3058. vpshufd \$0x00,$xb3,$xb0
  3059. vpshufd \$0x55,$xb3,$xb1
  3060. vpshufd \$0xaa,$xb3,$xb2
  3061. vpshufd \$0xff,$xb3,$xb3
  3062. vmovdqa64 $xb0,@key[4]
  3063. vmovdqa64 $xb1,@key[5]
  3064. vmovdqa64 $xb2,@key[6]
  3065. vmovdqa64 $xb3,@key[7]
  3066. vpshufd \$0x00,$xc3,$xc0
  3067. vpshufd \$0x55,$xc3,$xc1
  3068. vpshufd \$0xaa,$xc3,$xc2
  3069. vpshufd \$0xff,$xc3,$xc3
  3070. vmovdqa64 $xc0,@key[8]
  3071. vmovdqa64 $xc1,@key[9]
  3072. vmovdqa64 $xc2,@key[10]
  3073. vmovdqa64 $xc3,@key[11]
  3074. vpshufd \$0x00,$xd3,$xd0
  3075. vpshufd \$0x55,$xd3,$xd1
  3076. vpshufd \$0xaa,$xd3,$xd2
  3077. vpshufd \$0xff,$xd3,$xd3
  3078. vpaddd .Lincy(%rip),$xd0,$xd0 # don't save counters yet
  3079. vmovdqa64 $xd0,@key[12]
  3080. vmovdqa64 $xd1,@key[13]
  3081. vmovdqa64 $xd2,@key[14]
  3082. vmovdqa64 $xd3,@key[15]
  3083. mov \$10,%eax
  3084. jmp .Loop8xvl
  3085. .align 32
  3086. .Loop_outer8xvl:
  3087. #vpbroadcastd 0(%r10),$xa0 # reload key
  3088. #vpbroadcastd 4(%r10),$xa1
  3089. vpbroadcastd 8(%r10),$xa2
  3090. vpbroadcastd 12(%r10),$xa3
  3091. vpaddd .Leight(%rip),@key[12],@key[12] # next SIMD counters
  3092. vmovdqa64 @key[4],$xb0
  3093. vmovdqa64 @key[5],$xb1
  3094. vmovdqa64 @key[6],$xb2
  3095. vmovdqa64 @key[7],$xb3
  3096. vmovdqa64 @key[8],$xc0
  3097. vmovdqa64 @key[9],$xc1
  3098. vmovdqa64 @key[10],$xc2
  3099. vmovdqa64 @key[11],$xc3
  3100. vmovdqa64 @key[12],$xd0
  3101. vmovdqa64 @key[13],$xd1
  3102. vmovdqa64 @key[14],$xd2
  3103. vmovdqa64 @key[15],$xd3
  3104. vmovdqa64 $xa0,@key[0]
  3105. vmovdqa64 $xa1,@key[1]
  3106. vmovdqa64 $xa2,@key[2]
  3107. vmovdqa64 $xa3,@key[3]
  3108. mov \$10,%eax
  3109. jmp .Loop8xvl
  3110. .align 32
  3111. .Loop8xvl:
  3112. ___
  3113. foreach (&AVX512_lane_ROUND(0, 4, 8,12)) { eval; }
  3114. foreach (&AVX512_lane_ROUND(0, 5,10,15)) { eval; }
  3115. $code.=<<___;
  3116. dec %eax
  3117. jnz .Loop8xvl
  3118. vpaddd @key[0],$xa0,$xa0 # accumulate key
  3119. vpaddd @key[1],$xa1,$xa1
  3120. vpaddd @key[2],$xa2,$xa2
  3121. vpaddd @key[3],$xa3,$xa3
  3122. vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
  3123. vpunpckldq $xa3,$xa2,$xt3
  3124. vpunpckhdq $xa1,$xa0,$xa0
  3125. vpunpckhdq $xa3,$xa2,$xa2
  3126. vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
  3127. vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
  3128. vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
  3129. vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
  3130. ___
  3131. ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
  3132. $code.=<<___;
  3133. vpaddd @key[4],$xb0,$xb0
  3134. vpaddd @key[5],$xb1,$xb1
  3135. vpaddd @key[6],$xb2,$xb2
  3136. vpaddd @key[7],$xb3,$xb3
  3137. vpunpckldq $xb1,$xb0,$xt2
  3138. vpunpckldq $xb3,$xb2,$xt3
  3139. vpunpckhdq $xb1,$xb0,$xb0
  3140. vpunpckhdq $xb3,$xb2,$xb2
  3141. vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
  3142. vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
  3143. vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
  3144. vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
  3145. ___
  3146. ($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
  3147. $code.=<<___;
  3148. vshufi32x4 \$0,$xb0,$xa0,$xt3 # "de-interlace" further
  3149. vshufi32x4 \$3,$xb0,$xa0,$xb0
  3150. vshufi32x4 \$0,$xb1,$xa1,$xa0
  3151. vshufi32x4 \$3,$xb1,$xa1,$xb1
  3152. vshufi32x4 \$0,$xb2,$xa2,$xa1
  3153. vshufi32x4 \$3,$xb2,$xa2,$xb2
  3154. vshufi32x4 \$0,$xb3,$xa3,$xa2
  3155. vshufi32x4 \$3,$xb3,$xa3,$xb3
  3156. ___
  3157. ($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
  3158. $code.=<<___;
  3159. vpaddd @key[8],$xc0,$xc0
  3160. vpaddd @key[9],$xc1,$xc1
  3161. vpaddd @key[10],$xc2,$xc2
  3162. vpaddd @key[11],$xc3,$xc3
  3163. vpunpckldq $xc1,$xc0,$xt2
  3164. vpunpckldq $xc3,$xc2,$xt3
  3165. vpunpckhdq $xc1,$xc0,$xc0
  3166. vpunpckhdq $xc3,$xc2,$xc2
  3167. vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
  3168. vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
  3169. vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
  3170. vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
  3171. ___
  3172. ($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
  3173. $code.=<<___;
  3174. vpaddd @key[12],$xd0,$xd0
  3175. vpaddd @key[13],$xd1,$xd1
  3176. vpaddd @key[14],$xd2,$xd2
  3177. vpaddd @key[15],$xd3,$xd3
  3178. vpunpckldq $xd1,$xd0,$xt2
  3179. vpunpckldq $xd3,$xd2,$xt3
  3180. vpunpckhdq $xd1,$xd0,$xd0
  3181. vpunpckhdq $xd3,$xd2,$xd2
  3182. vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
  3183. vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
  3184. vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
  3185. vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
  3186. ___
  3187. ($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
  3188. $code.=<<___;
  3189. vperm2i128 \$0x20,$xd0,$xc0,$xt3 # "de-interlace" further
  3190. vperm2i128 \$0x31,$xd0,$xc0,$xd0
  3191. vperm2i128 \$0x20,$xd1,$xc1,$xc0
  3192. vperm2i128 \$0x31,$xd1,$xc1,$xd1
  3193. vperm2i128 \$0x20,$xd2,$xc2,$xc1
  3194. vperm2i128 \$0x31,$xd2,$xc2,$xd2
  3195. vperm2i128 \$0x20,$xd3,$xc3,$xc2
  3196. vperm2i128 \$0x31,$xd3,$xc3,$xd3
  3197. ___
  3198. ($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
  3199. ($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
  3200. ($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
  3201. $code.=<<___;
  3202. cmp \$64*8,$len
  3203. jb .Ltail8xvl
  3204. mov \$0x80,%eax # size optimization
  3205. vpxord 0x00($inp),$xa0,$xa0 # xor with input
  3206. vpxor 0x20($inp),$xb0,$xb0
  3207. vpxor 0x40($inp),$xc0,$xc0
  3208. vpxor 0x60($inp),$xd0,$xd0
  3209. lea ($inp,%rax),$inp # size optimization
  3210. vmovdqu32 $xa0,0x00($out)
  3211. vmovdqu $xb0,0x20($out)
  3212. vmovdqu $xc0,0x40($out)
  3213. vmovdqu $xd0,0x60($out)
  3214. lea ($out,%rax),$out # size optimization
  3215. vpxor 0x00($inp),$xa1,$xa1
  3216. vpxor 0x20($inp),$xb1,$xb1
  3217. vpxor 0x40($inp),$xc1,$xc1
  3218. vpxor 0x60($inp),$xd1,$xd1
  3219. lea ($inp,%rax),$inp # size optimization
  3220. vmovdqu $xa1,0x00($out)
  3221. vmovdqu $xb1,0x20($out)
  3222. vmovdqu $xc1,0x40($out)
  3223. vmovdqu $xd1,0x60($out)
  3224. lea ($out,%rax),$out # size optimization
  3225. vpxord 0x00($inp),$xa2,$xa2
  3226. vpxor 0x20($inp),$xb2,$xb2
  3227. vpxor 0x40($inp),$xc2,$xc2
  3228. vpxor 0x60($inp),$xd2,$xd2
  3229. lea ($inp,%rax),$inp # size optimization
  3230. vmovdqu32 $xa2,0x00($out)
  3231. vmovdqu $xb2,0x20($out)
  3232. vmovdqu $xc2,0x40($out)
  3233. vmovdqu $xd2,0x60($out)
  3234. lea ($out,%rax),$out # size optimization
  3235. vpxor 0x00($inp),$xa3,$xa3
  3236. vpxor 0x20($inp),$xb3,$xb3
  3237. vpxor 0x40($inp),$xc3,$xc3
  3238. vpxor 0x60($inp),$xd3,$xd3
  3239. lea ($inp,%rax),$inp # size optimization
  3240. vmovdqu $xa3,0x00($out)
  3241. vmovdqu $xb3,0x20($out)
  3242. vmovdqu $xc3,0x40($out)
  3243. vmovdqu $xd3,0x60($out)
  3244. lea ($out,%rax),$out # size optimization
  3245. vpbroadcastd 0(%r10),%ymm0 # reload key
  3246. vpbroadcastd 4(%r10),%ymm1
  3247. sub \$64*8,$len
  3248. jnz .Loop_outer8xvl
  3249. jmp .Ldone8xvl
  3250. .align 32
  3251. .Ltail8xvl:
  3252. vmovdqa64 $xa0,%ymm8 # size optimization
  3253. ___
  3254. $xa0 = "%ymm8";
  3255. $code.=<<___;
  3256. xor %r10,%r10
  3257. sub $inp,$out
  3258. cmp \$64*1,$len
  3259. jb .Less_than_64_8xvl
  3260. vpxor 0x00($inp),$xa0,$xa0 # xor with input
  3261. vpxor 0x20($inp),$xb0,$xb0
  3262. vmovdqu $xa0,0x00($out,$inp)
  3263. vmovdqu $xb0,0x20($out,$inp)
  3264. je .Ldone8xvl
  3265. vmovdqa $xc0,$xa0
  3266. vmovdqa $xd0,$xb0
  3267. lea 64($inp),$inp
  3268. cmp \$64*2,$len
  3269. jb .Less_than_64_8xvl
  3270. vpxor 0x00($inp),$xc0,$xc0
  3271. vpxor 0x20($inp),$xd0,$xd0
  3272. vmovdqu $xc0,0x00($out,$inp)
  3273. vmovdqu $xd0,0x20($out,$inp)
  3274. je .Ldone8xvl
  3275. vmovdqa $xa1,$xa0
  3276. vmovdqa $xb1,$xb0
  3277. lea 64($inp),$inp
  3278. cmp \$64*3,$len
  3279. jb .Less_than_64_8xvl
  3280. vpxor 0x00($inp),$xa1,$xa1
  3281. vpxor 0x20($inp),$xb1,$xb1
  3282. vmovdqu $xa1,0x00($out,$inp)
  3283. vmovdqu $xb1,0x20($out,$inp)
  3284. je .Ldone8xvl
  3285. vmovdqa $xc1,$xa0
  3286. vmovdqa $xd1,$xb0
  3287. lea 64($inp),$inp
  3288. cmp \$64*4,$len
  3289. jb .Less_than_64_8xvl
  3290. vpxor 0x00($inp),$xc1,$xc1
  3291. vpxor 0x20($inp),$xd1,$xd1
  3292. vmovdqu $xc1,0x00($out,$inp)
  3293. vmovdqu $xd1,0x20($out,$inp)
  3294. je .Ldone8xvl
  3295. vmovdqa32 $xa2,$xa0
  3296. vmovdqa $xb2,$xb0
  3297. lea 64($inp),$inp
  3298. cmp \$64*5,$len
  3299. jb .Less_than_64_8xvl
  3300. vpxord 0x00($inp),$xa2,$xa2
  3301. vpxor 0x20($inp),$xb2,$xb2
  3302. vmovdqu32 $xa2,0x00($out,$inp)
  3303. vmovdqu $xb2,0x20($out,$inp)
  3304. je .Ldone8xvl
  3305. vmovdqa $xc2,$xa0
  3306. vmovdqa $xd2,$xb0
  3307. lea 64($inp),$inp
  3308. cmp \$64*6,$len
  3309. jb .Less_than_64_8xvl
  3310. vpxor 0x00($inp),$xc2,$xc2
  3311. vpxor 0x20($inp),$xd2,$xd2
  3312. vmovdqu $xc2,0x00($out,$inp)
  3313. vmovdqu $xd2,0x20($out,$inp)
  3314. je .Ldone8xvl
  3315. vmovdqa $xa3,$xa0
  3316. vmovdqa $xb3,$xb0
  3317. lea 64($inp),$inp
  3318. cmp \$64*7,$len
  3319. jb .Less_than_64_8xvl
  3320. vpxor 0x00($inp),$xa3,$xa3
  3321. vpxor 0x20($inp),$xb3,$xb3
  3322. vmovdqu $xa3,0x00($out,$inp)
  3323. vmovdqu $xb3,0x20($out,$inp)
  3324. je .Ldone8xvl
  3325. vmovdqa $xc3,$xa0
  3326. vmovdqa $xd3,$xb0
  3327. lea 64($inp),$inp
  3328. .Less_than_64_8xvl:
  3329. vmovdqa $xa0,0x00(%rsp)
  3330. vmovdqa $xb0,0x20(%rsp)
  3331. lea ($out,$inp),$out
  3332. and \$63,$len
  3333. .Loop_tail8xvl:
  3334. movzb ($inp,%r10),%eax
  3335. movzb (%rsp,%r10),%ecx
  3336. lea 1(%r10),%r10
  3337. xor %ecx,%eax
  3338. mov %al,-1($out,%r10)
  3339. dec $len
  3340. jnz .Loop_tail8xvl
  3341. vpxor $xa0,$xa0,$xa0
  3342. vmovdqa $xa0,0x00(%rsp)
  3343. vmovdqa $xa0,0x20(%rsp)
  3344. .Ldone8xvl:
  3345. vzeroall
  3346. ___
  3347. $code.=<<___ if ($win64);
  3348. movaps -0xa8(%r9),%xmm6
  3349. movaps -0x98(%r9),%xmm7
  3350. movaps -0x88(%r9),%xmm8
  3351. movaps -0x78(%r9),%xmm9
  3352. movaps -0x68(%r9),%xmm10
  3353. movaps -0x58(%r9),%xmm11
  3354. movaps -0x48(%r9),%xmm12
  3355. movaps -0x38(%r9),%xmm13
  3356. movaps -0x28(%r9),%xmm14
  3357. movaps -0x18(%r9),%xmm15
  3358. ___
  3359. $code.=<<___;
  3360. lea (%r9),%rsp
  3361. .cfi_def_cfa_register %rsp
  3362. .L8xvl_epilogue:
  3363. ret
  3364. .cfi_endproc
  3365. .size ChaCha20_8xvl,.-ChaCha20_8xvl
  3366. ___
  3367. }
  3368. # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
  3369. # CONTEXT *context,DISPATCHER_CONTEXT *disp)
  3370. if ($win64) {
  3371. $rec="%rcx";
  3372. $frame="%rdx";
  3373. $context="%r8";
  3374. $disp="%r9";
  3375. $code.=<<___;
  3376. .extern __imp_RtlVirtualUnwind
  3377. .type se_handler,\@abi-omnipotent
  3378. .align 16
  3379. se_handler:
  3380. push %rsi
  3381. push %rdi
  3382. push %rbx
  3383. push %rbp
  3384. push %r12
  3385. push %r13
  3386. push %r14
  3387. push %r15
  3388. pushfq
  3389. sub \$64,%rsp
  3390. mov 120($context),%rax # pull context->Rax
  3391. mov 248($context),%rbx # pull context->Rip
  3392. mov 8($disp),%rsi # disp->ImageBase
  3393. mov 56($disp),%r11 # disp->HandlerData
  3394. lea .Lctr32_body(%rip),%r10
  3395. cmp %r10,%rbx # context->Rip<.Lprologue
  3396. jb .Lcommon_seh_tail
  3397. mov 152($context),%rax # pull context->Rsp
  3398. lea .Lno_data(%rip),%r10 # epilogue label
  3399. cmp %r10,%rbx # context->Rip>=.Lepilogue
  3400. jae .Lcommon_seh_tail
  3401. lea 64+24+48(%rax),%rax
  3402. mov -8(%rax),%rbx
  3403. mov -16(%rax),%rbp
  3404. mov -24(%rax),%r12
  3405. mov -32(%rax),%r13
  3406. mov -40(%rax),%r14
  3407. mov -48(%rax),%r15
  3408. mov %rbx,144($context) # restore context->Rbx
  3409. mov %rbp,160($context) # restore context->Rbp
  3410. mov %r12,216($context) # restore context->R12
  3411. mov %r13,224($context) # restore context->R13
  3412. mov %r14,232($context) # restore context->R14
  3413. mov %r15,240($context) # restore context->R14
  3414. .Lcommon_seh_tail:
  3415. mov 8(%rax),%rdi
  3416. mov 16(%rax),%rsi
  3417. mov %rax,152($context) # restore context->Rsp
  3418. mov %rsi,168($context) # restore context->Rsi
  3419. mov %rdi,176($context) # restore context->Rdi
  3420. mov 40($disp),%rdi # disp->ContextRecord
  3421. mov $context,%rsi # context
  3422. mov \$154,%ecx # sizeof(CONTEXT)
  3423. .long 0xa548f3fc # cld; rep movsq
  3424. mov $disp,%rsi
  3425. xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
  3426. mov 8(%rsi),%rdx # arg2, disp->ImageBase
  3427. mov 0(%rsi),%r8 # arg3, disp->ControlPc
  3428. mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
  3429. mov 40(%rsi),%r10 # disp->ContextRecord
  3430. lea 56(%rsi),%r11 # &disp->HandlerData
  3431. lea 24(%rsi),%r12 # &disp->EstablisherFrame
  3432. mov %r10,32(%rsp) # arg5
  3433. mov %r11,40(%rsp) # arg6
  3434. mov %r12,48(%rsp) # arg7
  3435. mov %rcx,56(%rsp) # arg8, (NULL)
  3436. call *__imp_RtlVirtualUnwind(%rip)
  3437. mov \$1,%eax # ExceptionContinueSearch
  3438. add \$64,%rsp
  3439. popfq
  3440. pop %r15
  3441. pop %r14
  3442. pop %r13
  3443. pop %r12
  3444. pop %rbp
  3445. pop %rbx
  3446. pop %rdi
  3447. pop %rsi
  3448. ret
  3449. .size se_handler,.-se_handler
  3450. .type simd_handler,\@abi-omnipotent
  3451. .align 16
  3452. simd_handler:
  3453. push %rsi
  3454. push %rdi
  3455. push %rbx
  3456. push %rbp
  3457. push %r12
  3458. push %r13
  3459. push %r14
  3460. push %r15
  3461. pushfq
  3462. sub \$64,%rsp
  3463. mov 120($context),%rax # pull context->Rax
  3464. mov 248($context),%rbx # pull context->Rip
  3465. mov 8($disp),%rsi # disp->ImageBase
  3466. mov 56($disp),%r11 # disp->HandlerData
  3467. mov 0(%r11),%r10d # HandlerData[0]
  3468. lea (%rsi,%r10),%r10 # prologue label
  3469. cmp %r10,%rbx # context->Rip<prologue label
  3470. jb .Lcommon_seh_tail
  3471. mov 192($context),%rax # pull context->R9
  3472. mov 4(%r11),%r10d # HandlerData[1]
  3473. mov 8(%r11),%ecx # HandlerData[2]
  3474. lea (%rsi,%r10),%r10 # epilogue label
  3475. cmp %r10,%rbx # context->Rip>=epilogue label
  3476. jae .Lcommon_seh_tail
  3477. neg %rcx
  3478. lea -8(%rax,%rcx),%rsi
  3479. lea 512($context),%rdi # &context.Xmm6
  3480. neg %ecx
  3481. shr \$3,%ecx
  3482. .long 0xa548f3fc # cld; rep movsq
  3483. jmp .Lcommon_seh_tail
  3484. .size simd_handler,.-simd_handler
  3485. .section .pdata
  3486. .align 4
  3487. .rva .LSEH_begin_ChaCha20_ctr32
  3488. .rva .LSEH_end_ChaCha20_ctr32
  3489. .rva .LSEH_info_ChaCha20_ctr32
  3490. .rva .LSEH_begin_ChaCha20_ssse3
  3491. .rva .LSEH_end_ChaCha20_ssse3
  3492. .rva .LSEH_info_ChaCha20_ssse3
  3493. .rva .LSEH_begin_ChaCha20_128
  3494. .rva .LSEH_end_ChaCha20_128
  3495. .rva .LSEH_info_ChaCha20_128
  3496. .rva .LSEH_begin_ChaCha20_4x
  3497. .rva .LSEH_end_ChaCha20_4x
  3498. .rva .LSEH_info_ChaCha20_4x
  3499. ___
  3500. $code.=<<___ if ($avx);
  3501. .rva .LSEH_begin_ChaCha20_4xop
  3502. .rva .LSEH_end_ChaCha20_4xop
  3503. .rva .LSEH_info_ChaCha20_4xop
  3504. ___
  3505. $code.=<<___ if ($avx>1);
  3506. .rva .LSEH_begin_ChaCha20_8x
  3507. .rva .LSEH_end_ChaCha20_8x
  3508. .rva .LSEH_info_ChaCha20_8x
  3509. ___
  3510. $code.=<<___ if ($avx>2);
  3511. .rva .LSEH_begin_ChaCha20_avx512
  3512. .rva .LSEH_end_ChaCha20_avx512
  3513. .rva .LSEH_info_ChaCha20_avx512
  3514. .rva .LSEH_begin_ChaCha20_avx512vl
  3515. .rva .LSEH_end_ChaCha20_avx512vl
  3516. .rva .LSEH_info_ChaCha20_avx512vl
  3517. .rva .LSEH_begin_ChaCha20_16x
  3518. .rva .LSEH_end_ChaCha20_16x
  3519. .rva .LSEH_info_ChaCha20_16x
  3520. .rva .LSEH_begin_ChaCha20_8xvl
  3521. .rva .LSEH_end_ChaCha20_8xvl
  3522. .rva .LSEH_info_ChaCha20_8xvl
  3523. ___
  3524. $code.=<<___;
  3525. .section .xdata
  3526. .align 8
  3527. .LSEH_info_ChaCha20_ctr32:
  3528. .byte 9,0,0,0
  3529. .rva se_handler
  3530. .LSEH_info_ChaCha20_ssse3:
  3531. .byte 9,0,0,0
  3532. .rva simd_handler
  3533. .rva .Lssse3_body,.Lssse3_epilogue
  3534. .long 0x20,0
  3535. .LSEH_info_ChaCha20_128:
  3536. .byte 9,0,0,0
  3537. .rva simd_handler
  3538. .rva .L128_body,.L128_epilogue
  3539. .long 0x60,0
  3540. .LSEH_info_ChaCha20_4x:
  3541. .byte 9,0,0,0
  3542. .rva simd_handler
  3543. .rva .L4x_body,.L4x_epilogue
  3544. .long 0xa0,0
  3545. ___
  3546. $code.=<<___ if ($avx);
  3547. .LSEH_info_ChaCha20_4xop:
  3548. .byte 9,0,0,0
  3549. .rva simd_handler
  3550. .rva .L4xop_body,.L4xop_epilogue # HandlerData[]
  3551. .long 0xa0,0
  3552. ___
  3553. $code.=<<___ if ($avx>1);
  3554. .LSEH_info_ChaCha20_8x:
  3555. .byte 9,0,0,0
  3556. .rva simd_handler
  3557. .rva .L8x_body,.L8x_epilogue # HandlerData[]
  3558. .long 0xa0,0
  3559. ___
  3560. $code.=<<___ if ($avx>2);
  3561. .LSEH_info_ChaCha20_avx512:
  3562. .byte 9,0,0,0
  3563. .rva simd_handler
  3564. .rva .Lavx512_body,.Lavx512_epilogue # HandlerData[]
  3565. .long 0x20,0
  3566. .LSEH_info_ChaCha20_avx512vl:
  3567. .byte 9,0,0,0
  3568. .rva simd_handler
  3569. .rva .Lavx512vl_body,.Lavx512vl_epilogue # HandlerData[]
  3570. .long 0x20,0
  3571. .LSEH_info_ChaCha20_16x:
  3572. .byte 9,0,0,0
  3573. .rva simd_handler
  3574. .rva .L16x_body,.L16x_epilogue # HandlerData[]
  3575. .long 0xa0,0
  3576. .LSEH_info_ChaCha20_8xvl:
  3577. .byte 9,0,0,0
  3578. .rva simd_handler
  3579. .rva .L8xvl_body,.L8xvl_epilogue # HandlerData[]
  3580. .long 0xa0,0
  3581. ___
  3582. }
  3583. foreach (split("\n",$code)) {
  3584. s/\`([^\`]*)\`/eval $1/ge;
  3585. s/%x#%[yz]/%x/g; # "down-shift"
  3586. print $_,"\n";
  3587. }
  3588. close STDOUT;