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