61ec16911bcc02adad4f9eacad9c5d9630ec1bd9
[openssl.git] / crypto / sha / asm / sha1-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # sha1_block procedure for x86_64.
11 #
12 # It was brought to my attention that on EM64T compiler-generated code
13 # was far behind 32-bit assembler implementation. This is unlike on
14 # Opteron where compiler-generated code was only 15% behind 32-bit
15 # assembler, which originally made it hard to motivate the effort.
16 # There was suggestion to mechanically translate 32-bit code, but I
17 # dismissed it, reasoning that x86_64 offers enough register bank
18 # capacity to fully utilize SHA-1 parallelism. Therefore this fresh
19 # implementation:-) However! While 64-bit code does perform better
20 # on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
21 # x86_64 does offer larger *addressable* bank, but out-of-order core
22 # reaches for even more registers through dynamic aliasing, and EM64T
23 # core must have managed to run-time optimize even 32-bit code just as
24 # good as 64-bit one. Performance improvement is summarized in the
25 # following table:
26 #
27 #               gcc 3.4         32-bit asm      cycles/byte
28 # Opteron       +45%            +20%            6.8
29 # Xeon P4       +65%            +0%             9.9
30 # Core2         +60%            +10%            7.0
31
32 # August 2009.
33 #
34 # The code was revised to minimize code size and to maximize
35 # "distance" between instructions producing input to 'lea'
36 # instruction and the 'lea' instruction itself, which is essential
37 # for Intel Atom core.
38
39 # October 2010.
40 #
41 # Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
42 # is to offload message schedule denoted by Wt in NIST specification,
43 # or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module
44 # for background and implementation details. The only difference from
45 # 32-bit code is that 64-bit code doesn't have to spill @X[] elements
46 # to free temporary registers.
47
48 # April 2011.
49 #
50 # Add AVX code path. See sha1-586.pl for further information.
51
52 ######################################################################
53 # Current performance is summarized in following table. Numbers are
54 # CPU clock cycles spent to process single byte (less is better).
55 #
56 #               x86_64          SSSE3           AVX
57 # P4            9.8             -
58 # Opteron       6.6             -
59 # Core2         6.7             6.1/+10%        -
60 # Atom          11.0            9.7/+13%        -
61 # Westmere      7.1             5.6/+27%        -
62 # Sandy Bridge  7.9             6.3/+25%        5.2/+51%
63
64 $flavour = shift;
65 $output  = shift;
66 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
67
68 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
69
70 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
71 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
72 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
73 die "can't locate x86_64-xlate.pl";
74
75 $avx=1 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
76                 =~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
77            $1>=2.19);
78 $avx=1 if (!$avx && $flavour =~ /nasm/ &&
79            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
80            $1>=2.03);
81
82 open STDOUT,"| $^X $xlate $flavour $output";
83
84 $ctx="%rdi";    # 1st arg
85 $inp="%rsi";    # 2nd arg
86 $num="%rdx";    # 3rd arg
87
88 # reassign arguments in order to produce more compact code
89 $ctx="%r8";
90 $inp="%r9";
91 $num="%r10";
92
93 $t0="%eax";
94 $t1="%ebx";
95 $t2="%ecx";
96 @xi=("%edx","%ebp");
97 $A="%esi";
98 $B="%edi";
99 $C="%r11d";
100 $D="%r12d";
101 $E="%r13d";
102
103 @V=($A,$B,$C,$D,$E);
104
105 sub BODY_00_19 {
106 my ($i,$a,$b,$c,$d,$e)=@_;
107 my $j=$i+1;
108 $code.=<<___ if ($i==0);
109         mov     `4*$i`($inp),$xi[0]
110         bswap   $xi[0]
111         mov     $xi[0],`4*$i`(%rsp)
112 ___
113 $code.=<<___ if ($i<15);
114         mov     $c,$t0
115         mov     `4*$j`($inp),$xi[1]
116         mov     $a,$t2
117         xor     $d,$t0
118         bswap   $xi[1]
119         rol     \$5,$t2
120         lea     0x5a827999($xi[0],$e),$e
121         and     $b,$t0
122         mov     $xi[1],`4*$j`(%rsp)
123         add     $t2,$e
124         xor     $d,$t0
125         rol     \$30,$b
126         add     $t0,$e
127 ___
128 $code.=<<___ if ($i>=15);
129         mov     `4*($j%16)`(%rsp),$xi[1]
130         mov     $c,$t0
131         mov     $a,$t2
132         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
133         xor     $d,$t0
134         rol     \$5,$t2
135         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
136         and     $b,$t0
137         lea     0x5a827999($xi[0],$e),$e
138         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
139         xor     $d,$t0
140         rol     \$1,$xi[1]
141         add     $t2,$e
142         rol     \$30,$b
143         mov     $xi[1],`4*($j%16)`(%rsp)
144         add     $t0,$e
145 ___
146 unshift(@xi,pop(@xi));
147 }
148
149 sub BODY_20_39 {
150 my ($i,$a,$b,$c,$d,$e)=@_;
151 my $j=$i+1;
152 my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
153 $code.=<<___ if ($i<79);
154         mov     `4*($j%16)`(%rsp),$xi[1]
155         mov     $c,$t0
156         mov     $a,$t2
157         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
158         xor     $b,$t0
159         rol     \$5,$t2
160         lea     $K($xi[0],$e),$e
161         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
162         xor     $d,$t0
163         add     $t2,$e
164         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
165         rol     \$30,$b
166         add     $t0,$e
167         rol     \$1,$xi[1]
168 ___
169 $code.=<<___ if ($i<76);
170         mov     $xi[1],`4*($j%16)`(%rsp)
171 ___
172 $code.=<<___ if ($i==79);
173         mov     $c,$t0
174         mov     $a,$t2
175         xor     $b,$t0
176         lea     $K($xi[0],$e),$e
177         rol     \$5,$t2
178         xor     $d,$t0
179         add     $t2,$e
180         rol     \$30,$b
181         add     $t0,$e
182 ___
183 unshift(@xi,pop(@xi));
184 }
185
186 sub BODY_40_59 {
187 my ($i,$a,$b,$c,$d,$e)=@_;
188 my $j=$i+1;
189 $code.=<<___;
190         mov     `4*($j%16)`(%rsp),$xi[1]
191         mov     $c,$t0
192         mov     $c,$t1
193         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
194         and     $d,$t0
195         mov     $a,$t2
196         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
197         xor     $d,$t1
198         lea     0x8f1bbcdc($xi[0],$e),$e
199         rol     \$5,$t2
200         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
201         add     $t0,$e
202         and     $b,$t1
203         rol     \$1,$xi[1]
204         add     $t1,$e
205         rol     \$30,$b
206         mov     $xi[1],`4*($j%16)`(%rsp)
207         add     $t2,$e
208 ___
209 unshift(@xi,pop(@xi));
210 }
211
212 $code.=<<___;
213 .text
214 .extern OPENSSL_ia32cap_P
215
216 .globl  sha1_block_data_order
217 .type   sha1_block_data_order,\@function,3
218 .align  16
219 sha1_block_data_order:
220         mov     OPENSSL_ia32cap_P+0(%rip),%r9d
221         mov     OPENSSL_ia32cap_P+4(%rip),%r8d
222         test    \$`1<<9`,%r8d           # check SSSE3 bit
223         jz      .Lialu
224 ___
225 $code.=<<___ if ($avx);
226         and     \$`1<<28`,%r8d          # mask AVX bit
227         and     \$`1<<30`,%r9d          # mask "Intel CPU" bit
228         or      %r9d,%r8d
229         cmp     \$`1<<28|1<<30`,%r8d
230         je      _avx_shortcut
231 ___
232 $code.=<<___;
233         jmp     _ssse3_shortcut
234
235 .align  16
236 .Lialu:
237         push    %rbx
238         push    %rbp
239         push    %r12
240         push    %r13
241         mov     %rsp,%r11
242         mov     %rdi,$ctx       # reassigned argument
243         sub     \$`8+16*4`,%rsp
244         mov     %rsi,$inp       # reassigned argument
245         and     \$-64,%rsp
246         mov     %rdx,$num       # reassigned argument
247         mov     %r11,`16*4`(%rsp)
248 .Lprologue:
249
250         mov     0($ctx),$A
251         mov     4($ctx),$B
252         mov     8($ctx),$C
253         mov     12($ctx),$D
254         mov     16($ctx),$E
255         jmp     .Lloop
256
257 .align  16
258 .Lloop:
259 ___
260 for($i=0;$i<20;$i++)    { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
261 for(;$i<40;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
262 for(;$i<60;$i++)        { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
263 for(;$i<80;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
264 $code.=<<___;
265         add     0($ctx),$A
266         add     4($ctx),$B
267         add     8($ctx),$C
268         add     12($ctx),$D
269         add     16($ctx),$E
270         mov     $A,0($ctx)
271         mov     $B,4($ctx)
272         mov     $C,8($ctx)
273         mov     $D,12($ctx)
274         mov     $E,16($ctx)
275
276         sub     \$1,$num
277         lea     `16*4`($inp),$inp
278         jnz     .Lloop
279
280         mov     `16*4`(%rsp),%rsi
281         mov     (%rsi),%r13
282         mov     8(%rsi),%r12
283         mov     16(%rsi),%rbp
284         mov     24(%rsi),%rbx
285         lea     32(%rsi),%rsp
286 .Lepilogue:
287         ret
288 .size   sha1_block_data_order,.-sha1_block_data_order
289 ___
290 {{{
291 my $Xi=4;
292 my @X=map("%xmm$_",(4..7,0..3));
293 my @Tx=map("%xmm$_",(8..10));
294 my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");    # size optimization
295 my @T=("%esi","%edi");
296 my $j=0;
297 my $K_XX_XX="%r11";
298
299 my $_rol=sub { &rol(@_) };
300 my $_ror=sub { &ror(@_) };
301
302 $code.=<<___;
303 .type   sha1_block_data_order_ssse3,\@function,3
304 .align  16
305 sha1_block_data_order_ssse3:
306 _ssse3_shortcut:
307         push    %rbx
308         push    %rbp
309         push    %r12
310         lea     `-64-($win64?5*16:0)`(%rsp),%rsp
311 ___
312 $code.=<<___ if ($win64);
313         movaps  %xmm6,64+0(%rsp)
314         movaps  %xmm7,64+16(%rsp)
315         movaps  %xmm8,64+32(%rsp)
316         movaps  %xmm9,64+48(%rsp)
317         movaps  %xmm10,64+64(%rsp)
318 .Lprologue_ssse3:
319 ___
320 $code.=<<___;
321         mov     %rdi,$ctx       # reassigned argument
322         mov     %rsi,$inp       # reassigned argument
323         mov     %rdx,$num       # reassigned argument
324
325         shl     \$6,$num
326         add     $inp,$num
327         lea     K_XX_XX(%rip),$K_XX_XX
328
329         mov     0($ctx),$A              # load context
330         mov     4($ctx),$B
331         mov     8($ctx),$C
332         mov     12($ctx),$D
333         mov     $B,@T[0]                # magic seed
334         mov     16($ctx),$E
335
336         movdqa  64($K_XX_XX),@X[2]      # pbswap mask
337         movdqa  0($K_XX_XX),@Tx[1]      # K_00_19
338         movdqu  0($inp),@X[-4&7]        # load input to %xmm[0-3]
339         movdqu  16($inp),@X[-3&7]
340         movdqu  32($inp),@X[-2&7]
341         movdqu  48($inp),@X[-1&7]
342         pshufb  @X[2],@X[-4&7]          # byte swap
343         add     \$64,$inp
344         pshufb  @X[2],@X[-3&7]
345         pshufb  @X[2],@X[-2&7]
346         pshufb  @X[2],@X[-1&7]
347         paddd   @Tx[1],@X[-4&7]         # add K_00_19
348         paddd   @Tx[1],@X[-3&7]
349         paddd   @Tx[1],@X[-2&7]
350         movdqa  @X[-4&7],0(%rsp)        # X[]+K xfer to IALU
351         psubd   @Tx[1],@X[-4&7]         # restore X[]
352         movdqa  @X[-3&7],16(%rsp)
353         psubd   @Tx[1],@X[-3&7]
354         movdqa  @X[-2&7],32(%rsp)
355         psubd   @Tx[1],@X[-2&7]
356         jmp     .Loop_ssse3
357 ___
358
359 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
360 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
361   my $arg = pop;
362     $arg = "\$$arg" if ($arg*1 eq $arg);
363     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
364 }
365
366 sub Xupdate_ssse3_16_31()               # recall that $Xi starts wtih 4
367 { use integer;
368   my $body = shift;
369   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
370   my ($a,$b,$c,$d,$e);
371
372         &movdqa (@X[0],@X[-3&7]);
373          eval(shift(@insns));
374          eval(shift(@insns));
375         &movdqa (@Tx[0],@X[-1&7]);
376         &palignr(@X[0],@X[-4&7],8);     # compose "X[-14]" in "X[0]"
377          eval(shift(@insns));
378          eval(shift(@insns));
379
380           &paddd        (@Tx[1],@X[-1&7]);
381          eval(shift(@insns));
382          eval(shift(@insns));
383         &psrldq (@Tx[0],4);             # "X[-3]", 3 dwords
384          eval(shift(@insns));
385          eval(shift(@insns));
386         &pxor   (@X[0],@X[-4&7]);       # "X[0]"^="X[-16]"
387          eval(shift(@insns));
388          eval(shift(@insns));
389
390         &pxor   (@Tx[0],@X[-2&7]);      # "X[-3]"^"X[-8]"
391          eval(shift(@insns));
392          eval(shift(@insns));
393          eval(shift(@insns));
394          eval(shift(@insns));
395
396         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-3]"^"X[-8]"
397          eval(shift(@insns));
398          eval(shift(@insns));
399           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
400          eval(shift(@insns));
401          eval(shift(@insns));
402
403         &movdqa (@Tx[2],@X[0]);
404         &movdqa (@Tx[0],@X[0]);
405          eval(shift(@insns));
406          eval(shift(@insns));
407          eval(shift(@insns));
408          eval(shift(@insns));
409
410         &pslldq (@Tx[2],12);            # "X[0]"<<96, extract one dword
411         &paddd  (@X[0],@X[0]);
412          eval(shift(@insns));
413          eval(shift(@insns));
414          eval(shift(@insns));
415          eval(shift(@insns));
416
417         &psrld  (@Tx[0],31);
418          eval(shift(@insns));
419          eval(shift(@insns));
420         &movdqa (@Tx[1],@Tx[2]);
421          eval(shift(@insns));
422          eval(shift(@insns));
423
424         &psrld  (@Tx[2],30);
425         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=1
426          eval(shift(@insns));
427          eval(shift(@insns));
428          eval(shift(@insns));
429          eval(shift(@insns));
430
431         &pslld  (@Tx[1],2);
432         &pxor   (@X[0],@Tx[2]);
433          eval(shift(@insns));
434          eval(shift(@insns));
435           &movdqa       (@Tx[2],eval(16*(($Xi)/5))."($K_XX_XX)");       # K_XX_XX
436          eval(shift(@insns));
437          eval(shift(@insns));
438
439         &pxor   (@X[0],@Tx[1]);         # "X[0]"^=("X[0]">>96)<<<2
440
441          foreach (@insns) { eval; }     # remaining instructions [if any]
442
443   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
444                 push(@Tx,shift(@Tx));
445 }
446
447 sub Xupdate_ssse3_32_79()
448 { use integer;
449   my $body = shift;
450   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 48 instructions
451   my ($a,$b,$c,$d,$e);
452
453         &movdqa (@Tx[0],@X[-1&7])       if ($Xi==8);
454          eval(shift(@insns));           # body_20_39
455         &pxor   (@X[0],@X[-4&7]);       # "X[0]"="X[-32]"^"X[-16]"
456         &palignr(@Tx[0],@X[-2&7],8);    # compose "X[-6]"
457          eval(shift(@insns));
458          eval(shift(@insns));
459          eval(shift(@insns));           # rol
460
461         &pxor   (@X[0],@X[-7&7]);       # "X[0]"^="X[-28]"
462          eval(shift(@insns));
463          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
464         if ($Xi%5) {
465           &movdqa       (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
466         } else {                        # ... or load next one
467           &movdqa       (@Tx[2],eval(16*($Xi/5))."($K_XX_XX)");
468         }
469           &paddd        (@Tx[1],@X[-1&7]);
470          eval(shift(@insns));           # ror
471          eval(shift(@insns));
472
473         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-6]"
474          eval(shift(@insns));           # body_20_39
475          eval(shift(@insns));
476          eval(shift(@insns));
477          eval(shift(@insns));           # rol
478
479         &movdqa (@Tx[0],@X[0]);
480           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
481          eval(shift(@insns));
482          eval(shift(@insns));
483          eval(shift(@insns));           # ror
484          eval(shift(@insns));
485
486         &pslld  (@X[0],2);
487          eval(shift(@insns));           # body_20_39
488          eval(shift(@insns));
489         &psrld  (@Tx[0],30);
490          eval(shift(@insns));
491          eval(shift(@insns));           # rol
492          eval(shift(@insns));
493          eval(shift(@insns));
494          eval(shift(@insns));           # ror
495          eval(shift(@insns));
496
497         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=2
498          eval(shift(@insns));           # body_20_39
499          eval(shift(@insns));
500           &movdqa       (@Tx[1],@X[0])  if ($Xi<19);
501          eval(shift(@insns));
502          eval(shift(@insns));           # rol
503          eval(shift(@insns));
504          eval(shift(@insns));
505          eval(shift(@insns));           # rol
506          eval(shift(@insns));
507
508          foreach (@insns) { eval; }     # remaining instructions
509
510   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
511                 push(@Tx,shift(@Tx));
512 }
513
514 sub Xuplast_ssse3_80()
515 { use integer;
516   my $body = shift;
517   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
518   my ($a,$b,$c,$d,$e);
519
520          eval(shift(@insns));
521           &paddd        (@Tx[1],@X[-1&7]);
522          eval(shift(@insns));
523          eval(shift(@insns));
524          eval(shift(@insns));
525          eval(shift(@insns));
526
527           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
528
529          foreach (@insns) { eval; }             # remaining instructions
530
531         &cmp    ($inp,$num);
532         &je     (".Ldone_ssse3");
533
534         unshift(@Tx,pop(@Tx));
535
536         &movdqa (@X[2],"64($K_XX_XX)");         # pbswap mask
537         &movdqa (@Tx[1],"0($K_XX_XX)");         # K_00_19
538         &movdqu (@X[-4&7],"0($inp)");           # load input
539         &movdqu (@X[-3&7],"16($inp)");
540         &movdqu (@X[-2&7],"32($inp)");
541         &movdqu (@X[-1&7],"48($inp)");
542         &pshufb (@X[-4&7],@X[2]);               # byte swap
543         &add    ($inp,64);
544
545   $Xi=0;
546 }
547
548 sub Xloop_ssse3()
549 { use integer;
550   my $body = shift;
551   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
552   my ($a,$b,$c,$d,$e);
553
554          eval(shift(@insns));
555          eval(shift(@insns));
556         &pshufb (@X[($Xi-3)&7],@X[2]);
557          eval(shift(@insns));
558          eval(shift(@insns));
559         &paddd  (@X[($Xi-4)&7],@Tx[1]);
560          eval(shift(@insns));
561          eval(shift(@insns));
562          eval(shift(@insns));
563          eval(shift(@insns));
564         &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);  # X[]+K xfer to IALU
565          eval(shift(@insns));
566          eval(shift(@insns));
567         &psubd  (@X[($Xi-4)&7],@Tx[1]);
568
569         foreach (@insns) { eval; }
570   $Xi++;
571 }
572
573 sub Xtail_ssse3()
574 { use integer;
575   my $body = shift;
576   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
577   my ($a,$b,$c,$d,$e);
578
579         foreach (@insns) { eval; }
580 }
581
582 sub body_00_19 () {
583         (
584         '($a,$b,$c,$d,$e)=@V;'.
585         '&add   ($e,eval(4*($j&15))."(%rsp)");',        # X[]+K xfer
586         '&xor   ($c,$d);',
587         '&mov   (@T[1],$a);',   # $b in next round
588         '&$_rol ($a,5);',
589         '&and   (@T[0],$c);',   # ($b&($c^$d))
590         '&xor   ($c,$d);',      # restore $c
591         '&xor   (@T[0],$d);',
592         '&add   ($e,$a);',
593         '&$_ror ($b,$j?7:2);',  # $b>>>2
594         '&add   ($e,@T[0]);'    .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
595         );
596 }
597
598 sub body_20_39 () {
599         (
600         '($a,$b,$c,$d,$e)=@V;'.
601         '&add   ($e,eval(4*($j++&15))."(%rsp)");',      # X[]+K xfer
602         '&xor   (@T[0],$d);',   # ($b^$d)
603         '&mov   (@T[1],$a);',   # $b in next round
604         '&$_rol ($a,5);',
605         '&xor   (@T[0],$c);',   # ($b^$d^$c)
606         '&add   ($e,$a);',
607         '&$_ror ($b,7);',       # $b>>>2
608         '&add   ($e,@T[0]);'    .'unshift(@V,pop(@V)); unshift(@T,pop(@T));'
609         );
610 }
611
612 sub body_40_59 () {
613         (
614         '($a,$b,$c,$d,$e)=@V;'.
615         '&mov   (@T[1],$c);',
616         '&xor   ($c,$d);',
617         '&add   ($e,eval(4*($j++&15))."(%rsp)");',      # X[]+K xfer
618         '&and   (@T[1],$d);',
619         '&and   (@T[0],$c);',   # ($b&($c^$d))
620         '&$_ror ($b,7);',       # $b>>>2
621         '&add   ($e,@T[1]);',
622         '&mov   (@T[1],$a);',   # $b in next round
623         '&$_rol ($a,5);',
624         '&add   ($e,@T[0]);',
625         '&xor   ($c,$d);',      # restore $c
626         '&add   ($e,$a);'       .'unshift(@V,pop(@V)); unshift(@T,pop(@T));'
627         );
628 }
629 $code.=<<___;
630 .align  16
631 .Loop_ssse3:
632 ___
633         &Xupdate_ssse3_16_31(\&body_00_19);
634         &Xupdate_ssse3_16_31(\&body_00_19);
635         &Xupdate_ssse3_16_31(\&body_00_19);
636         &Xupdate_ssse3_16_31(\&body_00_19);
637         &Xupdate_ssse3_32_79(\&body_00_19);
638         &Xupdate_ssse3_32_79(\&body_20_39);
639         &Xupdate_ssse3_32_79(\&body_20_39);
640         &Xupdate_ssse3_32_79(\&body_20_39);
641         &Xupdate_ssse3_32_79(\&body_20_39);
642         &Xupdate_ssse3_32_79(\&body_20_39);
643         &Xupdate_ssse3_32_79(\&body_40_59);
644         &Xupdate_ssse3_32_79(\&body_40_59);
645         &Xupdate_ssse3_32_79(\&body_40_59);
646         &Xupdate_ssse3_32_79(\&body_40_59);
647         &Xupdate_ssse3_32_79(\&body_40_59);
648         &Xupdate_ssse3_32_79(\&body_20_39);
649         &Xuplast_ssse3_80(\&body_20_39);        # can jump to "done"
650
651                                 $saved_j=$j; @saved_V=@V;
652
653         &Xloop_ssse3(\&body_20_39);
654         &Xloop_ssse3(\&body_20_39);
655         &Xloop_ssse3(\&body_20_39);
656
657 $code.=<<___;
658         add     0($ctx),$A                      # update context
659         add     4($ctx),@T[0]
660         add     8($ctx),$C
661         add     12($ctx),$D
662         mov     $A,0($ctx)
663         add     16($ctx),$E
664         mov     @T[0],4($ctx)
665         mov     @T[0],$B                        # magic seed
666         mov     $C,8($ctx)
667         mov     $D,12($ctx)
668         mov     $E,16($ctx)
669         jmp     .Loop_ssse3
670
671 .align  16
672 .Ldone_ssse3:
673 ___
674                                 $j=$saved_j; @V=@saved_V;
675
676         &Xtail_ssse3(\&body_20_39);
677         &Xtail_ssse3(\&body_20_39);
678         &Xtail_ssse3(\&body_20_39);
679
680 $code.=<<___;
681         add     0($ctx),$A                      # update context
682         add     4($ctx),@T[0]
683         add     8($ctx),$C
684         mov     $A,0($ctx)
685         add     12($ctx),$D
686         mov     @T[0],4($ctx)
687         add     16($ctx),$E
688         mov     $C,8($ctx)
689         mov     $D,12($ctx)
690         mov     $E,16($ctx)
691 ___
692 $code.=<<___ if ($win64);
693         movaps  64+0(%rsp),%xmm6
694         movaps  64+16(%rsp),%xmm7
695         movaps  64+32(%rsp),%xmm8
696         movaps  64+48(%rsp),%xmm9
697         movaps  64+64(%rsp),%xmm10
698 ___
699 $code.=<<___;
700         lea     `64+($win64?6*16:0)`(%rsp),%rsi
701         mov     0(%rsi),%r12
702         mov     8(%rsi),%rbp
703         mov     16(%rsi),%rbx
704         lea     24(%rsi),%rsp
705 .Lepilogue_ssse3:
706         ret
707 .size   sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3
708 ___
709
710 if ($avx) {
711 my $Xi=4;
712 my @X=map("%xmm$_",(4..7,0..3));
713 my @Tx=map("%xmm$_",(8..10));
714 my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");    # size optimization
715 my @T=("%esi","%edi");
716 my $j=0;
717 my $K_XX_XX="%r11";
718
719 my $_rol=sub { &shld(@_[0],@_) };
720 my $_ror=sub { &shrd(@_[0],@_) };
721
722 $code.=<<___;
723 .type   sha1_block_data_order_avx,\@function,3
724 .align  16
725 sha1_block_data_order_avx:
726 _avx_shortcut:
727         push    %rbx
728         push    %rbp
729         push    %r12
730         lea     `-64-($win64?5*16:0)`(%rsp),%rsp
731 ___
732 $code.=<<___ if ($win64);
733         movaps  %xmm6,64+0(%rsp)
734         movaps  %xmm7,64+16(%rsp)
735         movaps  %xmm8,64+32(%rsp)
736         movaps  %xmm9,64+48(%rsp)
737         movaps  %xmm10,64+64(%rsp)
738 .Lprologue_avx:
739 ___
740 $code.=<<___;
741         mov     %rdi,$ctx       # reassigned argument
742         mov     %rsi,$inp       # reassigned argument
743         mov     %rdx,$num       # reassigned argument
744         vzeroall
745
746         shl     \$6,$num
747         add     $inp,$num
748         lea     K_XX_XX(%rip),$K_XX_XX
749
750         mov     0($ctx),$A              # load context
751         mov     4($ctx),$B
752         mov     8($ctx),$C
753         mov     12($ctx),$D
754         mov     $B,@T[0]                # magic seed
755         mov     16($ctx),$E
756
757         vmovdqa 64($K_XX_XX),@X[2]      # pbswap mask
758         vmovdqa 0($K_XX_XX),@Tx[1]      # K_00_19
759         vmovdqu 0($inp),@X[-4&7]        # load input to %xmm[0-3]
760         vmovdqu 16($inp),@X[-3&7]
761         vmovdqu 32($inp),@X[-2&7]
762         vmovdqu 48($inp),@X[-1&7]
763         vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap
764         add     \$64,$inp
765         vpshufb @X[2],@X[-3&7],@X[-3&7]
766         vpshufb @X[2],@X[-2&7],@X[-2&7]
767         vpshufb @X[2],@X[-1&7],@X[-1&7]
768         vpaddd  @Tx[1],@X[-4&7],@X[0]   # add K_00_19
769         vpaddd  @Tx[1],@X[-3&7],@X[1]
770         vpaddd  @Tx[1],@X[-2&7],@X[2]
771         vmovdqa @X[0],0(%rsp)           # X[]+K xfer to IALU
772         vmovdqa @X[1],16(%rsp)
773         vmovdqa @X[2],32(%rsp)
774         jmp     .Loop_avx
775 ___
776
777 sub Xupdate_avx_16_31()         # recall that $Xi starts wtih 4
778 { use integer;
779   my $body = shift;
780   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
781   my ($a,$b,$c,$d,$e);
782
783          eval(shift(@insns));
784          eval(shift(@insns));
785         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
786          eval(shift(@insns));
787          eval(shift(@insns));
788
789           &vpaddd       (@Tx[1],@Tx[1],@X[-1&7]);
790          eval(shift(@insns));
791          eval(shift(@insns));
792         &vpsrldq(@Tx[0],@X[-1&7],4);    # "X[-3]", 3 dwords
793          eval(shift(@insns));
794          eval(shift(@insns));
795         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
796          eval(shift(@insns));
797          eval(shift(@insns));
798
799         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
800          eval(shift(@insns));
801          eval(shift(@insns));
802          eval(shift(@insns));
803          eval(shift(@insns));
804
805         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
806          eval(shift(@insns));
807          eval(shift(@insns));
808           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
809          eval(shift(@insns));
810          eval(shift(@insns));
811
812         &vpsrld (@Tx[0],@X[0],31);
813          eval(shift(@insns));
814          eval(shift(@insns));
815          eval(shift(@insns));
816          eval(shift(@insns));
817
818         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
819         &vpaddd (@X[0],@X[0],@X[0]);
820          eval(shift(@insns));
821          eval(shift(@insns));
822          eval(shift(@insns));
823          eval(shift(@insns));
824
825         &vpsrld (@Tx[1],@Tx[2],30);
826         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
827          eval(shift(@insns));
828          eval(shift(@insns));
829          eval(shift(@insns));
830          eval(shift(@insns));
831
832         &vpslld (@Tx[2],@Tx[2],2);
833         &vpxor  (@X[0],@X[0],@Tx[1]);
834          eval(shift(@insns));
835          eval(shift(@insns));
836          eval(shift(@insns));
837          eval(shift(@insns));
838
839         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
840          eval(shift(@insns));
841          eval(shift(@insns));
842           &vmovdqa      (@Tx[2],eval(16*(($Xi)/5))."($K_XX_XX)");       # K_XX_XX
843          eval(shift(@insns));
844          eval(shift(@insns));
845
846
847          foreach (@insns) { eval; }     # remaining instructions [if any]
848
849   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
850                 push(@Tx,shift(@Tx));
851 }
852
853 sub Xupdate_avx_32_79()
854 { use integer;
855   my $body = shift;
856   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 48 instructions
857   my ($a,$b,$c,$d,$e);
858
859         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
860         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
861          eval(shift(@insns));           # body_20_39
862          eval(shift(@insns));
863          eval(shift(@insns));
864          eval(shift(@insns));           # rol
865
866         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
867          eval(shift(@insns));
868          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
869         if ($Xi%5) {
870           &vmovdqa      (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
871         } else {                        # ... or load next one
872           &vmovdqa      (@Tx[2],eval(16*($Xi/5))."($K_XX_XX)");
873         }
874           &vpaddd       (@Tx[1],@Tx[1],@X[-1&7]);
875          eval(shift(@insns));           # ror
876          eval(shift(@insns));
877
878         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
879          eval(shift(@insns));           # body_20_39
880          eval(shift(@insns));
881          eval(shift(@insns));
882          eval(shift(@insns));           # rol
883
884         &vpsrld (@Tx[0],@X[0],30);
885           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
886          eval(shift(@insns));
887          eval(shift(@insns));
888          eval(shift(@insns));           # ror
889          eval(shift(@insns));
890
891         &vpslld (@X[0],@X[0],2);
892          eval(shift(@insns));           # body_20_39
893          eval(shift(@insns));
894          eval(shift(@insns));
895          eval(shift(@insns));           # rol
896          eval(shift(@insns));
897          eval(shift(@insns));
898          eval(shift(@insns));           # ror
899          eval(shift(@insns));
900
901         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
902          eval(shift(@insns));           # body_20_39
903          eval(shift(@insns));
904           &vmovdqa      (@Tx[1],@X[0])  if ($Xi<19);
905          eval(shift(@insns));
906          eval(shift(@insns));           # rol
907          eval(shift(@insns));
908          eval(shift(@insns));
909          eval(shift(@insns));           # rol
910          eval(shift(@insns));
911
912          foreach (@insns) { eval; }     # remaining instructions
913
914   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
915                 push(@Tx,shift(@Tx));
916 }
917
918 sub Xuplast_avx_80()
919 { use integer;
920   my $body = shift;
921   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
922   my ($a,$b,$c,$d,$e);
923
924          eval(shift(@insns));
925           &vpaddd       (@Tx[1],@Tx[1],@X[-1&7]);
926          eval(shift(@insns));
927          eval(shift(@insns));
928          eval(shift(@insns));
929          eval(shift(@insns));
930
931           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
932
933          foreach (@insns) { eval; }             # remaining instructions
934
935         &cmp    ($inp,$num);
936         &je     (".Ldone_avx");
937
938         unshift(@Tx,pop(@Tx));
939
940         &vmovdqa(@X[2],"64($K_XX_XX)");         # pbswap mask
941         &vmovdqa(@Tx[1],"0($K_XX_XX)");         # K_00_19
942         &vmovdqu(@X[-4&7],"0($inp)");           # load input
943         &vmovdqu(@X[-3&7],"16($inp)");
944         &vmovdqu(@X[-2&7],"32($inp)");
945         &vmovdqu(@X[-1&7],"48($inp)");
946         &vpshufb(@X[-4&7],@X[-4&7],@X[2]);      # byte swap
947         &add    ($inp,64);
948
949   $Xi=0;
950 }
951
952 sub Xloop_avx()
953 { use integer;
954   my $body = shift;
955   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
956   my ($a,$b,$c,$d,$e);
957
958          eval(shift(@insns));
959          eval(shift(@insns));
960         &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
961          eval(shift(@insns));
962          eval(shift(@insns));
963         &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],@Tx[1]);
964          eval(shift(@insns));
965          eval(shift(@insns));
966          eval(shift(@insns));
967          eval(shift(@insns));
968         &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]);      # X[]+K xfer to IALU
969          eval(shift(@insns));
970          eval(shift(@insns));
971
972         foreach (@insns) { eval; }
973   $Xi++;
974 }
975
976 sub Xtail_avx()
977 { use integer;
978   my $body = shift;
979   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
980   my ($a,$b,$c,$d,$e);
981
982         foreach (@insns) { eval; }
983 }
984
985 $code.=<<___;
986 .align  16
987 .Loop_avx:
988 ___
989         &Xupdate_avx_16_31(\&body_00_19);
990         &Xupdate_avx_16_31(\&body_00_19);
991         &Xupdate_avx_16_31(\&body_00_19);
992         &Xupdate_avx_16_31(\&body_00_19);
993         &Xupdate_avx_32_79(\&body_00_19);
994         &Xupdate_avx_32_79(\&body_20_39);
995         &Xupdate_avx_32_79(\&body_20_39);
996         &Xupdate_avx_32_79(\&body_20_39);
997         &Xupdate_avx_32_79(\&body_20_39);
998         &Xupdate_avx_32_79(\&body_20_39);
999         &Xupdate_avx_32_79(\&body_40_59);
1000         &Xupdate_avx_32_79(\&body_40_59);
1001         &Xupdate_avx_32_79(\&body_40_59);
1002         &Xupdate_avx_32_79(\&body_40_59);
1003         &Xupdate_avx_32_79(\&body_40_59);
1004         &Xupdate_avx_32_79(\&body_20_39);
1005         &Xuplast_avx_80(\&body_20_39);  # can jump to "done"
1006
1007                                 $saved_j=$j; @saved_V=@V;
1008
1009         &Xloop_avx(\&body_20_39);
1010         &Xloop_avx(\&body_20_39);
1011         &Xloop_avx(\&body_20_39);
1012
1013 $code.=<<___;
1014         add     0($ctx),$A                      # update context
1015         add     4($ctx),@T[0]
1016         add     8($ctx),$C
1017         add     12($ctx),$D
1018         mov     $A,0($ctx)
1019         add     16($ctx),$E
1020         mov     @T[0],4($ctx)
1021         mov     @T[0],$B                        # magic seed
1022         mov     $C,8($ctx)
1023         mov     $D,12($ctx)
1024         mov     $E,16($ctx)
1025         jmp     .Loop_avx
1026
1027 .align  16
1028 .Ldone_avx:
1029 ___
1030                                 $j=$saved_j; @V=@saved_V;
1031
1032         &Xtail_avx(\&body_20_39);
1033         &Xtail_avx(\&body_20_39);
1034         &Xtail_avx(\&body_20_39);
1035
1036 $code.=<<___;
1037         vzeroall
1038
1039         add     0($ctx),$A                      # update context
1040         add     4($ctx),@T[0]
1041         add     8($ctx),$C
1042         mov     $A,0($ctx)
1043         add     12($ctx),$D
1044         mov     @T[0],4($ctx)
1045         add     16($ctx),$E
1046         mov     $C,8($ctx)
1047         mov     $D,12($ctx)
1048         mov     $E,16($ctx)
1049 ___
1050 $code.=<<___ if ($win64);
1051         movaps  64+0(%rsp),%xmm6
1052         movaps  64+16(%rsp),%xmm7
1053         movaps  64+32(%rsp),%xmm8
1054         movaps  64+48(%rsp),%xmm9
1055         movaps  64+64(%rsp),%xmm10
1056 ___
1057 $code.=<<___;
1058         lea     `64+($win64?6*16:0)`(%rsp),%rsi
1059         mov     0(%rsi),%r12
1060         mov     8(%rsi),%rbp
1061         mov     16(%rsi),%rbx
1062         lea     24(%rsi),%rsp
1063 .Lepilogue_avx:
1064         ret
1065 .size   sha1_block_data_order_avx,.-sha1_block_data_order_avx
1066 ___
1067 }
1068 $code.=<<___;
1069 .align  64
1070 K_XX_XX:
1071 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1072 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1073 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1074 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1075 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1076 ___
1077 }}}
1078 $code.=<<___;
1079 .asciz  "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1080 .align  64
1081 ___
1082
1083 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1084 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1085 if ($win64) {
1086 $rec="%rcx";
1087 $frame="%rdx";
1088 $context="%r8";
1089 $disp="%r9";
1090
1091 $code.=<<___;
1092 .extern __imp_RtlVirtualUnwind
1093 .type   se_handler,\@abi-omnipotent
1094 .align  16
1095 se_handler:
1096         push    %rsi
1097         push    %rdi
1098         push    %rbx
1099         push    %rbp
1100         push    %r12
1101         push    %r13
1102         push    %r14
1103         push    %r15
1104         pushfq
1105         sub     \$64,%rsp
1106
1107         mov     120($context),%rax      # pull context->Rax
1108         mov     248($context),%rbx      # pull context->Rip
1109
1110         lea     .Lprologue(%rip),%r10
1111         cmp     %r10,%rbx               # context->Rip<.Lprologue
1112         jb      .Lcommon_seh_tail
1113
1114         mov     152($context),%rax      # pull context->Rsp
1115
1116         lea     .Lepilogue(%rip),%r10
1117         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
1118         jae     .Lcommon_seh_tail
1119
1120         mov     `16*4`(%rax),%rax       # pull saved stack pointer
1121         lea     32(%rax),%rax
1122
1123         mov     -8(%rax),%rbx
1124         mov     -16(%rax),%rbp
1125         mov     -24(%rax),%r12
1126         mov     -32(%rax),%r13
1127         mov     %rbx,144($context)      # restore context->Rbx
1128         mov     %rbp,160($context)      # restore context->Rbp
1129         mov     %r12,216($context)      # restore context->R12
1130         mov     %r13,224($context)      # restore context->R13
1131
1132         jmp     .Lcommon_seh_tail
1133 .size   se_handler,.-se_handler
1134
1135 .type   ssse3_handler,\@abi-omnipotent
1136 .align  16
1137 ssse3_handler:
1138         push    %rsi
1139         push    %rdi
1140         push    %rbx
1141         push    %rbp
1142         push    %r12
1143         push    %r13
1144         push    %r14
1145         push    %r15
1146         pushfq
1147         sub     \$64,%rsp
1148
1149         mov     120($context),%rax      # pull context->Rax
1150         mov     248($context),%rbx      # pull context->Rip
1151
1152         mov     8($disp),%rsi           # disp->ImageBase
1153         mov     56($disp),%r11          # disp->HandlerData
1154
1155         mov     0(%r11),%r10d           # HandlerData[0]
1156         lea     (%rsi,%r10),%r10        # prologue label
1157         cmp     %r10,%rbx               # context->Rip<prologue label
1158         jb      .Lcommon_seh_tail
1159
1160         mov     152($context),%rax      # pull context->Rsp
1161
1162         mov     4(%r11),%r10d           # HandlerData[1]
1163         lea     (%rsi,%r10),%r10        # epilogue label
1164         cmp     %r10,%rbx               # context->Rip>=epilogue label
1165         jae     .Lcommon_seh_tail
1166
1167         lea     64(%rax),%rsi
1168         lea     512($context),%rdi      # &context.Xmm6
1169         mov     \$10,%ecx
1170         .long   0xa548f3fc              # cld; rep movsq
1171         lea     24+5*16(%rax),%rax      # adjust stack pointer
1172
1173         mov     -8(%rax),%rbx
1174         mov     -16(%rax),%rbp
1175         mov     %rbx,144($context)      # restore context->Rbx
1176         mov     %rbp,160($context)      # restore context->Rbp
1177
1178 .Lcommon_seh_tail:
1179         mov     8(%rax),%rdi
1180         mov     16(%rax),%rsi
1181         mov     %rax,152($context)      # restore context->Rsp
1182         mov     %rsi,168($context)      # restore context->Rsi
1183         mov     %rdi,176($context)      # restore context->Rdi
1184
1185         mov     40($disp),%rdi          # disp->ContextRecord
1186         mov     $context,%rsi           # context
1187         mov     \$154,%ecx              # sizeof(CONTEXT)
1188         .long   0xa548f3fc              # cld; rep movsq
1189
1190         mov     $disp,%rsi
1191         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1192         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1193         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1194         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1195         mov     40(%rsi),%r10           # disp->ContextRecord
1196         lea     56(%rsi),%r11           # &disp->HandlerData
1197         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1198         mov     %r10,32(%rsp)           # arg5
1199         mov     %r11,40(%rsp)           # arg6
1200         mov     %r12,48(%rsp)           # arg7
1201         mov     %rcx,56(%rsp)           # arg8, (NULL)
1202         call    *__imp_RtlVirtualUnwind(%rip)
1203
1204         mov     \$1,%eax                # ExceptionContinueSearch
1205         add     \$64,%rsp
1206         popfq
1207         pop     %r15
1208         pop     %r14
1209         pop     %r13
1210         pop     %r12
1211         pop     %rbp
1212         pop     %rbx
1213         pop     %rdi
1214         pop     %rsi
1215         ret
1216 .size   ssse3_handler,.-ssse3_handler
1217
1218 .section        .pdata
1219 .align  4
1220         .rva    .LSEH_begin_sha1_block_data_order
1221         .rva    .LSEH_end_sha1_block_data_order
1222         .rva    .LSEH_info_sha1_block_data_order
1223         .rva    .LSEH_begin_sha1_block_data_order_ssse3
1224         .rva    .LSEH_end_sha1_block_data_order_ssse3
1225         .rva    .LSEH_info_sha1_block_data_order_ssse3
1226 ___
1227 $code.=<<___ if ($avx);
1228         .rva    .LSEH_begin_sha1_block_data_order_avx
1229         .rva    .LSEH_end_sha1_block_data_order_avx
1230         .rva    .LSEH_info_sha1_block_data_order_avx
1231 ___
1232 $code.=<<___;
1233 .section        .xdata
1234 .align  8
1235 .LSEH_info_sha1_block_data_order:
1236         .byte   9,0,0,0
1237         .rva    se_handler
1238 .LSEH_info_sha1_block_data_order_ssse3:
1239         .byte   9,0,0,0
1240         .rva    ssse3_handler
1241         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
1242 ___
1243 $code.=<<___ if ($avx);
1244 .LSEH_info_sha1_block_data_order_avx:
1245         .byte   9,0,0,0
1246         .rva    ssse3_handler
1247         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
1248 ___
1249 }
1250
1251 ####################################################################
1252
1253 $code =~ s/\`([^\`]*)\`/eval $1/gem;
1254 print $code;
1255 close STDOUT;