8f10f973e98c921f5e7dbfffa9b92647d6f81112
[openssl.git] / crypto / sha / asm / sha512-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. Rights for redistribution and usage in source and binary
6 # forms are granted according to the OpenSSL license.
7 # ====================================================================
8 #
9 # sha256/512_block procedure for x86_64.
10 #
11 # 40% improvement over compiler-generated code on Opteron. On EM64T
12 # sha256 was observed to run >80% faster and sha512 - >40%. No magical
13 # tricks, just straight implementation... I really wonder why gcc
14 # [being armed with inline assembler] fails to generate as fast code.
15 # The only thing which is cool about this module is that it's very
16 # same instruction sequence used for both SHA-256 and SHA-512. In
17 # former case the instructions operate on 32-bit operands, while in
18 # latter - on 64-bit ones. All I had to do is to get one flavor right,
19 # the other one passed the test right away:-)
20 #
21 # sha256_block runs in ~1005 cycles on Opteron, which gives you
22 # asymptotic performance of 64*1000/1005=63.7MBps times CPU clock
23 # frequency in GHz. sha512_block runs in ~1275 cycles, which results
24 # in 128*1000/1275=100MBps per GHz. Is there room for improvement?
25 # Well, if you compare it to IA-64 implementation, which maintains
26 # X[16] in register bank[!], tends to 4 instructions per CPU clock
27 # cycle and runs in 1003 cycles, 1275 is very good result for 3-way
28 # issue Opteron pipeline and X[16] maintained in memory. So that *if*
29 # there is a way to improve it, *then* the only way would be to try to
30 # offload X[16] updates to SSE unit, but that would require "deeper"
31 # loop unroll, which in turn would naturally cause size blow-up, not
32 # to mention increased complexity! And once again, only *if* it's
33 # actually possible to noticeably improve overall ILP, instruction
34 # level parallelism, on a given CPU implementation in this case.
35 #
36 # Special note on Intel EM64T. While Opteron CPU exhibits perfect
37 # perfromance ratio of 1.5 between 64- and 32-bit flavors [see above],
38 # [currently available] EM64T CPUs apparently are far from it. On the
39 # contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
40 # sha256_block:-( This is presumably because 64-bit shifts/rotates
41 # apparently are not atomic instructions, but implemented in microcode.
42 #
43 # May 2012.
44 #
45 # Optimization including one of Pavel Semjanov's ideas, alternative
46 # Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and
47 # unfortunately -10% SHA512 on P4 [which nobody should care about
48 # that much].
49 #
50 # June 2012.
51 #
52 # Add SIMD code paths, see below for improvement coefficients. SSSE3
53 # code path was not attempted for SHA512, because improvement is not
54 # estimated to be high enough, noticeably less than 9%, to justify
55 # the effort, not on pre-AVX processors. [Obviously with exclusion
56 # for VIA Nano, but it has SHA512 instruction that is faster and
57 # should be used instead.] For reference, corresponding estimated
58 # upper limit for improvement for SSSE3 SHA256 is 28%. The fact that
59 # higher coefficients are observed on VIA Nano and Bulldozer has more
60 # to do with specifics of their architecture [which is topic for
61 # separate discussion].
62
63 ######################################################################
64 # Current performance in cycles per processed byte (less is better):
65 #
66 #               SHA256  SSSE3       AVX/XOP(*)      SHA512  AVX/XOP(*)
67 #
68 # AMD K8        15.1    -           -               9.70    -
69 # P4            17.5    -           -               33.4    -
70 # Core 2        15.5    13.9(+11%)  -               10.3    -
71 # Westmere      15.1    12.5(+21%)  -               9.72    -
72 # Atom          23.0    21.6(+6%)   -               14.7    -
73 # VIA Nano      23.0    16.3(+41%)  -               14.7    -
74 # Sandy Bridge  17.4    14.0(+24%)  11.6(+50%(**))  11.2    8.10(+38%(**))
75 # Ivy Bridge    12.6    10.3(+22%)  10.3(+22%)      8.17    7.22(+13%)
76 # Bulldozer     21.5    13.7(+57%)  13.7(+57%(***)) 13.5    8.58(+57%)
77 #
78 # (*)   whichever applicable;
79 # (**)  switch from ror to shrd stands for fair share of improvement;
80 # (***) execution time is fully determined by remaining integer-only
81 #       part, body_00_15; reducing the amount of SIMD instructions
82 #       below certain limit makes no difference/sense; to conserve
83 #       space SHA256 XOP code path is therefore omitted;
84
85 $flavour = shift;
86 $output  = shift;
87 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
88
89 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
90
91 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
92 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
93 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
94 die "can't locate x86_64-xlate.pl";
95
96 $avx=1 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
97                 =~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
98            $1>=2.19);
99 $avx=1 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
100            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
101            $1>=2.09);
102 $avx=1 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
103            `ml64 2>&1` =~ /Version ([0-9]+)\./ &&
104            $1>=10);
105
106 open OUT,"| \"$^X\" $xlate $flavour $output";
107 *STDOUT=*OUT;
108
109 if ($output =~ /512/) {
110         $func="sha512_block_data_order";
111         $TABLE="K512";
112         $SZ=8;
113         @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx",
114                                         "%r8", "%r9", "%r10","%r11");
115         ($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi");
116         @Sigma0=(28,34,39);
117         @Sigma1=(14,18,41);
118         @sigma0=(1,  8, 7);
119         @sigma1=(19,61, 6);
120         $rounds=80;
121 } else {
122         $func="sha256_block_data_order";
123         $TABLE="K256";
124         $SZ=4;
125         @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx",
126                                         "%r8d","%r9d","%r10d","%r11d");
127         ($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi");
128         @Sigma0=( 2,13,22);
129         @Sigma1=( 6,11,25);
130         @sigma0=( 7,18, 3);
131         @sigma1=(17,19,10);
132         $rounds=64;
133 }
134
135 $ctx="%rdi";    # 1st arg, zapped by $a3
136 $inp="%rsi";    # 2nd arg
137 $Tbl="%rbp";
138
139 $_ctx="16*$SZ+0*8(%rsp)";
140 $_inp="16*$SZ+1*8(%rsp)";
141 $_end="16*$SZ+2*8(%rsp)";
142 $_rsp="16*$SZ+3*8(%rsp)";
143 $framesz="16*$SZ+4*8";
144
145
146 sub ROUND_00_15()
147 { my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
148
149 $code.=<<___;
150         ror     \$`$Sigma1[2]-$Sigma1[1]`,$a0
151         mov     $f,$a2
152
153         ror     \$`$Sigma0[2]-$Sigma0[1]`,$a1
154         xor     $e,$a0
155         xor     $g,$a2                  # f^g
156
157         mov     $T1,`$SZ*($i&0xf)`(%rsp)
158         xor     $a,$a1
159         and     $e,$a2                  # (f^g)&e
160
161         ror     \$`$Sigma1[1]-$Sigma1[0]`,$a0
162         add     $h,$T1                  # T1+=h
163         xor     $g,$a2                  # Ch(e,f,g)=((f^g)&e)^g
164
165         ror     \$`$Sigma0[1]-$Sigma0[0]`,$a1
166         xor     $e,$a0
167         add     $a2,$T1                 # T1+=Ch(e,f,g)
168
169         mov     $a,$a2
170         add     ($Tbl),$T1              # T1+=K[round]
171         xor     $a,$a1
172
173         ror     \$$Sigma1[0],$a0        # Sigma1(e)
174         xor     $b,$a2                  # a^b, b^c in next round
175         mov     $b,$h
176
177         ror     \$$Sigma0[0],$a1        # Sigma0(a)
178         and     $a2,$a3
179         add     $a0,$T1                 # T1+=Sigma1(e)
180
181         xor     $a3,$h                  # h=Maj(a,b,c)=Ch(a^b,c,b)
182         add     $T1,$d                  # d+=T1
183         add     $T1,$h                  # h+=T1
184 ___
185 $code.=<<___ if ($i>=15);
186         mov     `$SZ*(($i+2)&0xf)`(%rsp),$a0
187 ___
188 $code.=<<___;
189         lea     $SZ($Tbl),$Tbl          # round++
190         add     $a1,$h                  # h+=Sigma0(a)
191
192 ___
193         ($a2,$a3) = ($a3,$a2);
194 }
195
196 sub ROUND_16_XX()
197 { my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
198
199 $code.=<<___;
200         #mov    `$SZ*(($i+1)&0xf)`(%rsp),$a0
201         mov     `$SZ*(($i+14)&0xf)`(%rsp),$a1
202
203         mov     $a0,$T1
204         ror     \$`$sigma0[1]-$sigma0[0]`,$a0
205         mov     $a1,$a2
206         ror     \$`$sigma1[1]-$sigma1[0]`,$a1
207
208         xor     $T1,$a0
209         shr     \$$sigma0[2],$T1
210         ror     \$$sigma0[0],$a0
211         xor     $a2,$a1
212         shr     \$$sigma1[2],$a2
213
214         xor     $a0,$T1                 # sigma0(X[(i+1)&0xf])
215         ror     \$$sigma1[0],$a1
216         add     `$SZ*(($i+9)&0xf)`(%rsp),$T1
217         xor     $a2,$a1                 # sigma1(X[(i+14)&0xf])
218
219         add     `$SZ*($i&0xf)`(%rsp),$T1
220         mov     $e,$a0
221         add     $a1,$T1
222         mov     $a,$a1
223 ___
224         &ROUND_00_15(@_);
225 }
226
227 $code=<<___;
228 .text
229
230 .extern OPENSSL_ia32cap_P
231 .globl  $func
232 .type   $func,\@function,4
233 .align  16
234 $func:
235 ___
236 $code.=<<___ if ($SZ==4 || $avx);
237         lea     OPENSSL_ia32cap_P(%rip),%r11
238         mov     0(%r11),%r10d
239         mov     4(%r11),%r11d
240 ___
241 $code.=<<___ if ($avx && $SZ==8);
242         test    \$`1<<11`,%r11d         # check for XOP
243         jnz     .Lxop_shortcut
244 ___
245 $code.=<<___ if ($avx);
246         and     \$`1<<30`,%r10d         # mask "Intel CPU" bit
247         and     \$`1<<28|1<<9`,%r11d    # mask AVX and SSSE3 bits
248         or      %r10d,%r11d
249         cmp     \$`1<<28|1<<9|1<<30`,%r11d
250         je      .Lavx_shortcut
251 ___
252 $code.=<<___ if ($SZ==4);
253         test    \$`1<<9`,%r11d
254         jnz     .Lssse3_shortcut
255 ___
256 $code.=<<___;
257         push    %rbx
258         push    %rbp
259         push    %r12
260         push    %r13
261         push    %r14
262         push    %r15
263         mov     %rsp,%r11               # copy %rsp
264         shl     \$4,%rdx                # num*16
265         sub     \$$framesz,%rsp
266         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
267         and     \$-64,%rsp              # align stack frame
268         mov     $ctx,$_ctx              # save ctx, 1st arg
269         mov     $inp,$_inp              # save inp, 2nd arh
270         mov     %rdx,$_end              # save end pointer, "3rd" arg
271         mov     %r11,$_rsp              # save copy of %rsp
272 .Lprologue:
273
274         mov     $SZ*0($ctx),$A
275         mov     $SZ*1($ctx),$B
276         mov     $SZ*2($ctx),$C
277         mov     $SZ*3($ctx),$D
278         mov     $SZ*4($ctx),$E
279         mov     $SZ*5($ctx),$F
280         mov     $SZ*6($ctx),$G
281         mov     $SZ*7($ctx),$H
282         jmp     .Lloop
283
284 .align  16
285 .Lloop:
286         mov     $B,$a3
287         lea     $TABLE(%rip),$Tbl
288         xor     $C,$a3                  # magic
289 ___
290         for($i=0;$i<16;$i++) {
291                 $code.="        mov     $SZ*$i($inp),$T1\n";
292                 $code.="        mov     @ROT[4],$a0\n";
293                 $code.="        mov     @ROT[0],$a1\n";
294                 $code.="        bswap   $T1\n";
295                 &ROUND_00_15($i,@ROT);
296                 unshift(@ROT,pop(@ROT));
297         }
298 $code.=<<___;
299         jmp     .Lrounds_16_xx
300 .align  16
301 .Lrounds_16_xx:
302 ___
303         for(;$i<32;$i++) {
304                 &ROUND_16_XX($i,@ROT);
305                 unshift(@ROT,pop(@ROT));
306         }
307
308 $code.=<<___;
309         cmpb    \$0,`$SZ-1`($Tbl)
310         jnz     .Lrounds_16_xx
311
312         mov     $_ctx,$ctx
313         lea     16*$SZ($inp),$inp
314
315         add     $SZ*0($ctx),$A
316         add     $SZ*1($ctx),$B
317         add     $SZ*2($ctx),$C
318         add     $SZ*3($ctx),$D
319         add     $SZ*4($ctx),$E
320         add     $SZ*5($ctx),$F
321         add     $SZ*6($ctx),$G
322         add     $SZ*7($ctx),$H
323
324         cmp     $_end,$inp
325
326         mov     $A,$SZ*0($ctx)
327         mov     $B,$SZ*1($ctx)
328         mov     $C,$SZ*2($ctx)
329         mov     $D,$SZ*3($ctx)
330         mov     $E,$SZ*4($ctx)
331         mov     $F,$SZ*5($ctx)
332         mov     $G,$SZ*6($ctx)
333         mov     $H,$SZ*7($ctx)
334         jb      .Lloop
335
336         mov     $_rsp,%rsi
337         mov     (%rsi),%r15
338         mov     8(%rsi),%r14
339         mov     16(%rsi),%r13
340         mov     24(%rsi),%r12
341         mov     32(%rsi),%rbp
342         mov     40(%rsi),%rbx
343         lea     48(%rsi),%rsp
344 .Lepilogue:
345         ret
346 .size   $func,.-$func
347 ___
348
349 if ($SZ==4) {
350 $code.=<<___;
351 .align  64
352 .type   $TABLE,\@object
353 $TABLE:
354         .long   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
355         .long   0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
356         .long   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
357         .long   0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
358         .long   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
359         .long   0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
360         .long   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
361         .long   0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
362         .long   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
363         .long   0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
364         .long   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
365         .long   0xd192e819,0xd6990624,0xf40e3585,0x106aa070
366         .long   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
367         .long   0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
368         .long   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
369         .long   0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
370
371         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
372         .long   0x03020100,0x0b0a0908,0xffffffff,0xffffffff
373         .long   0xffffffff,0xffffffff,0x03020100,0x0b0a0908
374         .asciz  "SHA256 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
375 ___
376 } else {
377 $code.=<<___;
378 .align  64
379 .type   $TABLE,\@object
380 $TABLE:
381         .quad   0x428a2f98d728ae22,0x7137449123ef65cd
382         .quad   0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
383         .quad   0x3956c25bf348b538,0x59f111f1b605d019
384         .quad   0x923f82a4af194f9b,0xab1c5ed5da6d8118
385         .quad   0xd807aa98a3030242,0x12835b0145706fbe
386         .quad   0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
387         .quad   0x72be5d74f27b896f,0x80deb1fe3b1696b1
388         .quad   0x9bdc06a725c71235,0xc19bf174cf692694
389         .quad   0xe49b69c19ef14ad2,0xefbe4786384f25e3
390         .quad   0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
391         .quad   0x2de92c6f592b0275,0x4a7484aa6ea6e483
392         .quad   0x5cb0a9dcbd41fbd4,0x76f988da831153b5
393         .quad   0x983e5152ee66dfab,0xa831c66d2db43210
394         .quad   0xb00327c898fb213f,0xbf597fc7beef0ee4
395         .quad   0xc6e00bf33da88fc2,0xd5a79147930aa725
396         .quad   0x06ca6351e003826f,0x142929670a0e6e70
397         .quad   0x27b70a8546d22ffc,0x2e1b21385c26c926
398         .quad   0x4d2c6dfc5ac42aed,0x53380d139d95b3df
399         .quad   0x650a73548baf63de,0x766a0abb3c77b2a8
400         .quad   0x81c2c92e47edaee6,0x92722c851482353b
401         .quad   0xa2bfe8a14cf10364,0xa81a664bbc423001
402         .quad   0xc24b8b70d0f89791,0xc76c51a30654be30
403         .quad   0xd192e819d6ef5218,0xd69906245565a910
404         .quad   0xf40e35855771202a,0x106aa07032bbd1b8
405         .quad   0x19a4c116b8d2d0c8,0x1e376c085141ab53
406         .quad   0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
407         .quad   0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
408         .quad   0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
409         .quad   0x748f82ee5defb2fc,0x78a5636f43172f60
410         .quad   0x84c87814a1f0ab72,0x8cc702081a6439ec
411         .quad   0x90befffa23631e28,0xa4506cebde82bde9
412         .quad   0xbef9a3f7b2c67915,0xc67178f2e372532b
413         .quad   0xca273eceea26619c,0xd186b8c721c0c207
414         .quad   0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
415         .quad   0x06f067aa72176fba,0x0a637dc5a2c898a6
416         .quad   0x113f9804bef90dae,0x1b710b35131c471b
417         .quad   0x28db77f523047d84,0x32caab7b40c72493
418         .quad   0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
419         .quad   0x4cc5d4becb3e42b6,0x597f299cfc657e2a
420         .quad   0x5fcb6fab3ad6faec,0x6c44198c4a475817
421
422         .quad   0x0001020304050607,0x08090a0b0c0d0e0f
423         .asciz  "SHA512 block transfort for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
424 ___
425 }
426
427 ######################################################################
428 # SIMD code paths
429 #
430 {{{
431
432 my $a4=$T1;
433 my ($a,$b,$c,$d,$e,$f,$g,$h);
434
435 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
436 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
437   my $arg = pop;
438     $arg = "\$$arg" if ($arg*1 eq $arg);
439     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
440 }
441
442 sub body_00_15 () {
443         (
444         '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
445
446         '&ror   ($a0,$Sigma1[2]-$Sigma1[1])',
447         '&mov   ($a,$a1)',
448         '&mov   ($a4,$f)',
449
450         '&xor   ($a0,$e)',
451         '&ror   ($a1,$Sigma0[2]-$Sigma0[1])',
452         '&xor   ($a4,$g)',                      # f^g
453
454         '&ror   ($a0,$Sigma1[1]-$Sigma1[0])',
455         '&xor   ($a1,$a)',
456         '&and   ($a4,$e)',                      # (f^g)&e
457
458         '&xor   ($a0,$e)',
459         '&add   ($h,$SZ*($i&15)."(%rsp)")',     # h+=X[i]+K[i]
460         '&mov   ($a2,$a)',
461
462         '&ror   ($a1,$Sigma0[1]-$Sigma0[0])',
463         '&xor   ($a4,$g)',                      # Ch(e,f,g)=((f^g)&e)^g
464         '&xor   ($a2,$b)',                      # a^b, b^c in next round
465
466         '&ror   ($a0,$Sigma1[0])',              # Sigma1(e)
467         '&add   ($h,$a4)',                      # h+=Ch(e,f,g)
468         '&and   ($a3,$a2)',                     # (b^c)&(a^b)
469
470         '&xor   ($a1,$a)',
471         '&add   ($h,$a0)',                      # h+=Sigma1(e)
472         '&xor   ($a3,$b)',                      # Maj(a,b,c)=Ch(a^b,c,b)
473
474         '&add   ($d,$h)',                       # d+=h
475         '&ror   ($a1,$Sigma0[0])',              # Sigma0(a)
476         '&add   ($h,$a3)',                      # h+=Maj(a,b,c)
477
478         '&mov   ($a0,$d)',
479         '&add   ($a1,$h);'.                     # h+=Sigma0(a)
480         '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
481         );
482 }
483
484 ######################################################################
485 # SSSE3 code path
486 #
487 if ($SZ==4) {   # SHA256 only
488 my @X = map("%xmm$_",(0..3));
489 my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
490
491 $code.=<<___;
492 .type   ${func}_ssse3,\@function,4
493 .align  64
494 ${func}_ssse3:
495 .Lssse3_shortcut:
496         push    %rbx
497         push    %rbp
498         push    %r12
499         push    %r13
500         push    %r14
501         push    %r15
502         mov     %rsp,%r11               # copy %rsp
503         shl     \$4,%rdx                # num*16
504         sub     \$`$framesz+$win64*16*4`,%rsp
505         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
506         and     \$-64,%rsp              # align stack frame
507         mov     $ctx,$_ctx              # save ctx, 1st arg
508         mov     $inp,$_inp              # save inp, 2nd arh
509         mov     %rdx,$_end              # save end pointer, "3rd" arg
510         mov     %r11,$_rsp              # save copy of %rsp
511 ___
512 $code.=<<___ if ($win64);
513         movaps  %xmm6,16*$SZ+32(%rsp)
514         movaps  %xmm7,16*$SZ+48(%rsp)
515         movaps  %xmm8,16*$SZ+64(%rsp)
516         movaps  %xmm9,16*$SZ+80(%rsp)
517 ___
518 $code.=<<___;
519 .Lprologue_ssse3:
520
521         mov     $SZ*0($ctx),$A
522         mov     $SZ*1($ctx),$B
523         mov     $SZ*2($ctx),$C
524         mov     $SZ*3($ctx),$D
525         mov     $SZ*4($ctx),$E
526         mov     $SZ*5($ctx),$F
527         mov     $SZ*6($ctx),$G
528         mov     $SZ*7($ctx),$H
529 ___
530
531 $code.=<<___;
532         movdqa  $TABLE+`$SZ*$rounds`+16(%rip),$t4
533         movdqa  $TABLE+`$SZ*$rounds`+32(%rip),$t5
534         jmp     .Lloop_ssse3
535 .align  16
536 .Lloop_ssse3:
537         movdqa  $TABLE+`$SZ*$rounds`(%rip),$t3
538         movdqu  0x00($inp),@X[0]
539         movdqu  0x10($inp),@X[1]
540         movdqu  0x20($inp),@X[2]
541         movdqu  0x30($inp),@X[3]
542         pshufb  $t3,@X[0]
543         lea     $TABLE(%rip),$Tbl
544         pshufb  $t3,@X[1]
545         movdqa  0x00($Tbl),$t0
546         pshufb  $t3,@X[2]
547         movdqa  0x10($Tbl),$t1
548         paddd   @X[0],$t0
549         movdqa  0x20($Tbl),$t2
550         pshufb  $t3,@X[3]
551         movdqa  0x30($Tbl),$t3
552         paddd   @X[1],$t1
553         paddd   @X[2],$t2
554         paddd   @X[3],$t3
555         movdqa  $t0,0x00(%rsp)
556         mov     $A,$a1
557         movdqa  $t1,0x10(%rsp)
558         mov     $B,$a3
559         movdqa  $t2,0x20(%rsp)
560         xor     $C,$a3                  # magic
561         movdqa  $t3,0x30(%rsp)
562         mov     $E,$a0
563         jmp     .Lssse3_00_47
564
565 .align  16
566 .Lssse3_00_47:
567         add     \$16*$SZ,$Tbl
568 ___
569 sub Xupdate_256_SSSE3 () {
570         (
571         '&movdqa        ($t0,@X[1]);',
572         '&movdqa        ($t3,@X[3])',
573         '&palignr       ($t0,@X[0],$SZ)',       # X[1..4]
574          '&palignr      ($t3,@X[2],$SZ);',      # X[9..12]
575         '&movdqa        ($t1,$t0)',
576         '&movdqa        ($t2,$t0);',
577         '&psrld         ($t0,$sigma0[2])',
578          '&paddd        (@X[0],$t3);',          # X[0..3] += X[9..12]
579         '&psrld         ($t2,$sigma0[0])',
580          '&pshufd       ($t3,@X[3],0b11111010)',# X[14..15]
581         '&pslld         ($t1,8*$SZ-$sigma0[1]);'.
582         '&pxor          ($t0,$t2)',
583         '&psrld         ($t2,$sigma0[1]-$sigma0[0]);'.
584         '&pxor          ($t0,$t1)',
585         '&pslld         ($t1,$sigma0[1]-$sigma0[0]);'.
586         '&pxor          ($t0,$t2);',
587          '&movdqa       ($t2,$t3)',
588         '&pxor          ($t0,$t1);',            # sigma0(X[1..4])
589          '&psrld        ($t3,$sigma1[2])',
590         '&paddd         (@X[0],$t0);',          # X[0..3] += sigma0(X[1..4])
591          '&psrlq        ($t2,$sigma1[0])',
592          '&pxor         ($t3,$t2);',
593          '&psrlq        ($t2,$sigma1[1]-$sigma1[0])',
594          '&pxor         ($t3,$t2)',
595          '&pshufb       ($t3,$t4)',             # sigma1(X[14..15])
596         '&paddd         (@X[0],$t3)',           # X[0..1] += sigma1(X[14..15])
597          '&pshufd       ($t3,@X[0],0b01010000)',# X[16..17]
598          '&movdqa       ($t2,$t3);',
599          '&psrld        ($t3,$sigma1[2])',
600          '&psrlq        ($t2,$sigma1[0])',
601          '&pxor         ($t3,$t2);',
602          '&psrlq        ($t2,$sigma1[1]-$sigma1[0])',
603          '&pxor         ($t3,$t2);',
604         '&movdqa        ($t2,16*$j."($Tbl)")',
605          '&pshufb       ($t3,$t5)',
606         '&paddd         (@X[0],$t3)'            # X[2..3] += sigma1(X[16..17])
607         );
608 }
609
610 sub SSSE3_256_00_47 () {
611 my $j = shift;
612 my $body = shift;
613 my @X = @_;
614 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
615
616     if (0) {
617         foreach (Xupdate_256_SSSE3()) {         # 36 instructions
618             eval;
619             eval(shift(@insns));
620             eval(shift(@insns));
621             eval(shift(@insns));
622         }
623     } else {                    # squeeze extra 3% on Westmere and Atom
624           eval(shift(@insns));  #@
625           eval(shift(@insns));
626         &movdqa         ($t0,@X[1]);
627           eval(shift(@insns));
628         &movdqa         ($t3,@X[3]);
629           eval(shift(@insns));
630           eval(shift(@insns));  #@
631           eval(shift(@insns));
632         &palignr        ($t0,@X[0],$SZ);        # X[1..4]
633           eval(shift(@insns));  #@
634           eval(shift(@insns));
635          &palignr       ($t3,@X[2],$SZ);        # X[9..12]
636           eval(shift(@insns));
637           eval(shift(@insns));
638           eval(shift(@insns));
639           eval(shift(@insns));
640           eval(shift(@insns));  #@
641           eval(shift(@insns));
642         &movdqa         ($t1,$t0);
643           eval(shift(@insns));
644         &movdqa         ($t2,$t0);
645           eval(shift(@insns));  #@
646           eval(shift(@insns));
647           eval(shift(@insns));
648         &psrld          ($t0,$sigma0[2]);
649           eval(shift(@insns));
650           eval(shift(@insns));
651           eval(shift(@insns));
652          &paddd         (@X[0],$t3);            # X[0..3] += X[9..12]
653           eval(shift(@insns));
654           eval(shift(@insns));  #@
655           eval(shift(@insns));
656         &psrld          ($t2,$sigma0[0]);
657           eval(shift(@insns));
658           eval(shift(@insns));
659           eval(shift(@insns));  #@
660           eval(shift(@insns));
661          &pshufd        ($t3,@X[3],0b11111010); # X[4..15]
662           eval(shift(@insns));
663         &pslld          ($t1,8*$SZ-$sigma0[1]);
664           eval(shift(@insns));
665         &pxor           ($t0,$t2);
666           eval(shift(@insns));  #@
667           eval(shift(@insns));
668         &psrld          ($t2,$sigma0[1]-$sigma0[0]);
669           eval(shift(@insns));  #@
670           eval(shift(@insns));
671         &pxor           ($t0,$t1);
672           eval(shift(@insns));
673           eval(shift(@insns));
674         &pslld          ($t1,$sigma0[1]-$sigma0[0]);
675           eval(shift(@insns));
676         &pxor           ($t0,$t2);
677           eval(shift(@insns));
678           eval(shift(@insns));  #@
679           eval(shift(@insns));
680          &movdqa        ($t2,$t3);
681           eval(shift(@insns));
682           eval(shift(@insns));  #@
683           eval(shift(@insns));
684         &pxor           ($t0,$t1);              # sigma0(X[1..4])
685           eval(shift(@insns));
686           eval(shift(@insns));
687          &psrld         ($t3,$sigma1[2]);
688           eval(shift(@insns));
689           eval(shift(@insns));
690         &paddd          (@X[0],$t0);            # X[0..3] += sigma0(X[1..4])
691           eval(shift(@insns));
692           eval(shift(@insns));  #@
693           eval(shift(@insns));
694           eval(shift(@insns));
695          &psrlq         ($t2,$sigma1[0]);
696           eval(shift(@insns));
697           eval(shift(@insns));  #@
698           eval(shift(@insns));
699           eval(shift(@insns));
700          &pxor          ($t3,$t2);
701           eval(shift(@insns));
702           eval(shift(@insns));  #@
703          &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
704           eval(shift(@insns));
705           eval(shift(@insns));  #@
706           eval(shift(@insns));
707          &pxor          ($t3,$t2);
708           eval(shift(@insns));
709           eval(shift(@insns));
710           eval(shift(@insns));
711          &pshufb        ($t3,$t4);              # sigma1(X[14..15])
712           eval(shift(@insns));
713           eval(shift(@insns));  #@
714           eval(shift(@insns));
715           eval(shift(@insns));
716           eval(shift(@insns));  #@
717         &paddd          (@X[0],$t3);            # X[0..1] += sigma1(X[14..15])
718           eval(shift(@insns));
719          &pshufd        ($t3,@X[0],0b01010000); # X[16..17]
720           eval(shift(@insns));
721           eval(shift(@insns));
722           eval(shift(@insns));
723           eval(shift(@insns));
724          &movdqa        ($t2,$t3);
725           eval(shift(@insns));
726           eval(shift(@insns));  #@
727           eval(shift(@insns));
728          &psrld         ($t3,$sigma1[2]);
729           eval(shift(@insns));
730          &psrlq         ($t2,$sigma1[0]);
731           eval(shift(@insns));
732           eval(shift(@insns));  #@
733           eval(shift(@insns));
734           eval(shift(@insns));
735          &pxor          ($t3,$t2);
736           eval(shift(@insns));
737           eval(shift(@insns));  #@
738           eval(shift(@insns));
739          &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
740           eval(shift(@insns));  #@
741           eval(shift(@insns));
742           eval(shift(@insns));
743           eval(shift(@insns));
744          &pxor          ($t3,$t2);
745           eval(shift(@insns));
746           eval(shift(@insns));
747         &movdqa         ($t2,16*$j."($Tbl)");
748           eval(shift(@insns));  #@
749           eval(shift(@insns));
750          &pshufb        ($t3,$t5);
751           eval(shift(@insns));
752           eval(shift(@insns));  #@
753           eval(shift(@insns));
754           eval(shift(@insns));
755           eval(shift(@insns));
756         &paddd          (@X[0],$t3);            # X[2..3] += sigma1(X[16..17])
757           eval(shift(@insns));
758           eval(shift(@insns));
759           eval(shift(@insns));
760     }
761         &paddd          ($t2,@X[0]);
762           foreach (@insns) { eval; }            # remaining instructions
763         &movdqa         (16*$j."(%rsp)",$t2);
764 }
765
766     for ($i=0,$j=0; $j<4; $j++) {
767         &SSSE3_256_00_47($j,\&body_00_15,@X);
768         push(@X,shift(@X));                     # rotate(@X)
769     }
770         &cmpb   ($SZ-1+16*$SZ."($Tbl)",0);
771         &jne    (".Lssse3_00_47");
772
773     for ($i=0; $i<16; ) {
774         foreach(body_00_15()) { eval; }
775     }
776 $code.=<<___;
777         mov     $_ctx,$ctx
778         mov     $a1,$A
779
780         add     $SZ*0($ctx),$A
781         lea     16*$SZ($inp),$inp
782         add     $SZ*1($ctx),$B
783         add     $SZ*2($ctx),$C
784         add     $SZ*3($ctx),$D
785         add     $SZ*4($ctx),$E
786         add     $SZ*5($ctx),$F
787         add     $SZ*6($ctx),$G
788         add     $SZ*7($ctx),$H
789
790         cmp     $_end,$inp
791
792         mov     $A,$SZ*0($ctx)
793         mov     $B,$SZ*1($ctx)
794         mov     $C,$SZ*2($ctx)
795         mov     $D,$SZ*3($ctx)
796         mov     $E,$SZ*4($ctx)
797         mov     $F,$SZ*5($ctx)
798         mov     $G,$SZ*6($ctx)
799         mov     $H,$SZ*7($ctx)
800         jb      .Lloop_ssse3
801
802         mov     $_rsp,%rsi
803 ___
804 $code.=<<___ if ($win64);
805         movaps  16*$SZ+32(%rsp),%xmm6
806         movaps  16*$SZ+48(%rsp),%xmm7
807         movaps  16*$SZ+64(%rsp),%xmm8
808         movaps  16*$SZ+80(%rsp),%xmm9
809 ___
810 $code.=<<___;
811         mov     (%rsi),%r15
812         mov     8(%rsi),%r14
813         mov     16(%rsi),%r13
814         mov     24(%rsi),%r12
815         mov     32(%rsi),%rbp
816         mov     40(%rsi),%rbx
817         lea     48(%rsi),%rsp
818 .Lepilogue_ssse3:
819         ret
820 .size   ${func}_ssse3,.-${func}_ssse3
821 ___
822 }
823
824 if ($avx) {{
825 ######################################################################
826 # XOP code path
827 #
828 if ($SZ==8) {   # SHA512 only
829 $code.=<<___;
830 .type   ${func}_xop,\@function,4
831 .align  64
832 ${func}_xop:
833 .Lxop_shortcut:
834         push    %rbx
835         push    %rbp
836         push    %r12
837         push    %r13
838         push    %r14
839         push    %r15
840         mov     %rsp,%r11               # copy %rsp
841         shl     \$4,%rdx                # num*16
842         sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
843         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
844         and     \$-64,%rsp              # align stack frame
845         mov     $ctx,$_ctx              # save ctx, 1st arg
846         mov     $inp,$_inp              # save inp, 2nd arh
847         mov     %rdx,$_end              # save end pointer, "3rd" arg
848         mov     %r11,$_rsp              # save copy of %rsp
849 ___
850 $code.=<<___ if ($win64);
851         movaps  %xmm6,16*$SZ+32(%rsp)
852         movaps  %xmm7,16*$SZ+48(%rsp)
853         movaps  %xmm8,16*$SZ+64(%rsp)
854         movaps  %xmm9,16*$SZ+80(%rsp)
855 ___
856 $code.=<<___ if ($win64 && $SZ>4);
857         movaps  %xmm10,16*$SZ+96(%rsp)
858         movaps  %xmm11,16*$SZ+112(%rsp)
859 ___
860 $code.=<<___;
861 .Lprologue_xop:
862
863         vzeroall
864         mov     $SZ*0($ctx),$A
865         mov     $SZ*1($ctx),$B
866         mov     $SZ*2($ctx),$C
867         mov     $SZ*3($ctx),$D
868         mov     $SZ*4($ctx),$E
869         mov     $SZ*5($ctx),$F
870         mov     $SZ*6($ctx),$G
871         mov     $SZ*7($ctx),$H
872         jmp     .Lloop_xop
873 ___
874                                         if ($SZ==4) {   # SHA256
875     my @X = map("%xmm$_",(0..3));
876     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
877
878 $code.=<<___;
879 .align  16
880 .Lloop_xop:
881         vmovdqa $TABLE+`$SZ*$rounds`(%rip),$t3
882         vmovdqu 0x00($inp),@X[0]
883         vmovdqu 0x10($inp),@X[1]
884         vmovdqu 0x20($inp),@X[2]
885         vmovdqu 0x30($inp),@X[3]
886         vpshufb $t3,@X[0],@X[0]
887         lea     $TABLE(%rip),$Tbl
888         vpshufb $t3,@X[1],@X[1]
889         vpshufb $t3,@X[2],@X[2]
890         vpaddd  0x00($Tbl),@X[0],$t0
891         vpshufb $t3,@X[3],@X[3]
892         vpaddd  0x10($Tbl),@X[1],$t1
893         vpaddd  0x20($Tbl),@X[2],$t2
894         vpaddd  0x30($Tbl),@X[3],$t3
895         vmovdqa $t0,0x00(%rsp)
896         mov     $A,$a1
897         vmovdqa $t1,0x10(%rsp)
898         mov     $B,$a3
899         vmovdqa $t2,0x20(%rsp)
900         xor     $C,$a3                  # magic
901         vmovdqa $t3,0x30(%rsp)
902         mov     $E,$a0
903         jmp     .Lxop_00_47
904
905 .align  16
906 .Lxop_00_47:
907         add     \$16*$SZ,$Tbl
908 ___
909 sub XOP_256_00_47 () {
910 my $j = shift;
911 my $body = shift;
912 my @X = @_;
913 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
914
915         &vpalignr       ($t0,@X[1],@X[0],$SZ);  # X[1..4]
916           eval(shift(@insns));
917           eval(shift(@insns));
918          &vpalignr      ($t3,@X[3],@X[2],$SZ);  # X[9..12]
919           eval(shift(@insns));
920           eval(shift(@insns));
921         &vprotd         ($t1,$t0,8*$SZ-$sigma0[1]);
922           eval(shift(@insns));
923           eval(shift(@insns));
924         &vpsrld         ($t0,$t0,$sigma0[2]);
925           eval(shift(@insns));
926           eval(shift(@insns));
927          &vpaddd        (@X[0],@X[0],$t3);      # X[0..3] += X[9..12]
928           eval(shift(@insns));
929           eval(shift(@insns));
930           eval(shift(@insns));
931           eval(shift(@insns));
932         &vprotd         ($t2,$t1,$sigma0[1]-$sigma0[0]);
933           eval(shift(@insns));
934           eval(shift(@insns));
935         &vpxor          ($t0,$t0,$t1);
936           eval(shift(@insns));
937           eval(shift(@insns));
938           eval(shift(@insns));
939           eval(shift(@insns));
940          &vprotd        ($t3,@X[3],8*$SZ-$sigma1[1]);
941           eval(shift(@insns));
942           eval(shift(@insns));
943         &vpxor          ($t0,$t0,$t2);          # sigma0(X[1..4])
944           eval(shift(@insns));
945           eval(shift(@insns));
946          &vpsrld        ($t2,@X[3],$sigma1[2]);
947           eval(shift(@insns));
948           eval(shift(@insns));
949         &vpaddd         (@X[0],@X[0],$t0);      # X[0..3] += sigma0(X[1..4])
950           eval(shift(@insns));
951           eval(shift(@insns));
952          &vprotd        ($t1,$t3,$sigma1[1]-$sigma1[0]);
953           eval(shift(@insns));
954           eval(shift(@insns));
955          &vpxor         ($t3,$t3,$t2);
956           eval(shift(@insns));
957           eval(shift(@insns));
958           eval(shift(@insns));
959           eval(shift(@insns));
960          &vpxor         ($t3,$t3,$t1);          # sigma1(X[14..15])
961           eval(shift(@insns));
962           eval(shift(@insns));
963           eval(shift(@insns));
964           eval(shift(@insns));
965         &vpsrldq        ($t3,$t3,8);
966           eval(shift(@insns));
967           eval(shift(@insns));
968           eval(shift(@insns));
969           eval(shift(@insns));
970         &vpaddd         (@X[0],@X[0],$t3);      # X[0..1] += sigma1(X[14..15])
971           eval(shift(@insns));
972           eval(shift(@insns));
973           eval(shift(@insns));
974           eval(shift(@insns));
975          &vprotd        ($t3,@X[0],8*$SZ-$sigma1[1]);
976           eval(shift(@insns));
977           eval(shift(@insns));
978          &vpsrld        ($t2,@X[0],$sigma1[2]);
979           eval(shift(@insns));
980           eval(shift(@insns));
981          &vprotd        ($t1,$t3,$sigma1[1]-$sigma1[0]);
982           eval(shift(@insns));
983           eval(shift(@insns));
984          &vpxor         ($t3,$t3,$t2);
985           eval(shift(@insns));
986           eval(shift(@insns));
987           eval(shift(@insns));
988           eval(shift(@insns));
989          &vpxor         ($t3,$t3,$t1);          # sigma1(X[16..17])
990           eval(shift(@insns));
991           eval(shift(@insns));
992           eval(shift(@insns));
993           eval(shift(@insns));
994         &vpslldq        ($t3,$t3,8);            # 22 instructions
995           eval(shift(@insns));
996           eval(shift(@insns));
997           eval(shift(@insns));
998           eval(shift(@insns));
999         &vpaddd         (@X[0],@X[0],$t3);      # X[2..3] += sigma1(X[16..17])
1000           eval(shift(@insns));
1001           eval(shift(@insns));
1002           eval(shift(@insns));
1003           eval(shift(@insns));
1004         &vpaddd         ($t2,@X[0],16*$j."($Tbl)");
1005           foreach (@insns) { eval; }            # remaining instructions
1006         &vmovdqa        (16*$j."(%rsp)",$t2);
1007 }
1008
1009     for ($i=0,$j=0; $j<4; $j++) {
1010         &XOP_256_00_47($j,\&body_00_15,@X);
1011         push(@X,shift(@X));                     # rotate(@X)
1012     }
1013         &cmpb   ($SZ-1+16*$SZ."($Tbl)",0);
1014         &jne    (".Lxop_00_47");
1015
1016     for ($i=0; $i<16; ) {
1017         foreach(body_00_15()) { eval; }
1018     }
1019
1020                                         } else {        # SHA512
1021     my @X = map("%xmm$_",(0..7));
1022     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
1023
1024 $code.=<<___;
1025 .align  16
1026 .Lloop_xop:
1027         vmovdqa $TABLE+`$SZ*$rounds`(%rip),$t3
1028         vmovdqu 0x00($inp),@X[0]
1029         lea     $TABLE(%rip),$Tbl
1030         vmovdqu 0x10($inp),@X[1]
1031         vmovdqu 0x20($inp),@X[2]
1032         vpshufb $t3,@X[0],@X[0]
1033         vmovdqu 0x30($inp),@X[3]
1034         vpshufb $t3,@X[1],@X[1]
1035         vmovdqu 0x40($inp),@X[4]
1036         vpshufb $t3,@X[2],@X[2]
1037         vmovdqu 0x50($inp),@X[5]
1038         vpshufb $t3,@X[3],@X[3]
1039         vmovdqu 0x60($inp),@X[6]
1040         vpshufb $t3,@X[4],@X[4]
1041         vmovdqu 0x70($inp),@X[7]
1042         vpshufb $t3,@X[5],@X[5]
1043         vpaddq  0x00($Tbl),@X[0],$t0
1044         vpshufb $t3,@X[6],@X[6]
1045         vpaddq  0x10($Tbl),@X[1],$t1
1046         vpshufb $t3,@X[7],@X[7]
1047         vpaddq  0x20($Tbl),@X[2],$t2
1048         vpaddq  0x30($Tbl),@X[3],$t3
1049         vmovdqa $t0,0x00(%rsp)
1050         vpaddq  0x40($Tbl),@X[4],$t0
1051         vmovdqa $t1,0x10(%rsp)
1052         vpaddq  0x50($Tbl),@X[5],$t1
1053         vmovdqa $t2,0x20(%rsp)
1054         vpaddq  0x60($Tbl),@X[6],$t2
1055         vmovdqa $t3,0x30(%rsp)
1056         vpaddq  0x70($Tbl),@X[7],$t3
1057         vmovdqa $t0,0x40(%rsp)
1058         mov     $A,$a1
1059         vmovdqa $t1,0x50(%rsp)
1060         mov     $B,$a3
1061         vmovdqa $t2,0x60(%rsp)
1062         xor     $C,$a3                  # magic
1063         vmovdqa $t3,0x70(%rsp)
1064         mov     $E,$a0
1065         jmp     .Lxop_00_47
1066
1067 .align  16
1068 .Lxop_00_47:
1069         add     \$16*$SZ,$Tbl
1070 ___
1071 sub XOP_512_00_47 () {
1072 my $j = shift;
1073 my $body = shift;
1074 my @X = @_;
1075 my @insns = (&$body,&$body);                    # 52 instructions
1076
1077         &vpalignr       ($t0,@X[1],@X[0],$SZ);  # X[1..2]
1078           eval(shift(@insns));
1079           eval(shift(@insns));
1080          &vpalignr      ($t3,@X[5],@X[4],$SZ);  # X[9..10]
1081           eval(shift(@insns));
1082           eval(shift(@insns));
1083         &vprotq         ($t1,$t0,8*$SZ-$sigma0[1]);
1084           eval(shift(@insns));
1085           eval(shift(@insns));
1086         &vpsrlq         ($t0,$t0,$sigma0[2]);
1087           eval(shift(@insns));
1088           eval(shift(@insns));
1089          &vpaddq        (@X[0],@X[0],$t3);      # X[0..1] += X[9..10]
1090           eval(shift(@insns));
1091           eval(shift(@insns));
1092           eval(shift(@insns));
1093           eval(shift(@insns));
1094         &vprotq         ($t2,$t1,$sigma0[1]-$sigma0[0]);
1095           eval(shift(@insns));
1096           eval(shift(@insns));
1097         &vpxor          ($t0,$t0,$t1);
1098           eval(shift(@insns));
1099           eval(shift(@insns));
1100           eval(shift(@insns));
1101           eval(shift(@insns));
1102          &vprotq        ($t3,@X[7],8*$SZ-$sigma1[1]);
1103           eval(shift(@insns));
1104           eval(shift(@insns));
1105         &vpxor          ($t0,$t0,$t2);          # sigma0(X[1..2])
1106           eval(shift(@insns));
1107           eval(shift(@insns));
1108          &vpsrlq        ($t2,@X[7],$sigma1[2]);
1109           eval(shift(@insns));
1110           eval(shift(@insns));
1111         &vpaddq         (@X[0],@X[0],$t0);      # X[0..1] += sigma0(X[1..2])
1112           eval(shift(@insns));
1113           eval(shift(@insns));
1114          &vprotq        ($t1,$t3,$sigma1[1]-$sigma1[0]);
1115           eval(shift(@insns));
1116           eval(shift(@insns));
1117          &vpxor         ($t3,$t3,$t2);
1118           eval(shift(@insns));
1119           eval(shift(@insns));
1120           eval(shift(@insns));
1121           eval(shift(@insns));
1122          &vpxor         ($t3,$t3,$t1);          # sigma1(X[14..15])
1123           eval(shift(@insns));
1124           eval(shift(@insns));
1125           eval(shift(@insns));
1126           eval(shift(@insns));
1127         &vpaddq         (@X[0],@X[0],$t3);      # X[0..1] += sigma1(X[14..15])
1128           eval(shift(@insns));
1129           eval(shift(@insns));
1130           eval(shift(@insns));
1131           eval(shift(@insns));
1132         &vpaddq         ($t2,@X[0],16*$j."($Tbl)");
1133           foreach (@insns) { eval; }            # remaining instructions
1134         &vmovdqa        (16*$j."(%rsp)",$t2);
1135 }
1136
1137     for ($i=0,$j=0; $j<8; $j++) {
1138         &XOP_512_00_47($j,\&body_00_15,@X);
1139         push(@X,shift(@X));                     # rotate(@X)
1140     }
1141         &cmpb   ($SZ-1+16*$SZ."($Tbl)",0);
1142         &jne    (".Lxop_00_47");
1143
1144     for ($i=0; $i<16; ) {
1145         foreach(body_00_15()) { eval; }
1146     }
1147 }
1148 $code.=<<___;
1149         mov     $_ctx,$ctx
1150         mov     $a1,$A
1151
1152         add     $SZ*0($ctx),$A
1153         lea     16*$SZ($inp),$inp
1154         add     $SZ*1($ctx),$B
1155         add     $SZ*2($ctx),$C
1156         add     $SZ*3($ctx),$D
1157         add     $SZ*4($ctx),$E
1158         add     $SZ*5($ctx),$F
1159         add     $SZ*6($ctx),$G
1160         add     $SZ*7($ctx),$H
1161
1162         cmp     $_end,$inp
1163
1164         mov     $A,$SZ*0($ctx)
1165         mov     $B,$SZ*1($ctx)
1166         mov     $C,$SZ*2($ctx)
1167         mov     $D,$SZ*3($ctx)
1168         mov     $E,$SZ*4($ctx)
1169         mov     $F,$SZ*5($ctx)
1170         mov     $G,$SZ*6($ctx)
1171         mov     $H,$SZ*7($ctx)
1172         jb      .Lloop_xop
1173
1174         mov     $_rsp,%rsi
1175         vzeroall
1176 ___
1177 $code.=<<___ if ($win64);
1178         movaps  16*$SZ+32(%rsp),%xmm6
1179         movaps  16*$SZ+48(%rsp),%xmm7
1180         movaps  16*$SZ+64(%rsp),%xmm8
1181         movaps  16*$SZ+80(%rsp),%xmm9
1182 ___
1183 $code.=<<___ if ($win64 && $SZ>4);
1184         movaps  16*$SZ+96(%rsp),%xmm10
1185         movaps  16*$SZ+112(%rsp),%xmm11
1186 ___
1187 $code.=<<___;
1188         mov     (%rsi),%r15
1189         mov     8(%rsi),%r14
1190         mov     16(%rsi),%r13
1191         mov     24(%rsi),%r12
1192         mov     32(%rsi),%rbp
1193         mov     40(%rsi),%rbx
1194         lea     48(%rsi),%rsp
1195 .Lepilogue_xop:
1196         ret
1197 .size   ${func}_xop,.-${func}_xop
1198 ___
1199 }
1200 ######################################################################
1201 # AVX+shrd code path
1202 #
1203 local *ror = sub { &shrd(@_[0],@_) };
1204
1205 $code.=<<___;
1206 .type   ${func}_avx,\@function,4
1207 .align  64
1208 ${func}_avx:
1209 .Lavx_shortcut:
1210         push    %rbx
1211         push    %rbp
1212         push    %r12
1213         push    %r13
1214         push    %r14
1215         push    %r15
1216         mov     %rsp,%r11               # copy %rsp
1217         shl     \$4,%rdx                # num*16
1218         sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
1219         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
1220         and     \$-64,%rsp              # align stack frame
1221         mov     $ctx,$_ctx              # save ctx, 1st arg
1222         mov     $inp,$_inp              # save inp, 2nd arh
1223         mov     %rdx,$_end              # save end pointer, "3rd" arg
1224         mov     %r11,$_rsp              # save copy of %rsp
1225 ___
1226 $code.=<<___ if ($win64);
1227         movaps  %xmm6,16*$SZ+32(%rsp)
1228         movaps  %xmm7,16*$SZ+48(%rsp)
1229         movaps  %xmm8,16*$SZ+64(%rsp)
1230         movaps  %xmm9,16*$SZ+80(%rsp)
1231 ___
1232 $code.=<<___ if ($win64 && $SZ>4);
1233         movaps  %xmm10,16*$SZ+96(%rsp)
1234         movaps  %xmm11,16*$SZ+112(%rsp)
1235 ___
1236 $code.=<<___;
1237 .Lprologue_avx:
1238
1239         vzeroall
1240         mov     $SZ*0($ctx),$A
1241         mov     $SZ*1($ctx),$B
1242         mov     $SZ*2($ctx),$C
1243         mov     $SZ*3($ctx),$D
1244         mov     $SZ*4($ctx),$E
1245         mov     $SZ*5($ctx),$F
1246         mov     $SZ*6($ctx),$G
1247         mov     $SZ*7($ctx),$H
1248 ___
1249                                         if ($SZ==4) {   # SHA256
1250     my @X = map("%xmm$_",(0..3));
1251     my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
1252
1253 $code.=<<___;
1254         vmovdqa $TABLE+`$SZ*$rounds`+16(%rip),$t4
1255         vmovdqa $TABLE+`$SZ*$rounds`+32(%rip),$t5
1256         jmp     .Lloop_avx
1257 .align  16
1258 .Lloop_avx:
1259         vmovdqa $TABLE+`$SZ*$rounds`(%rip),$t3
1260         vmovdqu 0x00($inp),@X[0]
1261         vmovdqu 0x10($inp),@X[1]
1262         vmovdqu 0x20($inp),@X[2]
1263         vmovdqu 0x30($inp),@X[3]
1264         vpshufb $t3,@X[0],@X[0]
1265         lea     $TABLE(%rip),$Tbl
1266         vpshufb $t3,@X[1],@X[1]
1267         vpshufb $t3,@X[2],@X[2]
1268         vpaddd  0x00($Tbl),@X[0],$t0
1269         vpshufb $t3,@X[3],@X[3]
1270         vpaddd  0x10($Tbl),@X[1],$t1
1271         vpaddd  0x20($Tbl),@X[2],$t2
1272         vpaddd  0x30($Tbl),@X[3],$t3
1273         vmovdqa $t0,0x00(%rsp)
1274         mov     $A,$a1
1275         vmovdqa $t1,0x10(%rsp)
1276         mov     $B,$a3
1277         vmovdqa $t2,0x20(%rsp)
1278         xor     $C,$a3                  # magic
1279         vmovdqa $t3,0x30(%rsp)
1280         mov     $E,$a0
1281         jmp     .Lavx_00_47
1282
1283 .align  16
1284 .Lavx_00_47:
1285         add     \$16*$SZ,$Tbl
1286 ___
1287 sub Xupdate_256_AVX () {
1288         (
1289         '&vpalignr      ($t0,@X[1],@X[0],$SZ)', # X[1..4]
1290          '&vpalignr     ($t3,@X[3],@X[2],$SZ)', # X[9..12]
1291         '&vpsrld        ($t2,$t0,$sigma0[0]);',
1292          '&vpaddd       (@X[0],@X[0],$t3)',     # X[0..3] += X[9..12]
1293         '&vpsrld        ($t3,$t0,$sigma0[2])',
1294         '&vpslld        ($t1,$t0,8*$SZ-$sigma0[1]);',
1295         '&vpxor         ($t0,$t3,$t2)',
1296          '&vpshufd      ($t3,@X[3],0b11111010)',# X[14..15]
1297         '&vpsrld        ($t2,$t2,$sigma0[1]-$sigma0[0]);',
1298         '&vpxor         ($t0,$t0,$t1)',
1299         '&vpslld        ($t1,$t1,$sigma0[1]-$sigma0[0]);',
1300         '&vpxor         ($t0,$t0,$t2)',
1301          '&vpsrld       ($t2,$t3,$sigma1[2]);',
1302         '&vpxor         ($t0,$t0,$t1)',         # sigma0(X[1..4])
1303          '&vpsrlq       ($t3,$t3,$sigma1[0]);',
1304         '&vpaddd        (@X[0],@X[0],$t0)',     # X[0..3] += sigma0(X[1..4])
1305          '&vpxor        ($t2,$t2,$t3);',
1306          '&vpsrlq       ($t3,$t3,$sigma1[1]-$sigma1[0])',
1307          '&vpxor        ($t2,$t2,$t3)',
1308          '&vpshufb      ($t2,$t2,$t4)',         # sigma1(X[14..15])
1309         '&vpaddd        (@X[0],@X[0],$t2)',     # X[0..1] += sigma1(X[14..15])
1310          '&vpshufd      ($t3,@X[0],0b01010000)',# X[16..17]
1311          '&vpsrld       ($t2,$t3,$sigma1[2])',
1312          '&vpsrlq       ($t3,$t3,$sigma1[0])',
1313          '&vpxor        ($t2,$t2,$t3);',
1314          '&vpsrlq       ($t3,$t3,$sigma1[1]-$sigma1[0])',
1315          '&vpxor        ($t2,$t2,$t3)',
1316          '&vpshufb      ($t2,$t2,$t5)',
1317         '&vpaddd        (@X[0],@X[0],$t2)'      # X[2..3] += sigma1(X[16..17])
1318         );
1319 }
1320
1321 sub AVX_256_00_47 () {
1322 my $j = shift;
1323 my $body = shift;
1324 my @X = @_;
1325 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
1326
1327         foreach (Xupdate_256_AVX()) {           # 29 instructions
1328             eval;
1329             eval(shift(@insns));
1330             eval(shift(@insns));
1331             eval(shift(@insns));
1332         }
1333         &vpaddd         ($t2,@X[0],16*$j."($Tbl)");
1334           foreach (@insns) { eval; }            # remaining instructions
1335         &vmovdqa        (16*$j."(%rsp)",$t2);
1336 }
1337
1338     for ($i=0,$j=0; $j<4; $j++) {
1339         &AVX_256_00_47($j,\&body_00_15,@X);
1340         push(@X,shift(@X));                     # rotate(@X)
1341     }
1342         &cmpb   ($SZ-1+16*$SZ."($Tbl)",0);
1343         &jne    (".Lavx_00_47");
1344
1345     for ($i=0; $i<16; ) {
1346         foreach(body_00_15()) { eval; }
1347     }
1348
1349                                         } else {        # SHA512
1350     my @X = map("%xmm$_",(0..7));
1351     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
1352
1353 $code.=<<___;
1354         jmp     .Lloop_avx
1355 .align  16
1356 .Lloop_avx:
1357         vmovdqa $TABLE+`$SZ*$rounds`(%rip),$t3
1358         vmovdqu 0x00($inp),@X[0]
1359         lea     $TABLE(%rip),$Tbl
1360         vmovdqu 0x10($inp),@X[1]
1361         vmovdqu 0x20($inp),@X[2]
1362         vpshufb $t3,@X[0],@X[0]
1363         vmovdqu 0x30($inp),@X[3]
1364         vpshufb $t3,@X[1],@X[1]
1365         vmovdqu 0x40($inp),@X[4]
1366         vpshufb $t3,@X[2],@X[2]
1367         vmovdqu 0x50($inp),@X[5]
1368         vpshufb $t3,@X[3],@X[3]
1369         vmovdqu 0x60($inp),@X[6]
1370         vpshufb $t3,@X[4],@X[4]
1371         vmovdqu 0x70($inp),@X[7]
1372         vpshufb $t3,@X[5],@X[5]
1373         vpaddq  0x00($Tbl),@X[0],$t0
1374         vpshufb $t3,@X[6],@X[6]
1375         vpaddq  0x10($Tbl),@X[1],$t1
1376         vpshufb $t3,@X[7],@X[7]
1377         vpaddq  0x20($Tbl),@X[2],$t2
1378         vpaddq  0x30($Tbl),@X[3],$t3
1379         vmovdqa $t0,0x00(%rsp)
1380         vpaddq  0x40($Tbl),@X[4],$t0
1381         vmovdqa $t1,0x10(%rsp)
1382         vpaddq  0x50($Tbl),@X[5],$t1
1383         vmovdqa $t2,0x20(%rsp)
1384         vpaddq  0x60($Tbl),@X[6],$t2
1385         vmovdqa $t3,0x30(%rsp)
1386         vpaddq  0x70($Tbl),@X[7],$t3
1387         vmovdqa $t0,0x40(%rsp)
1388         mov     $A,$a1
1389         vmovdqa $t1,0x50(%rsp)
1390         mov     $B,$a3
1391         vmovdqa $t2,0x60(%rsp)
1392         xor     $C,$a3                  # magic
1393         vmovdqa $t3,0x70(%rsp)
1394         mov     $E,$a0
1395         jmp     .Lavx_00_47
1396
1397 .align  16
1398 .Lavx_00_47:
1399         add     \$16*$SZ,$Tbl
1400 ___
1401 sub Xupdate_512_AVX () {
1402         (
1403         '&vpalignr      ($t0,@X[1],@X[0],$SZ)', # X[1..2]
1404          '&vpalignr     ($t3,@X[5],@X[4],$SZ)', # X[9..10]
1405         '&vpsrlq        ($t2,$t0,$sigma0[0]);',
1406          '&vpaddq       (@X[0],@X[0],$t3)',     # X[0..1] += X[9..10]
1407         '&vpsrlq        ($t3,$t0,$sigma0[2])',
1408         '&vpsllq        ($t1,$t0,8*$SZ-$sigma0[1]);',
1409          '&vpxor        ($t0,$t3,$t2)',
1410         '&vpsrlq        ($t2,$t2,$sigma0[1]-$sigma0[0]);',
1411          '&vpxor        ($t0,$t0,$t1)',
1412         '&vpsllq        ($t1,$t1,$sigma0[1]-$sigma0[0]);',
1413          '&vpxor        ($t0,$t0,$t2)',
1414          '&vpsrlq       ($t3,@X[7],$sigma1[2]);',
1415         '&vpxor         ($t0,$t0,$t1)',         # sigma0(X[1..2])
1416          '&vpsllq       ($t2,@X[7],8*$SZ-$sigma1[1])',
1417         '&vpaddq        (@X[0],@X[0],$t0)',     # X[0..1] += sigma0(X[1..2])
1418          '&vpsrlq       ($t1,@X[7],$sigma1[0]);',
1419          '&vpxor        ($t3,$t3,$t2)',
1420          '&vpsllq       ($t2,$t2,$sigma1[1]-$sigma1[0]);',
1421          '&vpxor        ($t3,$t3,$t1)',
1422          '&vpsrlq       ($t1,$t1,$sigma1[1]-$sigma1[0]);',
1423          '&vpxor        ($t3,$t3,$t2)',
1424          '&vpxor        ($t3,$t3,$t1)',         # sigma1(X[14..15])
1425         '&vpaddq        (@X[0],@X[0],$t3)',     # X[0..1] += sigma1(X[14..15])
1426         );
1427 }
1428
1429 sub AVX_512_00_47 () {
1430 my $j = shift;
1431 my $body = shift;
1432 my @X = @_;
1433 my @insns = (&$body,&$body);                    # 52 instructions
1434
1435         foreach (Xupdate_512_AVX()) {           # 23 instructions
1436             eval;
1437             eval(shift(@insns));
1438             eval(shift(@insns));
1439         }
1440         &vpaddq         ($t2,@X[0],16*$j."($Tbl)");
1441           foreach (@insns) { eval; }            # remaining instructions
1442         &vmovdqa        (16*$j."(%rsp)",$t2);
1443 }
1444
1445     for ($i=0,$j=0; $j<8; $j++) {
1446         &AVX_512_00_47($j,\&body_00_15,@X);
1447         push(@X,shift(@X));                     # rotate(@X)
1448     }
1449         &cmpb   ($SZ-1+16*$SZ."($Tbl)",0);
1450         &jne    (".Lavx_00_47");
1451
1452     for ($i=0; $i<16; ) {
1453         foreach(body_00_15()) { eval; }
1454     }
1455 }
1456 $code.=<<___;
1457         mov     $_ctx,$ctx
1458         mov     $a1,$A
1459
1460         add     $SZ*0($ctx),$A
1461         lea     16*$SZ($inp),$inp
1462         add     $SZ*1($ctx),$B
1463         add     $SZ*2($ctx),$C
1464         add     $SZ*3($ctx),$D
1465         add     $SZ*4($ctx),$E
1466         add     $SZ*5($ctx),$F
1467         add     $SZ*6($ctx),$G
1468         add     $SZ*7($ctx),$H
1469
1470         cmp     $_end,$inp
1471
1472         mov     $A,$SZ*0($ctx)
1473         mov     $B,$SZ*1($ctx)
1474         mov     $C,$SZ*2($ctx)
1475         mov     $D,$SZ*3($ctx)
1476         mov     $E,$SZ*4($ctx)
1477         mov     $F,$SZ*5($ctx)
1478         mov     $G,$SZ*6($ctx)
1479         mov     $H,$SZ*7($ctx)
1480         jb      .Lloop_avx
1481
1482         mov     $_rsp,%rsi
1483         vzeroall
1484 ___
1485 $code.=<<___ if ($win64);
1486         movaps  16*$SZ+32(%rsp),%xmm6
1487         movaps  16*$SZ+48(%rsp),%xmm7
1488         movaps  16*$SZ+64(%rsp),%xmm8
1489         movaps  16*$SZ+80(%rsp),%xmm9
1490 ___
1491 $code.=<<___ if ($win64 && $SZ>4);
1492         movaps  16*$SZ+96(%rsp),%xmm10
1493         movaps  16*$SZ+112(%rsp),%xmm11
1494 ___
1495 $code.=<<___;
1496         mov     (%rsi),%r15
1497         mov     8(%rsi),%r14
1498         mov     16(%rsi),%r13
1499         mov     24(%rsi),%r12
1500         mov     32(%rsi),%rbp
1501         mov     40(%rsi),%rbx
1502         lea     48(%rsi),%rsp
1503 .Lepilogue_avx:
1504         ret
1505 .size   ${func}_avx,.-${func}_avx
1506 ___
1507 }}}}}
1508
1509 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1510 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1511 if ($win64) {
1512 $rec="%rcx";
1513 $frame="%rdx";
1514 $context="%r8";
1515 $disp="%r9";
1516
1517 $code.=<<___;
1518 .extern __imp_RtlVirtualUnwind
1519 .type   se_handler,\@abi-omnipotent
1520 .align  16
1521 se_handler:
1522         push    %rsi
1523         push    %rdi
1524         push    %rbx
1525         push    %rbp
1526         push    %r12
1527         push    %r13
1528         push    %r14
1529         push    %r15
1530         pushfq
1531         sub     \$64,%rsp
1532
1533         mov     120($context),%rax      # pull context->Rax
1534         mov     248($context),%rbx      # pull context->Rip
1535
1536         mov     8($disp),%rsi           # disp->ImageBase
1537         mov     56($disp),%r11          # disp->HanderlData
1538
1539         mov     0(%r11),%r10d           # HandlerData[0]
1540         lea     (%rsi,%r10),%r10        # prologue label
1541         cmp     %r10,%rbx               # context->Rip<prologue label
1542         jb      .Lin_prologue
1543
1544         mov     152($context),%rax      # pull context->Rsp
1545
1546         mov     4(%r11),%r10d           # HandlerData[1]
1547         lea     (%rsi,%r10),%r10        # epilogue label
1548         cmp     %r10,%rbx               # context->Rip>=epilogue label
1549         jae     .Lin_prologue
1550
1551         mov     %rax,%rsi               # put aside Rsp
1552         mov     16*$SZ+3*8(%rax),%rax   # pull $_rsp
1553         lea     48(%rax),%rax
1554
1555         mov     -8(%rax),%rbx
1556         mov     -16(%rax),%rbp
1557         mov     -24(%rax),%r12
1558         mov     -32(%rax),%r13
1559         mov     -40(%rax),%r14
1560         mov     -48(%rax),%r15
1561         mov     %rbx,144($context)      # restore context->Rbx
1562         mov     %rbp,160($context)      # restore context->Rbp
1563         mov     %r12,216($context)      # restore context->R12
1564         mov     %r13,224($context)      # restore context->R13
1565         mov     %r14,232($context)      # restore context->R14
1566         mov     %r15,240($context)      # restore context->R15
1567
1568         lea     .Lepilogue(%rip),%r10
1569         cmp     %r10,%rbx
1570         jb      .Lin_prologue           # non-AVX code
1571
1572         lea     16*$SZ+4*8(%rsi),%rsi   # Xmm6- save area
1573         lea     512($context),%rdi      # &context.Xmm6
1574         mov     \$`$SZ==4?8:12`,%ecx
1575         .long   0xa548f3fc              # cld; rep movsq
1576
1577 .Lin_prologue:
1578         mov     8(%rax),%rdi
1579         mov     16(%rax),%rsi
1580         mov     %rax,152($context)      # restore context->Rsp
1581         mov     %rsi,168($context)      # restore context->Rsi
1582         mov     %rdi,176($context)      # restore context->Rdi
1583
1584         mov     40($disp),%rdi          # disp->ContextRecord
1585         mov     $context,%rsi           # context
1586         mov     \$154,%ecx              # sizeof(CONTEXT)
1587         .long   0xa548f3fc              # cld; rep movsq
1588
1589         mov     $disp,%rsi
1590         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1591         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1592         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1593         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1594         mov     40(%rsi),%r10           # disp->ContextRecord
1595         lea     56(%rsi),%r11           # &disp->HandlerData
1596         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1597         mov     %r10,32(%rsp)           # arg5
1598         mov     %r11,40(%rsp)           # arg6
1599         mov     %r12,48(%rsp)           # arg7
1600         mov     %rcx,56(%rsp)           # arg8, (NULL)
1601         call    *__imp_RtlVirtualUnwind(%rip)
1602
1603         mov     \$1,%eax                # ExceptionContinueSearch
1604         add     \$64,%rsp
1605         popfq
1606         pop     %r15
1607         pop     %r14
1608         pop     %r13
1609         pop     %r12
1610         pop     %rbp
1611         pop     %rbx
1612         pop     %rdi
1613         pop     %rsi
1614         ret
1615 .size   se_handler,.-se_handler
1616
1617 .section        .pdata
1618 .align  4
1619         .rva    .LSEH_begin_$func
1620         .rva    .LSEH_end_$func
1621         .rva    .LSEH_info_$func
1622 ___
1623 $code.=<<___ if ($SZ==4);
1624         .rva    .LSEH_begin_${func}_ssse3
1625         .rva    .LSEH_end_${func}_ssse3
1626         .rva    .LSEH_info_${func}_ssse3
1627 ___
1628 $code.=<<___ if ($avx && $SZ==8);
1629         .rva    .LSEH_begin_${func}_xop
1630         .rva    .LSEH_end_${func}_xop
1631         .rva    .LSEH_info_${func}_xop
1632 ___
1633 $code.=<<___ if ($avx);
1634         .rva    .LSEH_begin_${func}_avx
1635         .rva    .LSEH_end_${func}_avx
1636         .rva    .LSEH_info_${func}_avx
1637 ___
1638 $code.=<<___;
1639 .section        .xdata
1640 .align  8
1641 .LSEH_info_$func:
1642         .byte   9,0,0,0
1643         .rva    se_handler
1644         .rva    .Lprologue,.Lepilogue                   # HandlerData[]
1645 ___
1646 $code.=<<___ if ($SZ==4);
1647 .LSEH_info_${func}_ssse3:
1648         .byte   9,0,0,0
1649         .rva    se_handler
1650         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
1651 ___
1652 $code.=<<___ if ($avx && $SZ==8);
1653 .LSEH_info_${func}_xop:
1654         .byte   9,0,0,0
1655         .rva    se_handler
1656         .rva    .Lprologue_xop,.Lepilogue_xop           # HandlerData[]
1657 ___
1658 $code.=<<___ if ($avx);
1659 .LSEH_info_${func}_avx:
1660         .byte   9,0,0,0
1661         .rva    se_handler
1662         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
1663 ___
1664 }
1665
1666 $code =~ s/\`([^\`]*)\`/eval $1/gem;
1667 print $code;
1668 close STDOUT;