8f4e6516260b22ecad3b01d8693b212c05ba52c0
[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 # November 2012.
64 #
65 # Add AVX2 code path. Two consecutive input blocks are loaded to
66 # 256-bit %ymm registers, with data from first block to least
67 # significant 128-bit halves and data from second to most significant.
68 # The data is then processed with same SIMD instruction sequence as
69 # for AVX, but with %ymm as operands. Side effect is increased stack
70 # frame, 448 additional bytes in SHA256 and 1152 in SHA512.
71
72 ######################################################################
73 # Current performance in cycles per processed byte (less is better):
74 #
75 #               SHA256  SSSE3       AVX/XOP(*)      SHA512  AVX/XOP(*)
76 #
77 # AMD K8        15.1    -           -               9.70    -
78 # P4            17.5    -           -               33.4    -
79 # Core 2        15.5    13.8(+12%)  -               10.3    -
80 # Westmere      15.1    12.7(+19%)  -               9.72    -
81 # Sandy Bridge  17.4    14.2(+23%)  11.6(+50%(**))  11.2    8.10(+38%(**))
82 # Ivy Bridge    12.6    10.5(+20%)  10.3(+22%)      8.17    7.22(+13%)
83 # Bulldozer     21.5    13.7(+57%)  13.7(+57%(***)) 13.5    8.58(+57%)
84 # VIA Nano      23.0    16.5(+39%)  -               14.7    -
85 # Atom          23.0    18.7(+23%)  -               14.7    -
86 #
87 # (*)   whichever best applicable;
88 # (**)  switch from ror to shrd stands for fair share of improvement;
89 # (***) execution time is fully determined by remaining integer-only
90 #       part, body_00_15; reducing the amount of SIMD instructions
91 #       below certain limit makes no difference/sense; to conserve
92 #       space SHA256 XOP code path is therefore omitted;
93
94 $flavour = shift;
95 $output  = shift;
96 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
97
98 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
99
100 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
101 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
102 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
103 die "can't locate x86_64-xlate.pl";
104
105 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
106                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
107         $avx = ($1>=2.19) + ($1>=2.22);
108 }
109
110 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
111            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
112         $avx = ($1>=2.09) + ($1>=2.10);
113 }
114
115 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
116            `ml64 2>&1` =~ /Version ([0-9]+)\./) {
117         $avx = ($1>=10) + ($1>=11);
118 }
119
120 open OUT,"| \"$^X\" $xlate $flavour $output";
121 *STDOUT=*OUT;
122
123 if ($output =~ /512/) {
124         $func="sha512_block_data_order";
125         $TABLE="K512";
126         $SZ=8;
127         @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx",
128                                         "%r8", "%r9", "%r10","%r11");
129         ($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi");
130         @Sigma0=(28,34,39);
131         @Sigma1=(14,18,41);
132         @sigma0=(1,  8, 7);
133         @sigma1=(19,61, 6);
134         $rounds=80;
135 } else {
136         $func="sha256_block_data_order";
137         $TABLE="K256";
138         $SZ=4;
139         @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx",
140                                         "%r8d","%r9d","%r10d","%r11d");
141         ($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi");
142         @Sigma0=( 2,13,22);
143         @Sigma1=( 6,11,25);
144         @sigma0=( 7,18, 3);
145         @sigma1=(17,19,10);
146         $rounds=64;
147 }
148
149 $ctx="%rdi";    # 1st arg, zapped by $a3
150 $inp="%rsi";    # 2nd arg
151 $Tbl="%rbp";
152
153 $_ctx="16*$SZ+0*8(%rsp)";
154 $_inp="16*$SZ+1*8(%rsp)";
155 $_end="16*$SZ+2*8(%rsp)";
156 $_rsp="16*$SZ+3*8(%rsp)";
157 $framesz="16*$SZ+4*8";
158
159
160 sub ROUND_00_15()
161 { my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
162   my $STRIDE=$SZ;
163      $STRIDE += 16 if ($i%(16/$SZ)==(16/$SZ-1));
164
165 $code.=<<___;
166         ror     \$`$Sigma1[2]-$Sigma1[1]`,$a0
167         mov     $f,$a2
168
169         ror     \$`$Sigma0[2]-$Sigma0[1]`,$a1
170         xor     $e,$a0
171         xor     $g,$a2                  # f^g
172
173         mov     $T1,`$SZ*($i&0xf)`(%rsp)
174         xor     $a,$a1
175         and     $e,$a2                  # (f^g)&e
176
177         ror     \$`$Sigma1[1]-$Sigma1[0]`,$a0
178         add     $h,$T1                  # T1+=h
179         xor     $g,$a2                  # Ch(e,f,g)=((f^g)&e)^g
180
181         ror     \$`$Sigma0[1]-$Sigma0[0]`,$a1
182         xor     $e,$a0
183         add     $a2,$T1                 # T1+=Ch(e,f,g)
184
185         mov     $a,$a2
186         add     ($Tbl),$T1              # T1+=K[round]
187         xor     $a,$a1
188
189         ror     \$$Sigma1[0],$a0        # Sigma1(e)
190         xor     $b,$a2                  # a^b, b^c in next round
191         mov     $b,$h
192
193         ror     \$$Sigma0[0],$a1        # Sigma0(a)
194         and     $a2,$a3
195         add     $a0,$T1                 # T1+=Sigma1(e)
196
197         xor     $a3,$h                  # h=Maj(a,b,c)=Ch(a^b,c,b)
198         add     $T1,$d                  # d+=T1
199         add     $T1,$h                  # h+=T1
200 ___
201 $code.=<<___ if ($i>=15);
202         mov     `$SZ*(($i+2)&0xf)`(%rsp),$a0
203 ___
204 $code.=<<___;
205         lea     $STRIDE($Tbl),$Tbl      # round++
206         add     $a1,$h                  # h+=Sigma0(a)
207
208 ___
209         ($a2,$a3) = ($a3,$a2);
210 }
211
212 sub ROUND_16_XX()
213 { my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
214
215 $code.=<<___;
216         #mov    `$SZ*(($i+1)&0xf)`(%rsp),$a0
217         mov     `$SZ*(($i+14)&0xf)`(%rsp),$a1
218
219         mov     $a0,$T1
220         ror     \$`$sigma0[1]-$sigma0[0]`,$a0
221         mov     $a1,$a2
222         ror     \$`$sigma1[1]-$sigma1[0]`,$a1
223
224         xor     $T1,$a0
225         shr     \$$sigma0[2],$T1
226         ror     \$$sigma0[0],$a0
227         xor     $a2,$a1
228         shr     \$$sigma1[2],$a2
229
230         xor     $a0,$T1                 # sigma0(X[(i+1)&0xf])
231         ror     \$$sigma1[0],$a1
232         add     `$SZ*(($i+9)&0xf)`(%rsp),$T1
233         xor     $a2,$a1                 # sigma1(X[(i+14)&0xf])
234
235         add     `$SZ*($i&0xf)`(%rsp),$T1
236         mov     $e,$a0
237         add     $a1,$T1
238         mov     $a,$a1
239 ___
240         &ROUND_00_15(@_);
241 }
242
243 $code=<<___;
244 .text
245
246 .extern OPENSSL_ia32cap_P
247 .globl  $func
248 .type   $func,\@function,3
249 .align  16
250 $func:
251 ___
252 $code.=<<___ if ($SZ==4 || $avx);
253         lea     OPENSSL_ia32cap_P(%rip),%r11
254         mov     0(%r11),%r9d
255         mov     4(%r11),%r10d
256         mov     8(%r11),%r11d
257 ___
258 $code.=<<___ if ($avx && $SZ==8);
259         test    \$`1<<11`,%r10d         # check for XOP
260         jnz     .Lxop_shortcut
261 ___
262 $code.=<<___ if ($avx>1);
263         and     \$`1<<8|1<<5|1<<3`,%r11d        # check for BMI2+AVX2+BMI1
264         cmp     \$`1<<8|1<<5|1<<3`,%r11d
265         je      .Lavx2_shortcut
266 ___
267 $code.=<<___ if ($avx);
268         and     \$`1<<30`,%r9d          # mask "Intel CPU" bit
269         and     \$`1<<28|1<<9`,%r10d    # mask AVX and SSSE3 bits
270         or      %r9d,%r10d
271         cmp     \$`1<<28|1<<9|1<<30`,%r10d
272         je      .Lavx_shortcut
273 ___
274 $code.=<<___ if ($SZ==4);
275         test    \$`1<<9`,%r10d
276         jnz     .Lssse3_shortcut
277 ___
278 $code.=<<___;
279         push    %rbx
280         push    %rbp
281         push    %r12
282         push    %r13
283         push    %r14
284         push    %r15
285         mov     %rsp,%r11               # copy %rsp
286         shl     \$4,%rdx                # num*16
287         sub     \$$framesz,%rsp
288         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
289         and     \$-64,%rsp              # align stack frame
290         mov     $ctx,$_ctx              # save ctx, 1st arg
291         mov     $inp,$_inp              # save inp, 2nd arh
292         mov     %rdx,$_end              # save end pointer, "3rd" arg
293         mov     %r11,$_rsp              # save copy of %rsp
294 .Lprologue:
295
296         mov     $SZ*0($ctx),$A
297         mov     $SZ*1($ctx),$B
298         mov     $SZ*2($ctx),$C
299         mov     $SZ*3($ctx),$D
300         mov     $SZ*4($ctx),$E
301         mov     $SZ*5($ctx),$F
302         mov     $SZ*6($ctx),$G
303         mov     $SZ*7($ctx),$H
304         jmp     .Lloop
305
306 .align  16
307 .Lloop:
308         mov     $B,$a3
309         lea     $TABLE(%rip),$Tbl
310         xor     $C,$a3                  # magic
311 ___
312         for($i=0;$i<16;$i++) {
313                 $code.="        mov     $SZ*$i($inp),$T1\n";
314                 $code.="        mov     @ROT[4],$a0\n";
315                 $code.="        mov     @ROT[0],$a1\n";
316                 $code.="        bswap   $T1\n";
317                 &ROUND_00_15($i,@ROT);
318                 unshift(@ROT,pop(@ROT));
319         }
320 $code.=<<___;
321         jmp     .Lrounds_16_xx
322 .align  16
323 .Lrounds_16_xx:
324 ___
325         for(;$i<32;$i++) {
326                 &ROUND_16_XX($i,@ROT);
327                 unshift(@ROT,pop(@ROT));
328         }
329
330 $code.=<<___;
331         cmpb    \$0,`$SZ-1`($Tbl)
332         jnz     .Lrounds_16_xx
333
334         mov     $_ctx,$ctx
335         lea     16*$SZ($inp),$inp
336
337         add     $SZ*0($ctx),$A
338         add     $SZ*1($ctx),$B
339         add     $SZ*2($ctx),$C
340         add     $SZ*3($ctx),$D
341         add     $SZ*4($ctx),$E
342         add     $SZ*5($ctx),$F
343         add     $SZ*6($ctx),$G
344         add     $SZ*7($ctx),$H
345
346         cmp     $_end,$inp
347
348         mov     $A,$SZ*0($ctx)
349         mov     $B,$SZ*1($ctx)
350         mov     $C,$SZ*2($ctx)
351         mov     $D,$SZ*3($ctx)
352         mov     $E,$SZ*4($ctx)
353         mov     $F,$SZ*5($ctx)
354         mov     $G,$SZ*6($ctx)
355         mov     $H,$SZ*7($ctx)
356         jb      .Lloop
357
358         mov     $_rsp,%rsi
359         mov     (%rsi),%r15
360         mov     8(%rsi),%r14
361         mov     16(%rsi),%r13
362         mov     24(%rsi),%r12
363         mov     32(%rsi),%rbp
364         mov     40(%rsi),%rbx
365         lea     48(%rsi),%rsp
366 .Lepilogue:
367         ret
368 .size   $func,.-$func
369 ___
370
371 if ($SZ==4) {
372 $code.=<<___;
373 .align  64
374 .type   $TABLE,\@object
375 $TABLE:
376         .long   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
377         .long   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
378         .long   0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
379         .long   0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
380         .long   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
381         .long   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
382         .long   0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
383         .long   0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
384         .long   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
385         .long   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
386         .long   0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
387         .long   0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
388         .long   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
389         .long   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
390         .long   0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
391         .long   0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
392         .long   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
393         .long   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
394         .long   0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
395         .long   0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
396         .long   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
397         .long   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
398         .long   0xd192e819,0xd6990624,0xf40e3585,0x106aa070
399         .long   0xd192e819,0xd6990624,0xf40e3585,0x106aa070
400         .long   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
401         .long   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
402         .long   0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
403         .long   0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
404         .long   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
405         .long   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
406         .long   0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
407         .long   0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
408
409         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
410         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
411         .long   0x03020100,0x0b0a0908,0xffffffff,0xffffffff
412         .long   0x03020100,0x0b0a0908,0xffffffff,0xffffffff
413         .long   0xffffffff,0xffffffff,0x03020100,0x0b0a0908
414         .long   0xffffffff,0xffffffff,0x03020100,0x0b0a0908
415         .asciz  "SHA256 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
416 ___
417 } else {
418 $code.=<<___;
419 .align  64
420 .type   $TABLE,\@object
421 $TABLE:
422         .quad   0x428a2f98d728ae22,0x7137449123ef65cd
423         .quad   0x428a2f98d728ae22,0x7137449123ef65cd
424         .quad   0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
425         .quad   0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
426         .quad   0x3956c25bf348b538,0x59f111f1b605d019
427         .quad   0x3956c25bf348b538,0x59f111f1b605d019
428         .quad   0x923f82a4af194f9b,0xab1c5ed5da6d8118
429         .quad   0x923f82a4af194f9b,0xab1c5ed5da6d8118
430         .quad   0xd807aa98a3030242,0x12835b0145706fbe
431         .quad   0xd807aa98a3030242,0x12835b0145706fbe
432         .quad   0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
433         .quad   0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
434         .quad   0x72be5d74f27b896f,0x80deb1fe3b1696b1
435         .quad   0x72be5d74f27b896f,0x80deb1fe3b1696b1
436         .quad   0x9bdc06a725c71235,0xc19bf174cf692694
437         .quad   0x9bdc06a725c71235,0xc19bf174cf692694
438         .quad   0xe49b69c19ef14ad2,0xefbe4786384f25e3
439         .quad   0xe49b69c19ef14ad2,0xefbe4786384f25e3
440         .quad   0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
441         .quad   0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
442         .quad   0x2de92c6f592b0275,0x4a7484aa6ea6e483
443         .quad   0x2de92c6f592b0275,0x4a7484aa6ea6e483
444         .quad   0x5cb0a9dcbd41fbd4,0x76f988da831153b5
445         .quad   0x5cb0a9dcbd41fbd4,0x76f988da831153b5
446         .quad   0x983e5152ee66dfab,0xa831c66d2db43210
447         .quad   0x983e5152ee66dfab,0xa831c66d2db43210
448         .quad   0xb00327c898fb213f,0xbf597fc7beef0ee4
449         .quad   0xb00327c898fb213f,0xbf597fc7beef0ee4
450         .quad   0xc6e00bf33da88fc2,0xd5a79147930aa725
451         .quad   0xc6e00bf33da88fc2,0xd5a79147930aa725
452         .quad   0x06ca6351e003826f,0x142929670a0e6e70
453         .quad   0x06ca6351e003826f,0x142929670a0e6e70
454         .quad   0x27b70a8546d22ffc,0x2e1b21385c26c926
455         .quad   0x27b70a8546d22ffc,0x2e1b21385c26c926
456         .quad   0x4d2c6dfc5ac42aed,0x53380d139d95b3df
457         .quad   0x4d2c6dfc5ac42aed,0x53380d139d95b3df
458         .quad   0x650a73548baf63de,0x766a0abb3c77b2a8
459         .quad   0x650a73548baf63de,0x766a0abb3c77b2a8
460         .quad   0x81c2c92e47edaee6,0x92722c851482353b
461         .quad   0x81c2c92e47edaee6,0x92722c851482353b
462         .quad   0xa2bfe8a14cf10364,0xa81a664bbc423001
463         .quad   0xa2bfe8a14cf10364,0xa81a664bbc423001
464         .quad   0xc24b8b70d0f89791,0xc76c51a30654be30
465         .quad   0xc24b8b70d0f89791,0xc76c51a30654be30
466         .quad   0xd192e819d6ef5218,0xd69906245565a910
467         .quad   0xd192e819d6ef5218,0xd69906245565a910
468         .quad   0xf40e35855771202a,0x106aa07032bbd1b8
469         .quad   0xf40e35855771202a,0x106aa07032bbd1b8
470         .quad   0x19a4c116b8d2d0c8,0x1e376c085141ab53
471         .quad   0x19a4c116b8d2d0c8,0x1e376c085141ab53
472         .quad   0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
473         .quad   0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
474         .quad   0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
475         .quad   0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
476         .quad   0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
477         .quad   0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
478         .quad   0x748f82ee5defb2fc,0x78a5636f43172f60
479         .quad   0x748f82ee5defb2fc,0x78a5636f43172f60
480         .quad   0x84c87814a1f0ab72,0x8cc702081a6439ec
481         .quad   0x84c87814a1f0ab72,0x8cc702081a6439ec
482         .quad   0x90befffa23631e28,0xa4506cebde82bde9
483         .quad   0x90befffa23631e28,0xa4506cebde82bde9
484         .quad   0xbef9a3f7b2c67915,0xc67178f2e372532b
485         .quad   0xbef9a3f7b2c67915,0xc67178f2e372532b
486         .quad   0xca273eceea26619c,0xd186b8c721c0c207
487         .quad   0xca273eceea26619c,0xd186b8c721c0c207
488         .quad   0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
489         .quad   0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
490         .quad   0x06f067aa72176fba,0x0a637dc5a2c898a6
491         .quad   0x06f067aa72176fba,0x0a637dc5a2c898a6
492         .quad   0x113f9804bef90dae,0x1b710b35131c471b
493         .quad   0x113f9804bef90dae,0x1b710b35131c471b
494         .quad   0x28db77f523047d84,0x32caab7b40c72493
495         .quad   0x28db77f523047d84,0x32caab7b40c72493
496         .quad   0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
497         .quad   0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
498         .quad   0x4cc5d4becb3e42b6,0x597f299cfc657e2a
499         .quad   0x4cc5d4becb3e42b6,0x597f299cfc657e2a
500         .quad   0x5fcb6fab3ad6faec,0x6c44198c4a475817
501         .quad   0x5fcb6fab3ad6faec,0x6c44198c4a475817
502
503         .quad   0x0001020304050607,0x08090a0b0c0d0e0f
504         .quad   0x0001020304050607,0x08090a0b0c0d0e0f
505         .asciz  "SHA512 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
506 ___
507 }
508
509 ######################################################################
510 # SIMD code paths
511 #
512 {{{
513
514 my $a4=$T1;
515 my ($a,$b,$c,$d,$e,$f,$g,$h);
516
517 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
518 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
519   my $arg = pop;
520     $arg = "\$$arg" if ($arg*1 eq $arg);
521     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
522 }
523
524 sub body_00_15 () {
525         (
526         '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
527
528         '&ror   ($a0,$Sigma1[2]-$Sigma1[1])',
529         '&mov   ($a,$a1)',
530         '&mov   ($a4,$f)',
531
532         '&xor   ($a0,$e)',
533         '&ror   ($a1,$Sigma0[2]-$Sigma0[1])',
534         '&xor   ($a4,$g)',                      # f^g
535
536         '&ror   ($a0,$Sigma1[1]-$Sigma1[0])',
537         '&xor   ($a1,$a)',
538         '&and   ($a4,$e)',                      # (f^g)&e
539
540         '&xor   ($a0,$e)',
541         '&add   ($h,$SZ*($i&15)."(%rsp)")',     # h+=X[i]+K[i]
542         '&mov   ($a2,$a)',
543
544         '&ror   ($a1,$Sigma0[1]-$Sigma0[0])',
545         '&xor   ($a4,$g)',                      # Ch(e,f,g)=((f^g)&e)^g
546         '&xor   ($a2,$b)',                      # a^b, b^c in next round
547
548         '&ror   ($a0,$Sigma1[0])',              # Sigma1(e)
549         '&add   ($h,$a4)',                      # h+=Ch(e,f,g)
550         '&and   ($a3,$a2)',                     # (b^c)&(a^b)
551
552         '&xor   ($a1,$a)',
553         '&add   ($h,$a0)',                      # h+=Sigma1(e)
554         '&xor   ($a3,$b)',                      # Maj(a,b,c)=Ch(a^b,c,b)
555
556         '&add   ($d,$h)',                       # d+=h
557         '&ror   ($a1,$Sigma0[0])',              # Sigma0(a)
558         '&add   ($h,$a3)',                      # h+=Maj(a,b,c)
559
560         '&mov   ($a0,$d)',
561         '&add   ($a1,$h);'.                     # h+=Sigma0(a)
562         '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
563         );
564 }
565
566 ######################################################################
567 # SSSE3 code path
568 #
569 if ($SZ==4) {   # SHA256 only
570 my @X = map("%xmm$_",(0..3));
571 my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
572
573 $code.=<<___;
574 .type   ${func}_ssse3,\@function,3
575 .align  64
576 ${func}_ssse3:
577 .Lssse3_shortcut:
578         push    %rbx
579         push    %rbp
580         push    %r12
581         push    %r13
582         push    %r14
583         push    %r15
584         mov     %rsp,%r11               # copy %rsp
585         shl     \$4,%rdx                # num*16
586         sub     \$`$framesz+$win64*16*4`,%rsp
587         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
588         and     \$-64,%rsp              # align stack frame
589         mov     $ctx,$_ctx              # save ctx, 1st arg
590         mov     $inp,$_inp              # save inp, 2nd arh
591         mov     %rdx,$_end              # save end pointer, "3rd" arg
592         mov     %r11,$_rsp              # save copy of %rsp
593 ___
594 $code.=<<___ if ($win64);
595         movaps  %xmm6,16*$SZ+32(%rsp)
596         movaps  %xmm7,16*$SZ+48(%rsp)
597         movaps  %xmm8,16*$SZ+64(%rsp)
598         movaps  %xmm9,16*$SZ+80(%rsp)
599 ___
600 $code.=<<___;
601 .Lprologue_ssse3:
602
603         mov     $SZ*0($ctx),$A
604         mov     $SZ*1($ctx),$B
605         mov     $SZ*2($ctx),$C
606         mov     $SZ*3($ctx),$D
607         mov     $SZ*4($ctx),$E
608         mov     $SZ*5($ctx),$F
609         mov     $SZ*6($ctx),$G
610         mov     $SZ*7($ctx),$H
611 ___
612
613 $code.=<<___;
614         #movdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
615         #movdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
616         jmp     .Lloop_ssse3
617 .align  16
618 .Lloop_ssse3:
619         movdqa  $TABLE+`$SZ*2*$rounds`(%rip),$t3
620         movdqu  0x00($inp),@X[0]
621         movdqu  0x10($inp),@X[1]
622         movdqu  0x20($inp),@X[2]
623         movdqu  0x30($inp),@X[3]
624         pshufb  $t3,@X[0]
625         lea     $TABLE(%rip),$Tbl
626         pshufb  $t3,@X[1]
627         movdqa  0x00($Tbl),$t0
628         pshufb  $t3,@X[2]
629         movdqa  0x20($Tbl),$t1
630         paddd   @X[0],$t0
631         movdqa  0x40($Tbl),$t2
632         pshufb  $t3,@X[3]
633         movdqa  0x60($Tbl),$t3
634         paddd   @X[1],$t1
635         paddd   @X[2],$t2
636         paddd   @X[3],$t3
637         movdqa  $t0,0x00(%rsp)
638         mov     $A,$a1
639         movdqa  $t1,0x10(%rsp)
640         mov     $B,$a3
641         movdqa  $t2,0x20(%rsp)
642         xor     $C,$a3                  # magic
643         movdqa  $t3,0x30(%rsp)
644         mov     $E,$a0
645         jmp     .Lssse3_00_47
646
647 .align  16
648 .Lssse3_00_47:
649         sub     \$-16*2*$SZ,$Tbl        # size optimization
650 ___
651 sub Xupdate_256_SSSE3 () {
652         (
653         '&movdqa        ($t0,@X[1]);',
654         '&movdqa        ($t3,@X[3])',
655         '&palignr       ($t0,@X[0],$SZ)',       # X[1..4]
656          '&palignr      ($t3,@X[2],$SZ);',      # X[9..12]
657         '&movdqa        ($t1,$t0)',
658         '&movdqa        ($t2,$t0);',
659         '&psrld         ($t0,$sigma0[2])',
660          '&paddd        (@X[0],$t3);',          # X[0..3] += X[9..12]
661         '&psrld         ($t2,$sigma0[0])',
662          '&pshufd       ($t3,@X[3],0b11111010)',# X[14..15]
663         '&pslld         ($t1,8*$SZ-$sigma0[1]);'.
664         '&pxor          ($t0,$t2)',
665         '&psrld         ($t2,$sigma0[1]-$sigma0[0]);'.
666         '&pxor          ($t0,$t1)',
667         '&pslld         ($t1,$sigma0[1]-$sigma0[0]);'.
668         '&pxor          ($t0,$t2);',
669          '&movdqa       ($t2,$t3)',
670         '&pxor          ($t0,$t1);',            # sigma0(X[1..4])
671          '&psrld        ($t3,$sigma1[2])',
672         '&paddd         (@X[0],$t0);',          # X[0..3] += sigma0(X[1..4])
673          '&psrlq        ($t2,$sigma1[0])',
674          '&pxor         ($t3,$t2);',
675          '&psrlq        ($t2,$sigma1[1]-$sigma1[0])',
676          '&pxor         ($t3,$t2)',
677          '&pshufb       ($t3,$t4)',             # sigma1(X[14..15])
678         '&paddd         (@X[0],$t3)',           # X[0..1] += sigma1(X[14..15])
679          '&pshufd       ($t3,@X[0],0b01010000)',# X[16..17]
680          '&movdqa       ($t2,$t3);',
681          '&psrld        ($t3,$sigma1[2])',
682          '&psrlq        ($t2,$sigma1[0])',
683          '&pxor         ($t3,$t2);',
684          '&psrlq        ($t2,$sigma1[1]-$sigma1[0])',
685          '&pxor         ($t3,$t2);',
686         '&movdqa        ($t2,16*2*$j."($Tbl)")',
687          '&pshufb       ($t3,$t5)',
688         '&paddd         (@X[0],$t3)'            # X[2..3] += sigma1(X[16..17])
689         );
690 }
691
692 sub SSSE3_256_00_47 () {
693 my $j = shift;
694 my $body = shift;
695 my @X = @_;
696 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
697
698     if (0) {
699         foreach (Xupdate_256_SSSE3()) {         # 36 instructions
700             eval;
701             eval(shift(@insns));
702             eval(shift(@insns));
703             eval(shift(@insns));
704         }
705     } else {                    # squeeze extra 3% on Westmere and Atom
706           eval(shift(@insns));  #@
707           eval(shift(@insns));
708         &movdqa         ($t0,@X[1]);
709           eval(shift(@insns));
710         &movdqa         ($t3,@X[3]);
711           eval(shift(@insns));
712           eval(shift(@insns));  #@
713           eval(shift(@insns));
714         &palignr        ($t0,@X[0],$SZ);        # X[1..4]
715           eval(shift(@insns));  #@
716           eval(shift(@insns));
717          &palignr       ($t3,@X[2],$SZ);        # X[9..12]
718           eval(shift(@insns));
719           eval(shift(@insns));
720           eval(shift(@insns));
721           eval(shift(@insns));
722           eval(shift(@insns));  #@
723           eval(shift(@insns));
724         &movdqa         ($t1,$t0);
725           eval(shift(@insns));
726         &movdqa         ($t2,$t0);
727           eval(shift(@insns));  #@
728           eval(shift(@insns));
729           eval(shift(@insns));
730         &psrld          ($t0,$sigma0[2]);
731           eval(shift(@insns));
732           eval(shift(@insns));
733           eval(shift(@insns));
734          &paddd         (@X[0],$t3);            # X[0..3] += X[9..12]
735           eval(shift(@insns));
736           eval(shift(@insns));  #@
737           eval(shift(@insns));
738         &psrld          ($t2,$sigma0[0]);
739           eval(shift(@insns));
740           eval(shift(@insns));
741           eval(shift(@insns));  #@
742           eval(shift(@insns));
743          &pshufd        ($t3,@X[3],0b11111010); # X[4..15]
744           eval(shift(@insns));
745         &pslld          ($t1,8*$SZ-$sigma0[1]);
746           eval(shift(@insns));
747         &pxor           ($t0,$t2);
748           eval(shift(@insns));  #@
749           eval(shift(@insns));
750         &psrld          ($t2,$sigma0[1]-$sigma0[0]);
751           eval(shift(@insns));  #@
752           eval(shift(@insns));
753         &pxor           ($t0,$t1);
754           eval(shift(@insns));
755           eval(shift(@insns));
756         &pslld          ($t1,$sigma0[1]-$sigma0[0]);
757           eval(shift(@insns));
758         &pxor           ($t0,$t2);
759           eval(shift(@insns));
760           eval(shift(@insns));  #@
761           eval(shift(@insns));
762          &movdqa        ($t2,$t3);
763           eval(shift(@insns));
764           eval(shift(@insns));  #@
765           eval(shift(@insns));
766         &pxor           ($t0,$t1);              # sigma0(X[1..4])
767           eval(shift(@insns));
768           eval(shift(@insns));
769          &psrld         ($t3,$sigma1[2]);
770           eval(shift(@insns));
771           eval(shift(@insns));
772         &paddd          (@X[0],$t0);            # X[0..3] += sigma0(X[1..4])
773           eval(shift(@insns));
774           eval(shift(@insns));  #@
775           eval(shift(@insns));
776           eval(shift(@insns));
777          &psrlq         ($t2,$sigma1[0]);
778           eval(shift(@insns));
779           eval(shift(@insns));  #@
780           eval(shift(@insns));
781           eval(shift(@insns));
782          &pxor          ($t3,$t2);
783           eval(shift(@insns));
784           eval(shift(@insns));  #@
785          &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
786           eval(shift(@insns));
787           eval(shift(@insns));  #@
788           eval(shift(@insns));
789          &pxor          ($t3,$t2);
790           eval(shift(@insns));
791           eval(shift(@insns));
792           eval(shift(@insns));
793          #&pshufb       ($t3,$t4);              # sigma1(X[14..15])
794          &pshufd        ($t3,$t3,0b10000000);
795           eval(shift(@insns));
796           eval(shift(@insns));  #@
797           eval(shift(@insns));
798          &psrldq        ($t3,8);
799           eval(shift(@insns));
800           eval(shift(@insns));  #@
801         &paddd          (@X[0],$t3);            # X[0..1] += sigma1(X[14..15])
802           eval(shift(@insns));
803          &pshufd        ($t3,@X[0],0b01010000); # X[16..17]
804           eval(shift(@insns));
805           eval(shift(@insns));
806           eval(shift(@insns));
807           eval(shift(@insns));
808          &movdqa        ($t2,$t3);
809           eval(shift(@insns));
810           eval(shift(@insns));  #@
811           eval(shift(@insns));
812          &psrld         ($t3,$sigma1[2]);
813           eval(shift(@insns));
814          &psrlq         ($t2,$sigma1[0]);
815           eval(shift(@insns));
816           eval(shift(@insns));  #@
817           eval(shift(@insns));
818           eval(shift(@insns));
819          &pxor          ($t3,$t2);
820           eval(shift(@insns));
821           eval(shift(@insns));  #@
822           eval(shift(@insns));
823          &psrlq         ($t2,$sigma1[1]-$sigma1[0]);
824           eval(shift(@insns));  #@
825           eval(shift(@insns));
826           eval(shift(@insns));
827           eval(shift(@insns));
828          &pxor          ($t3,$t2);
829           eval(shift(@insns));
830           eval(shift(@insns));
831         &movdqa         ($t2,16*2*$j."($Tbl)");
832           eval(shift(@insns));  #@
833           eval(shift(@insns));
834          #&pshufb       ($t3,$t5);
835          &pshufd        ($t3,$t3,0b00001000);
836           eval(shift(@insns));
837           eval(shift(@insns));  #@
838           eval(shift(@insns));
839          &pslldq        ($t3,8);
840           eval(shift(@insns));
841           eval(shift(@insns));
842         &paddd          (@X[0],$t3);            # X[2..3] += sigma1(X[16..17])
843           eval(shift(@insns));
844           eval(shift(@insns));
845           eval(shift(@insns));
846     }
847         &paddd          ($t2,@X[0]);
848           foreach (@insns) { eval; }            # remaining instructions
849         &movdqa         (16*$j."(%rsp)",$t2);
850 }
851
852     for ($i=0,$j=0; $j<4; $j++) {
853         &SSSE3_256_00_47($j,\&body_00_15,@X);
854         push(@X,shift(@X));                     # rotate(@X)
855     }
856         &cmpb   ($SZ-1+16*2*$SZ."($Tbl)",0);
857         &jne    (".Lssse3_00_47");
858
859     for ($i=0; $i<16; ) {
860         foreach(body_00_15()) { eval; }
861     }
862 $code.=<<___;
863         mov     $_ctx,$ctx
864         mov     $a1,$A
865
866         add     $SZ*0($ctx),$A
867         lea     16*$SZ($inp),$inp
868         add     $SZ*1($ctx),$B
869         add     $SZ*2($ctx),$C
870         add     $SZ*3($ctx),$D
871         add     $SZ*4($ctx),$E
872         add     $SZ*5($ctx),$F
873         add     $SZ*6($ctx),$G
874         add     $SZ*7($ctx),$H
875
876         cmp     $_end,$inp
877
878         mov     $A,$SZ*0($ctx)
879         mov     $B,$SZ*1($ctx)
880         mov     $C,$SZ*2($ctx)
881         mov     $D,$SZ*3($ctx)
882         mov     $E,$SZ*4($ctx)
883         mov     $F,$SZ*5($ctx)
884         mov     $G,$SZ*6($ctx)
885         mov     $H,$SZ*7($ctx)
886         jb      .Lloop_ssse3
887
888         mov     $_rsp,%rsi
889 ___
890 $code.=<<___ if ($win64);
891         movaps  16*$SZ+32(%rsp),%xmm6
892         movaps  16*$SZ+48(%rsp),%xmm7
893         movaps  16*$SZ+64(%rsp),%xmm8
894         movaps  16*$SZ+80(%rsp),%xmm9
895 ___
896 $code.=<<___;
897         mov     (%rsi),%r15
898         mov     8(%rsi),%r14
899         mov     16(%rsi),%r13
900         mov     24(%rsi),%r12
901         mov     32(%rsi),%rbp
902         mov     40(%rsi),%rbx
903         lea     48(%rsi),%rsp
904 .Lepilogue_ssse3:
905         ret
906 .size   ${func}_ssse3,.-${func}_ssse3
907 ___
908 }
909
910 if ($avx) {{
911 ######################################################################
912 # XOP code path
913 #
914 if ($SZ==8) {   # SHA512 only
915 $code.=<<___;
916 .type   ${func}_xop,\@function,3
917 .align  64
918 ${func}_xop:
919 .Lxop_shortcut:
920         push    %rbx
921         push    %rbp
922         push    %r12
923         push    %r13
924         push    %r14
925         push    %r15
926         mov     %rsp,%r11               # copy %rsp
927         shl     \$4,%rdx                # num*16
928         sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
929         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
930         and     \$-64,%rsp              # align stack frame
931         mov     $ctx,$_ctx              # save ctx, 1st arg
932         mov     $inp,$_inp              # save inp, 2nd arh
933         mov     %rdx,$_end              # save end pointer, "3rd" arg
934         mov     %r11,$_rsp              # save copy of %rsp
935 ___
936 $code.=<<___ if ($win64);
937         movaps  %xmm6,16*$SZ+32(%rsp)
938         movaps  %xmm7,16*$SZ+48(%rsp)
939         movaps  %xmm8,16*$SZ+64(%rsp)
940         movaps  %xmm9,16*$SZ+80(%rsp)
941 ___
942 $code.=<<___ if ($win64 && $SZ>4);
943         movaps  %xmm10,16*$SZ+96(%rsp)
944         movaps  %xmm11,16*$SZ+112(%rsp)
945 ___
946 $code.=<<___;
947 .Lprologue_xop:
948
949         vzeroall
950         mov     $SZ*0($ctx),$A
951         mov     $SZ*1($ctx),$B
952         mov     $SZ*2($ctx),$C
953         mov     $SZ*3($ctx),$D
954         mov     $SZ*4($ctx),$E
955         mov     $SZ*5($ctx),$F
956         mov     $SZ*6($ctx),$G
957         mov     $SZ*7($ctx),$H
958         jmp     .Lloop_xop
959 ___
960                                         if ($SZ==4) {   # SHA256
961     my @X = map("%xmm$_",(0..3));
962     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
963
964 $code.=<<___;
965 .align  16
966 .Lloop_xop:
967         vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
968         vmovdqu 0x00($inp),@X[0]
969         vmovdqu 0x10($inp),@X[1]
970         vmovdqu 0x20($inp),@X[2]
971         vmovdqu 0x30($inp),@X[3]
972         vpshufb $t3,@X[0],@X[0]
973         lea     $TABLE(%rip),$Tbl
974         vpshufb $t3,@X[1],@X[1]
975         vpshufb $t3,@X[2],@X[2]
976         vpaddd  0x00($Tbl),@X[0],$t0
977         vpshufb $t3,@X[3],@X[3]
978         vpaddd  0x20($Tbl),@X[1],$t1
979         vpaddd  0x40($Tbl),@X[2],$t2
980         vpaddd  0x60($Tbl),@X[3],$t3
981         vmovdqa $t0,0x00(%rsp)
982         mov     $A,$a1
983         vmovdqa $t1,0x10(%rsp)
984         mov     $B,$a3
985         vmovdqa $t2,0x20(%rsp)
986         xor     $C,$a3                  # magic
987         vmovdqa $t3,0x30(%rsp)
988         mov     $E,$a0
989         jmp     .Lxop_00_47
990
991 .align  16
992 .Lxop_00_47:
993         sub     \$-16*2*$SZ,$Tbl        # size optimization
994 ___
995 sub XOP_256_00_47 () {
996 my $j = shift;
997 my $body = shift;
998 my @X = @_;
999 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
1000
1001         &vpalignr       ($t0,@X[1],@X[0],$SZ);  # X[1..4]
1002           eval(shift(@insns));
1003           eval(shift(@insns));
1004          &vpalignr      ($t3,@X[3],@X[2],$SZ);  # X[9..12]
1005           eval(shift(@insns));
1006           eval(shift(@insns));
1007         &vprotd         ($t1,$t0,8*$SZ-$sigma0[1]);
1008           eval(shift(@insns));
1009           eval(shift(@insns));
1010         &vpsrld         ($t0,$t0,$sigma0[2]);
1011           eval(shift(@insns));
1012           eval(shift(@insns));
1013          &vpaddd        (@X[0],@X[0],$t3);      # X[0..3] += X[9..12]
1014           eval(shift(@insns));
1015           eval(shift(@insns));
1016           eval(shift(@insns));
1017           eval(shift(@insns));
1018         &vprotd         ($t2,$t1,$sigma0[1]-$sigma0[0]);
1019           eval(shift(@insns));
1020           eval(shift(@insns));
1021         &vpxor          ($t0,$t0,$t1);
1022           eval(shift(@insns));
1023           eval(shift(@insns));
1024           eval(shift(@insns));
1025           eval(shift(@insns));
1026          &vprotd        ($t3,@X[3],8*$SZ-$sigma1[1]);
1027           eval(shift(@insns));
1028           eval(shift(@insns));
1029         &vpxor          ($t0,$t0,$t2);          # sigma0(X[1..4])
1030           eval(shift(@insns));
1031           eval(shift(@insns));
1032          &vpsrld        ($t2,@X[3],$sigma1[2]);
1033           eval(shift(@insns));
1034           eval(shift(@insns));
1035         &vpaddd         (@X[0],@X[0],$t0);      # X[0..3] += sigma0(X[1..4])
1036           eval(shift(@insns));
1037           eval(shift(@insns));
1038          &vprotd        ($t1,$t3,$sigma1[1]-$sigma1[0]);
1039           eval(shift(@insns));
1040           eval(shift(@insns));
1041          &vpxor         ($t3,$t3,$t2);
1042           eval(shift(@insns));
1043           eval(shift(@insns));
1044           eval(shift(@insns));
1045           eval(shift(@insns));
1046          &vpxor         ($t3,$t3,$t1);          # sigma1(X[14..15])
1047           eval(shift(@insns));
1048           eval(shift(@insns));
1049           eval(shift(@insns));
1050           eval(shift(@insns));
1051         &vpsrldq        ($t3,$t3,8);
1052           eval(shift(@insns));
1053           eval(shift(@insns));
1054           eval(shift(@insns));
1055           eval(shift(@insns));
1056         &vpaddd         (@X[0],@X[0],$t3);      # X[0..1] += sigma1(X[14..15])
1057           eval(shift(@insns));
1058           eval(shift(@insns));
1059           eval(shift(@insns));
1060           eval(shift(@insns));
1061          &vprotd        ($t3,@X[0],8*$SZ-$sigma1[1]);
1062           eval(shift(@insns));
1063           eval(shift(@insns));
1064          &vpsrld        ($t2,@X[0],$sigma1[2]);
1065           eval(shift(@insns));
1066           eval(shift(@insns));
1067          &vprotd        ($t1,$t3,$sigma1[1]-$sigma1[0]);
1068           eval(shift(@insns));
1069           eval(shift(@insns));
1070          &vpxor         ($t3,$t3,$t2);
1071           eval(shift(@insns));
1072           eval(shift(@insns));
1073           eval(shift(@insns));
1074           eval(shift(@insns));
1075          &vpxor         ($t3,$t3,$t1);          # sigma1(X[16..17])
1076           eval(shift(@insns));
1077           eval(shift(@insns));
1078           eval(shift(@insns));
1079           eval(shift(@insns));
1080         &vpslldq        ($t3,$t3,8);            # 22 instructions
1081           eval(shift(@insns));
1082           eval(shift(@insns));
1083           eval(shift(@insns));
1084           eval(shift(@insns));
1085         &vpaddd         (@X[0],@X[0],$t3);      # X[2..3] += sigma1(X[16..17])
1086           eval(shift(@insns));
1087           eval(shift(@insns));
1088           eval(shift(@insns));
1089           eval(shift(@insns));
1090         &vpaddd         ($t2,@X[0],16*2*$j."($Tbl)");
1091           foreach (@insns) { eval; }            # remaining instructions
1092         &vmovdqa        (16*$j."(%rsp)",$t2);
1093 }
1094
1095     for ($i=0,$j=0; $j<4; $j++) {
1096         &XOP_256_00_47($j,\&body_00_15,@X);
1097         push(@X,shift(@X));                     # rotate(@X)
1098     }
1099         &cmpb   ($SZ-1+16*2*$SZ."($Tbl)",0);
1100         &jne    (".Lxop_00_47");
1101
1102     for ($i=0; $i<16; ) {
1103         foreach(body_00_15()) { eval; }
1104     }
1105
1106                                         } else {        # SHA512
1107     my @X = map("%xmm$_",(0..7));
1108     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
1109
1110 $code.=<<___;
1111 .align  16
1112 .Lloop_xop:
1113         vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
1114         vmovdqu 0x00($inp),@X[0]
1115         lea     $TABLE+0x80(%rip),$Tbl  # size optimization
1116         vmovdqu 0x10($inp),@X[1]
1117         vmovdqu 0x20($inp),@X[2]
1118         vpshufb $t3,@X[0],@X[0]
1119         vmovdqu 0x30($inp),@X[3]
1120         vpshufb $t3,@X[1],@X[1]
1121         vmovdqu 0x40($inp),@X[4]
1122         vpshufb $t3,@X[2],@X[2]
1123         vmovdqu 0x50($inp),@X[5]
1124         vpshufb $t3,@X[3],@X[3]
1125         vmovdqu 0x60($inp),@X[6]
1126         vpshufb $t3,@X[4],@X[4]
1127         vmovdqu 0x70($inp),@X[7]
1128         vpshufb $t3,@X[5],@X[5]
1129         vpaddq  -0x80($Tbl),@X[0],$t0
1130         vpshufb $t3,@X[6],@X[6]
1131         vpaddq  -0x60($Tbl),@X[1],$t1
1132         vpshufb $t3,@X[7],@X[7]
1133         vpaddq  -0x40($Tbl),@X[2],$t2
1134         vpaddq  -0x20($Tbl),@X[3],$t3
1135         vmovdqa $t0,0x00(%rsp)
1136         vpaddq  0x00($Tbl),@X[4],$t0
1137         vmovdqa $t1,0x10(%rsp)
1138         vpaddq  0x20($Tbl),@X[5],$t1
1139         vmovdqa $t2,0x20(%rsp)
1140         vpaddq  0x40($Tbl),@X[6],$t2
1141         vmovdqa $t3,0x30(%rsp)
1142         vpaddq  0x60($Tbl),@X[7],$t3
1143         vmovdqa $t0,0x40(%rsp)
1144         mov     $A,$a1
1145         vmovdqa $t1,0x50(%rsp)
1146         mov     $B,$a3
1147         vmovdqa $t2,0x60(%rsp)
1148         xor     $C,$a3                  # magic
1149         vmovdqa $t3,0x70(%rsp)
1150         mov     $E,$a0
1151         jmp     .Lxop_00_47
1152
1153 .align  16
1154 .Lxop_00_47:
1155         add     \$16*2*$SZ,$Tbl
1156 ___
1157 sub XOP_512_00_47 () {
1158 my $j = shift;
1159 my $body = shift;
1160 my @X = @_;
1161 my @insns = (&$body,&$body);                    # 52 instructions
1162
1163         &vpalignr       ($t0,@X[1],@X[0],$SZ);  # X[1..2]
1164           eval(shift(@insns));
1165           eval(shift(@insns));
1166          &vpalignr      ($t3,@X[5],@X[4],$SZ);  # X[9..10]
1167           eval(shift(@insns));
1168           eval(shift(@insns));
1169         &vprotq         ($t1,$t0,8*$SZ-$sigma0[1]);
1170           eval(shift(@insns));
1171           eval(shift(@insns));
1172         &vpsrlq         ($t0,$t0,$sigma0[2]);
1173           eval(shift(@insns));
1174           eval(shift(@insns));
1175          &vpaddq        (@X[0],@X[0],$t3);      # X[0..1] += X[9..10]
1176           eval(shift(@insns));
1177           eval(shift(@insns));
1178           eval(shift(@insns));
1179           eval(shift(@insns));
1180         &vprotq         ($t2,$t1,$sigma0[1]-$sigma0[0]);
1181           eval(shift(@insns));
1182           eval(shift(@insns));
1183         &vpxor          ($t0,$t0,$t1);
1184           eval(shift(@insns));
1185           eval(shift(@insns));
1186           eval(shift(@insns));
1187           eval(shift(@insns));
1188          &vprotq        ($t3,@X[7],8*$SZ-$sigma1[1]);
1189           eval(shift(@insns));
1190           eval(shift(@insns));
1191         &vpxor          ($t0,$t0,$t2);          # sigma0(X[1..2])
1192           eval(shift(@insns));
1193           eval(shift(@insns));
1194          &vpsrlq        ($t2,@X[7],$sigma1[2]);
1195           eval(shift(@insns));
1196           eval(shift(@insns));
1197         &vpaddq         (@X[0],@X[0],$t0);      # X[0..1] += sigma0(X[1..2])
1198           eval(shift(@insns));
1199           eval(shift(@insns));
1200          &vprotq        ($t1,$t3,$sigma1[1]-$sigma1[0]);
1201           eval(shift(@insns));
1202           eval(shift(@insns));
1203          &vpxor         ($t3,$t3,$t2);
1204           eval(shift(@insns));
1205           eval(shift(@insns));
1206           eval(shift(@insns));
1207           eval(shift(@insns));
1208          &vpxor         ($t3,$t3,$t1);          # sigma1(X[14..15])
1209           eval(shift(@insns));
1210           eval(shift(@insns));
1211           eval(shift(@insns));
1212           eval(shift(@insns));
1213         &vpaddq         (@X[0],@X[0],$t3);      # X[0..1] += sigma1(X[14..15])
1214           eval(shift(@insns));
1215           eval(shift(@insns));
1216           eval(shift(@insns));
1217           eval(shift(@insns));
1218         &vpaddq         ($t2,@X[0],16*2*$j-0x80."($Tbl)");
1219           foreach (@insns) { eval; }            # remaining instructions
1220         &vmovdqa        (16*$j."(%rsp)",$t2);
1221 }
1222
1223     for ($i=0,$j=0; $j<8; $j++) {
1224         &XOP_512_00_47($j,\&body_00_15,@X);
1225         push(@X,shift(@X));                     # rotate(@X)
1226     }
1227         &cmpb   ($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
1228         &jne    (".Lxop_00_47");
1229
1230     for ($i=0; $i<16; ) {
1231         foreach(body_00_15()) { eval; }
1232     }
1233 }
1234 $code.=<<___;
1235         mov     $_ctx,$ctx
1236         mov     $a1,$A
1237
1238         add     $SZ*0($ctx),$A
1239         lea     16*$SZ($inp),$inp
1240         add     $SZ*1($ctx),$B
1241         add     $SZ*2($ctx),$C
1242         add     $SZ*3($ctx),$D
1243         add     $SZ*4($ctx),$E
1244         add     $SZ*5($ctx),$F
1245         add     $SZ*6($ctx),$G
1246         add     $SZ*7($ctx),$H
1247
1248         cmp     $_end,$inp
1249
1250         mov     $A,$SZ*0($ctx)
1251         mov     $B,$SZ*1($ctx)
1252         mov     $C,$SZ*2($ctx)
1253         mov     $D,$SZ*3($ctx)
1254         mov     $E,$SZ*4($ctx)
1255         mov     $F,$SZ*5($ctx)
1256         mov     $G,$SZ*6($ctx)
1257         mov     $H,$SZ*7($ctx)
1258         jb      .Lloop_xop
1259
1260         mov     $_rsp,%rsi
1261         vzeroall
1262 ___
1263 $code.=<<___ if ($win64);
1264         movaps  16*$SZ+32(%rsp),%xmm6
1265         movaps  16*$SZ+48(%rsp),%xmm7
1266         movaps  16*$SZ+64(%rsp),%xmm8
1267         movaps  16*$SZ+80(%rsp),%xmm9
1268 ___
1269 $code.=<<___ if ($win64 && $SZ>4);
1270         movaps  16*$SZ+96(%rsp),%xmm10
1271         movaps  16*$SZ+112(%rsp),%xmm11
1272 ___
1273 $code.=<<___;
1274         mov     (%rsi),%r15
1275         mov     8(%rsi),%r14
1276         mov     16(%rsi),%r13
1277         mov     24(%rsi),%r12
1278         mov     32(%rsi),%rbp
1279         mov     40(%rsi),%rbx
1280         lea     48(%rsi),%rsp
1281 .Lepilogue_xop:
1282         ret
1283 .size   ${func}_xop,.-${func}_xop
1284 ___
1285 }
1286 ######################################################################
1287 # AVX+shrd code path
1288 #
1289 local *ror = sub { &shrd(@_[0],@_) };
1290
1291 $code.=<<___;
1292 .type   ${func}_avx,\@function,3
1293 .align  64
1294 ${func}_avx:
1295 .Lavx_shortcut:
1296         push    %rbx
1297         push    %rbp
1298         push    %r12
1299         push    %r13
1300         push    %r14
1301         push    %r15
1302         mov     %rsp,%r11               # copy %rsp
1303         shl     \$4,%rdx                # num*16
1304         sub     \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
1305         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
1306         and     \$-64,%rsp              # align stack frame
1307         mov     $ctx,$_ctx              # save ctx, 1st arg
1308         mov     $inp,$_inp              # save inp, 2nd arh
1309         mov     %rdx,$_end              # save end pointer, "3rd" arg
1310         mov     %r11,$_rsp              # save copy of %rsp
1311 ___
1312 $code.=<<___ if ($win64);
1313         movaps  %xmm6,16*$SZ+32(%rsp)
1314         movaps  %xmm7,16*$SZ+48(%rsp)
1315         movaps  %xmm8,16*$SZ+64(%rsp)
1316         movaps  %xmm9,16*$SZ+80(%rsp)
1317 ___
1318 $code.=<<___ if ($win64 && $SZ>4);
1319         movaps  %xmm10,16*$SZ+96(%rsp)
1320         movaps  %xmm11,16*$SZ+112(%rsp)
1321 ___
1322 $code.=<<___;
1323 .Lprologue_avx:
1324
1325         vzeroall
1326         mov     $SZ*0($ctx),$A
1327         mov     $SZ*1($ctx),$B
1328         mov     $SZ*2($ctx),$C
1329         mov     $SZ*3($ctx),$D
1330         mov     $SZ*4($ctx),$E
1331         mov     $SZ*5($ctx),$F
1332         mov     $SZ*6($ctx),$G
1333         mov     $SZ*7($ctx),$H
1334 ___
1335                                         if ($SZ==4) {   # SHA256
1336     my @X = map("%xmm$_",(0..3));
1337     my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
1338
1339 $code.=<<___;
1340         vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
1341         vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
1342         jmp     .Lloop_avx
1343 .align  16
1344 .Lloop_avx:
1345         vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
1346         vmovdqu 0x00($inp),@X[0]
1347         vmovdqu 0x10($inp),@X[1]
1348         vmovdqu 0x20($inp),@X[2]
1349         vmovdqu 0x30($inp),@X[3]
1350         vpshufb $t3,@X[0],@X[0]
1351         lea     $TABLE(%rip),$Tbl
1352         vpshufb $t3,@X[1],@X[1]
1353         vpshufb $t3,@X[2],@X[2]
1354         vpaddd  0x00($Tbl),@X[0],$t0
1355         vpshufb $t3,@X[3],@X[3]
1356         vpaddd  0x20($Tbl),@X[1],$t1
1357         vpaddd  0x40($Tbl),@X[2],$t2
1358         vpaddd  0x60($Tbl),@X[3],$t3
1359         vmovdqa $t0,0x00(%rsp)
1360         mov     $A,$a1
1361         vmovdqa $t1,0x10(%rsp)
1362         mov     $B,$a3
1363         vmovdqa $t2,0x20(%rsp)
1364         xor     $C,$a3                  # magic
1365         vmovdqa $t3,0x30(%rsp)
1366         mov     $E,$a0
1367         jmp     .Lavx_00_47
1368
1369 .align  16
1370 .Lavx_00_47:
1371         sub     \$-16*2*$SZ,$Tbl        # size optimization
1372 ___
1373 sub Xupdate_256_AVX () {
1374         (
1375         '&vpalignr      ($t0,@X[1],@X[0],$SZ)', # X[1..4]
1376          '&vpalignr     ($t3,@X[3],@X[2],$SZ)', # X[9..12]
1377         '&vpsrld        ($t2,$t0,$sigma0[0]);',
1378          '&vpaddd       (@X[0],@X[0],$t3)',     # X[0..3] += X[9..12]
1379         '&vpsrld        ($t3,$t0,$sigma0[2])',
1380         '&vpslld        ($t1,$t0,8*$SZ-$sigma0[1]);',
1381         '&vpxor         ($t0,$t3,$t2)',
1382          '&vpshufd      ($t3,@X[3],0b11111010)',# X[14..15]
1383         '&vpsrld        ($t2,$t2,$sigma0[1]-$sigma0[0]);',
1384         '&vpxor         ($t0,$t0,$t1)',
1385         '&vpslld        ($t1,$t1,$sigma0[1]-$sigma0[0]);',
1386         '&vpxor         ($t0,$t0,$t2)',
1387          '&vpsrld       ($t2,$t3,$sigma1[2]);',
1388         '&vpxor         ($t0,$t0,$t1)',         # sigma0(X[1..4])
1389          '&vpsrlq       ($t3,$t3,$sigma1[0]);',
1390         '&vpaddd        (@X[0],@X[0],$t0)',     # X[0..3] += sigma0(X[1..4])
1391          '&vpxor        ($t2,$t2,$t3);',
1392          '&vpsrlq       ($t3,$t3,$sigma1[1]-$sigma1[0])',
1393          '&vpxor        ($t2,$t2,$t3)',
1394          '&vpshufb      ($t2,$t2,$t4)',         # sigma1(X[14..15])
1395         '&vpaddd        (@X[0],@X[0],$t2)',     # X[0..1] += sigma1(X[14..15])
1396          '&vpshufd      ($t3,@X[0],0b01010000)',# X[16..17]
1397          '&vpsrld       ($t2,$t3,$sigma1[2])',
1398          '&vpsrlq       ($t3,$t3,$sigma1[0])',
1399          '&vpxor        ($t2,$t2,$t3);',
1400          '&vpsrlq       ($t3,$t3,$sigma1[1]-$sigma1[0])',
1401          '&vpxor        ($t2,$t2,$t3)',
1402          '&vpshufb      ($t2,$t2,$t5)',
1403         '&vpaddd        (@X[0],@X[0],$t2)'      # X[2..3] += sigma1(X[16..17])
1404         );
1405 }
1406
1407 sub AVX_256_00_47 () {
1408 my $j = shift;
1409 my $body = shift;
1410 my @X = @_;
1411 my @insns = (&$body,&$body,&$body,&$body);      # 104 instructions
1412
1413         foreach (Xupdate_256_AVX()) {           # 29 instructions
1414             eval;
1415             eval(shift(@insns));
1416             eval(shift(@insns));
1417             eval(shift(@insns));
1418         }
1419         &vpaddd         ($t2,@X[0],16*2*$j."($Tbl)");
1420           foreach (@insns) { eval; }            # remaining instructions
1421         &vmovdqa        (16*$j."(%rsp)",$t2);
1422 }
1423
1424     for ($i=0,$j=0; $j<4; $j++) {
1425         &AVX_256_00_47($j,\&body_00_15,@X);
1426         push(@X,shift(@X));                     # rotate(@X)
1427     }
1428         &cmpb   ($SZ-1+16*2*$SZ."($Tbl)",0);
1429         &jne    (".Lavx_00_47");
1430
1431     for ($i=0; $i<16; ) {
1432         foreach(body_00_15()) { eval; }
1433     }
1434
1435                                         } else {        # SHA512
1436     my @X = map("%xmm$_",(0..7));
1437     my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
1438
1439 $code.=<<___;
1440         jmp     .Lloop_avx
1441 .align  16
1442 .Lloop_avx:
1443         vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
1444         vmovdqu 0x00($inp),@X[0]
1445         lea     $TABLE+0x80(%rip),$Tbl  # size optimization
1446         vmovdqu 0x10($inp),@X[1]
1447         vmovdqu 0x20($inp),@X[2]
1448         vpshufb $t3,@X[0],@X[0]
1449         vmovdqu 0x30($inp),@X[3]
1450         vpshufb $t3,@X[1],@X[1]
1451         vmovdqu 0x40($inp),@X[4]
1452         vpshufb $t3,@X[2],@X[2]
1453         vmovdqu 0x50($inp),@X[5]
1454         vpshufb $t3,@X[3],@X[3]
1455         vmovdqu 0x60($inp),@X[6]
1456         vpshufb $t3,@X[4],@X[4]
1457         vmovdqu 0x70($inp),@X[7]
1458         vpshufb $t3,@X[5],@X[5]
1459         vpaddq  -0x80($Tbl),@X[0],$t0
1460         vpshufb $t3,@X[6],@X[6]
1461         vpaddq  -0x60($Tbl),@X[1],$t1
1462         vpshufb $t3,@X[7],@X[7]
1463         vpaddq  -0x40($Tbl),@X[2],$t2
1464         vpaddq  -0x20($Tbl),@X[3],$t3
1465         vmovdqa $t0,0x00(%rsp)
1466         vpaddq  0x00($Tbl),@X[4],$t0
1467         vmovdqa $t1,0x10(%rsp)
1468         vpaddq  0x20($Tbl),@X[5],$t1
1469         vmovdqa $t2,0x20(%rsp)
1470         vpaddq  0x40($Tbl),@X[6],$t2
1471         vmovdqa $t3,0x30(%rsp)
1472         vpaddq  0x60($Tbl),@X[7],$t3
1473         vmovdqa $t0,0x40(%rsp)
1474         mov     $A,$a1
1475         vmovdqa $t1,0x50(%rsp)
1476         mov     $B,$a3
1477         vmovdqa $t2,0x60(%rsp)
1478         xor     $C,$a3                  # magic
1479         vmovdqa $t3,0x70(%rsp)
1480         mov     $E,$a0
1481         jmp     .Lavx_00_47
1482
1483 .align  16
1484 .Lavx_00_47:
1485         add     \$16*2*$SZ,$Tbl
1486 ___
1487 sub Xupdate_512_AVX () {
1488         (
1489         '&vpalignr      ($t0,@X[1],@X[0],$SZ)', # X[1..2]
1490          '&vpalignr     ($t3,@X[5],@X[4],$SZ)', # X[9..10]
1491         '&vpsrlq        ($t2,$t0,$sigma0[0])',
1492          '&vpaddq       (@X[0],@X[0],$t3);',    # X[0..1] += X[9..10]
1493         '&vpsrlq        ($t3,$t0,$sigma0[2])',
1494         '&vpsllq        ($t1,$t0,8*$SZ-$sigma0[1]);',
1495          '&vpxor        ($t0,$t3,$t2)',
1496         '&vpsrlq        ($t2,$t2,$sigma0[1]-$sigma0[0]);',
1497          '&vpxor        ($t0,$t0,$t1)',
1498         '&vpsllq        ($t1,$t1,$sigma0[1]-$sigma0[0]);',
1499          '&vpxor        ($t0,$t0,$t2)',
1500          '&vpsrlq       ($t3,@X[7],$sigma1[2]);',
1501         '&vpxor         ($t0,$t0,$t1)',         # sigma0(X[1..2])
1502          '&vpsllq       ($t2,@X[7],8*$SZ-$sigma1[1]);',
1503         '&vpaddq        (@X[0],@X[0],$t0)',     # X[0..1] += sigma0(X[1..2])
1504          '&vpsrlq       ($t1,@X[7],$sigma1[0]);',
1505          '&vpxor        ($t3,$t3,$t2)',
1506          '&vpsllq       ($t2,$t2,$sigma1[1]-$sigma1[0]);',
1507          '&vpxor        ($t3,$t3,$t1)',
1508          '&vpsrlq       ($t1,$t1,$sigma1[1]-$sigma1[0]);',
1509          '&vpxor        ($t3,$t3,$t2)',
1510          '&vpxor        ($t3,$t3,$t1)',         # sigma1(X[14..15])
1511         '&vpaddq        (@X[0],@X[0],$t3)',     # X[0..1] += sigma1(X[14..15])
1512         );
1513 }
1514
1515 sub AVX_512_00_47 () {
1516 my $j = shift;
1517 my $body = shift;
1518 my @X = @_;
1519 my @insns = (&$body,&$body);                    # 52 instructions
1520
1521         foreach (Xupdate_512_AVX()) {           # 23 instructions
1522             eval;
1523             eval(shift(@insns));
1524             eval(shift(@insns));
1525         }
1526         &vpaddq         ($t2,@X[0],16*2*$j-0x80."($Tbl)");
1527           foreach (@insns) { eval; }            # remaining instructions
1528         &vmovdqa        (16*$j."(%rsp)",$t2);
1529 }
1530
1531     for ($i=0,$j=0; $j<8; $j++) {
1532         &AVX_512_00_47($j,\&body_00_15,@X);
1533         push(@X,shift(@X));                     # rotate(@X)
1534     }
1535         &cmpb   ($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
1536         &jne    (".Lavx_00_47");
1537
1538     for ($i=0; $i<16; ) {
1539         foreach(body_00_15()) { eval; }
1540     }
1541 }
1542 $code.=<<___;
1543         mov     $_ctx,$ctx
1544         mov     $a1,$A
1545
1546         add     $SZ*0($ctx),$A
1547         lea     16*$SZ($inp),$inp
1548         add     $SZ*1($ctx),$B
1549         add     $SZ*2($ctx),$C
1550         add     $SZ*3($ctx),$D
1551         add     $SZ*4($ctx),$E
1552         add     $SZ*5($ctx),$F
1553         add     $SZ*6($ctx),$G
1554         add     $SZ*7($ctx),$H
1555
1556         cmp     $_end,$inp
1557
1558         mov     $A,$SZ*0($ctx)
1559         mov     $B,$SZ*1($ctx)
1560         mov     $C,$SZ*2($ctx)
1561         mov     $D,$SZ*3($ctx)
1562         mov     $E,$SZ*4($ctx)
1563         mov     $F,$SZ*5($ctx)
1564         mov     $G,$SZ*6($ctx)
1565         mov     $H,$SZ*7($ctx)
1566         jb      .Lloop_avx
1567
1568         mov     $_rsp,%rsi
1569         vzeroall
1570 ___
1571 $code.=<<___ if ($win64);
1572         movaps  16*$SZ+32(%rsp),%xmm6
1573         movaps  16*$SZ+48(%rsp),%xmm7
1574         movaps  16*$SZ+64(%rsp),%xmm8
1575         movaps  16*$SZ+80(%rsp),%xmm9
1576 ___
1577 $code.=<<___ if ($win64 && $SZ>4);
1578         movaps  16*$SZ+96(%rsp),%xmm10
1579         movaps  16*$SZ+112(%rsp),%xmm11
1580 ___
1581 $code.=<<___;
1582         mov     (%rsi),%r15
1583         mov     8(%rsi),%r14
1584         mov     16(%rsi),%r13
1585         mov     24(%rsi),%r12
1586         mov     32(%rsi),%rbp
1587         mov     40(%rsi),%rbx
1588         lea     48(%rsi),%rsp
1589 .Lepilogue_avx:
1590         ret
1591 .size   ${func}_avx,.-${func}_avx
1592 ___
1593
1594 if ($avx>1) {{
1595 ######################################################################
1596 # AVX2+BMI code path
1597 #
1598 my $a5=$SZ==4?"%esi":"%rsi";    # zap $inp 
1599 my $PUSH8=8*2*$SZ;
1600 use integer;
1601
1602 sub bodyx_00_15 () {
1603         # at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f
1604         (
1605         '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
1606
1607         '&add   ($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)',    # h+=X[i]+K[i]
1608         '&and   ($a4,$e)',              # f&e
1609         '&rorx  ($a0,$e,$Sigma1[2])',
1610         '&rorx  ($a2,$e,$Sigma1[1])',
1611
1612         '&lea   ($a,"($a,$a1)")',       # h+=Sigma0(a) from the past
1613         '&lea   ($h,"($h,$a4)")',
1614         '&andn  ($a4,$e,$g)',           # ~e&g
1615         '&xor   ($a0,$a2)',
1616
1617         '&rorx  ($a1,$e,$Sigma1[0])',
1618         '&lea   ($h,"($h,$a4)")',       # h+=Ch(e,f,g)=(e&f)+(~e&g)
1619         '&xor   ($a0,$a1)',             # Sigma1(e)
1620         '&mov   ($a2,$a)',
1621
1622         '&rorx  ($a4,$a,$Sigma0[2])',
1623         '&lea   ($h,"($h,$a0)")',       # h+=Sigma1(e)
1624         '&xor   ($a2,$b)',              # a^b, b^c in next round
1625         '&rorx  ($a1,$a,$Sigma0[1])',
1626
1627         '&rorx  ($a0,$a,$Sigma0[0])',
1628         '&lea   ($d,"($d,$h)")',        # d+=h
1629         '&and   ($a3,$a2)',             # (b^c)&(a^b)
1630         '&xor   ($a1,$a4)',
1631
1632         '&xor   ($a3,$b)',              # Maj(a,b,c)=Ch(a^b,c,b)
1633         '&xor   ($a1,$a0)',             # Sigma0(a)
1634         '&lea   ($h,"($h,$a3)");'.      # h+=Maj(a,b,c)
1635         '&mov   ($a4,$e)',              # copy of f in future
1636
1637         '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
1638         );
1639         # and at the finish one has to $a+=$a1
1640 }
1641
1642 $code.=<<___;
1643 .type   ${func}_avx2,\@function,3
1644 .align  64
1645 ${func}_avx2:
1646 .Lavx2_shortcut:
1647         push    %rbx
1648         push    %rbp
1649         push    %r12
1650         push    %r13
1651         push    %r14
1652         push    %r15
1653         mov     %rsp,%r11               # copy %rsp
1654         sub     \$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp
1655         shl     \$4,%rdx                # num*16
1656         and     \$-256*$SZ,%rsp         # align stack frame
1657         lea     ($inp,%rdx,$SZ),%rdx    # inp+num*16*$SZ
1658         add     \$`2*$SZ*($rounds-8)`,%rsp
1659         mov     $ctx,$_ctx              # save ctx, 1st arg
1660         mov     $inp,$_inp              # save inp, 2nd arh
1661         mov     %rdx,$_end              # save end pointer, "3rd" arg
1662         mov     %r11,$_rsp              # save copy of %rsp
1663 ___
1664 $code.=<<___ if ($win64);
1665         movaps  %xmm6,16*$SZ+32(%rsp)
1666         movaps  %xmm7,16*$SZ+48(%rsp)
1667         movaps  %xmm8,16*$SZ+64(%rsp)
1668         movaps  %xmm9,16*$SZ+80(%rsp)
1669 ___
1670 $code.=<<___ if ($win64 && $SZ>4);
1671         movaps  %xmm10,16*$SZ+96(%rsp)
1672         movaps  %xmm11,16*$SZ+112(%rsp)
1673 ___
1674 $code.=<<___;
1675 .Lprologue_avx2:
1676
1677         vzeroall
1678         sub     \$-16*$SZ,$inp          # inp++, size optimization
1679         mov     $SZ*0($ctx),$A
1680         mov     $inp,%r12               # borrow $T1
1681         mov     $SZ*1($ctx),$B
1682         cmp     %rdx,$inp               # $_end
1683         mov     $SZ*2($ctx),$C
1684         cmove   %rsp,%r12               # next block or random data
1685         mov     $SZ*3($ctx),$D
1686         mov     $SZ*4($ctx),$E
1687         mov     $SZ*5($ctx),$F
1688         mov     $SZ*6($ctx),$G
1689         mov     $SZ*7($ctx),$H
1690 ___
1691                                         if ($SZ==4) {   # SHA256
1692     my @X = map("%ymm$_",(0..3));
1693     my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%ymm$_",(4..9));
1694
1695 $code.=<<___;
1696         vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
1697         vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
1698         jmp     .Loop_avx2
1699 .align  16
1700 .Loop_avx2:
1701         vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
1702         vmovdqu -16*$SZ+0($inp),%xmm0
1703         vmovdqu -16*$SZ+16($inp),%xmm1
1704         vmovdqu -16*$SZ+32($inp),%xmm2
1705         vmovdqu -16*$SZ+48($inp),%xmm3
1706         #mov            $inp,$_inp      # offload $inp
1707         vinserti128     \$1,(%r12),@X[0],@X[0]
1708         vinserti128     \$1,16(%r12),@X[1],@X[1]
1709         vpshufb         $t3,@X[0],@X[0]
1710         vinserti128     \$1,32(%r12),@X[2],@X[2]
1711         vpshufb         $t3,@X[1],@X[1]
1712         vinserti128     \$1,48(%r12),@X[3],@X[3]
1713
1714         lea     $TABLE(%rip),$Tbl
1715         vpshufb $t3,@X[2],@X[2]
1716         vpaddd  0x00($Tbl),@X[0],$t0
1717         vpshufb $t3,@X[3],@X[3]
1718         vpaddd  0x20($Tbl),@X[1],$t1
1719         vpaddd  0x40($Tbl),@X[2],$t2
1720         vpaddd  0x60($Tbl),@X[3],$t3
1721         vmovdqa $t0,0x00(%rsp)
1722         xor     $a1,$a1
1723         vmovdqa $t1,0x20(%rsp)
1724         lea     -$PUSH8(%rsp),%rsp
1725         mov     $B,$a3
1726         vmovdqa $t2,0x00(%rsp)
1727         xor     $C,$a3                  # magic
1728         vmovdqa $t3,0x20(%rsp)
1729         mov     $F,$a4
1730         sub     \$-16*2*$SZ,$Tbl        # size optimization
1731         jmp     .Lavx2_00_47
1732
1733 .align  16
1734 .Lavx2_00_47:
1735 ___
1736
1737 sub AVX2_256_00_47 () {
1738 my $j = shift;
1739 my $body = shift;
1740 my @X = @_;
1741 my @insns = (&$body,&$body,&$body,&$body);      # 96 instructions
1742 my $base = "+2*$PUSH8(%rsp)";
1743
1744         &lea    ("%rsp","-$PUSH8(%rsp)")        if (($j%2)==0);
1745         foreach (Xupdate_256_AVX()) {           # 29 instructions
1746             eval;
1747             eval(shift(@insns));
1748             eval(shift(@insns));
1749             eval(shift(@insns));
1750         }
1751         &vpaddd         ($t2,@X[0],16*2*$j."($Tbl)");
1752           foreach (@insns) { eval; }            # remaining instructions
1753         &vmovdqa        ((32*$j)%$PUSH8."(%rsp)",$t2);
1754 }
1755
1756     for ($i=0,$j=0; $j<4; $j++) {
1757         &AVX2_256_00_47($j,\&bodyx_00_15,@X);
1758         push(@X,shift(@X));                     # rotate(@X)
1759     }
1760         &lea    ($Tbl,16*2*$SZ."($Tbl)");
1761         &cmpb   (($SZ-1)."($Tbl)",0);
1762         &jne    (".Lavx2_00_47");
1763
1764     for ($i=0; $i<16; ) {
1765         my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
1766         foreach(bodyx_00_15()) { eval; }
1767     }
1768                                         } else {        # SHA512
1769     my @X = map("%ymm$_",(0..7));
1770     my ($t0,$t1,$t2,$t3) = map("%ymm$_",(8..11));
1771
1772 $code.=<<___;
1773         jmp     .Loop_avx2
1774 .align  16
1775 .Loop_avx2:
1776         vmovdqu -16*$SZ($inp),%xmm0
1777         vmovdqu -16*$SZ+16($inp),%xmm1
1778         vmovdqu -16*$SZ+32($inp),%xmm2
1779         lea     $TABLE+0x80(%rip),$Tbl  # size optimization
1780         vmovdqu -16*$SZ+48($inp),%xmm3
1781         vmovdqu -16*$SZ+64($inp),%xmm4
1782         vmovdqu -16*$SZ+80($inp),%xmm5
1783         vmovdqu -16*$SZ+96($inp),%xmm6
1784         vmovdqu -16*$SZ+112($inp),%xmm7
1785         #mov    $inp,$_inp      # offload $inp
1786         vmovdqa `$SZ*2*$rounds-0x80`($Tbl),$t2
1787         vinserti128     \$1,(%r12),@X[0],@X[0]
1788         vinserti128     \$1,16(%r12),@X[1],@X[1]
1789          vpshufb        $t2,@X[0],@X[0]
1790         vinserti128     \$1,32(%r12),@X[2],@X[2]
1791          vpshufb        $t2,@X[1],@X[1]
1792         vinserti128     \$1,48(%r12),@X[3],@X[3]
1793          vpshufb        $t2,@X[2],@X[2]
1794         vinserti128     \$1,64(%r12),@X[4],@X[4]
1795          vpshufb        $t2,@X[3],@X[3]
1796         vinserti128     \$1,80(%r12),@X[5],@X[5]
1797          vpshufb        $t2,@X[4],@X[4]
1798         vinserti128     \$1,96(%r12),@X[6],@X[6]
1799          vpshufb        $t2,@X[5],@X[5]
1800         vinserti128     \$1,112(%r12),@X[7],@X[7]
1801
1802         vpaddq  -0x80($Tbl),@X[0],$t0
1803         vpshufb $t2,@X[6],@X[6]
1804         vpaddq  -0x60($Tbl),@X[1],$t1
1805         vpshufb $t2,@X[7],@X[7]
1806         vpaddq  -0x40($Tbl),@X[2],$t2
1807         vpaddq  -0x20($Tbl),@X[3],$t3
1808         vmovdqa $t0,0x00(%rsp)
1809         vpaddq  0x00($Tbl),@X[4],$t0
1810         vmovdqa $t1,0x20(%rsp)
1811         vpaddq  0x20($Tbl),@X[5],$t1
1812         vmovdqa $t2,0x40(%rsp)
1813         vpaddq  0x40($Tbl),@X[6],$t2
1814         vmovdqa $t3,0x60(%rsp)
1815         lea     -$PUSH8(%rsp),%rsp
1816         vpaddq  0x60($Tbl),@X[7],$t3
1817         vmovdqa $t0,0x00(%rsp)
1818         xor     $a1,$a1
1819         vmovdqa $t1,0x20(%rsp)
1820         mov     $B,$a3
1821         vmovdqa $t2,0x40(%rsp)
1822         xor     $C,$a3                  # magic
1823         vmovdqa $t3,0x60(%rsp)
1824         mov     $F,$a4
1825         add     \$16*2*$SZ,$Tbl
1826         jmp     .Lavx2_00_47
1827
1828 .align  16
1829 .Lavx2_00_47:
1830 ___
1831
1832 sub AVX2_512_00_47 () {
1833 my $j = shift;
1834 my $body = shift;
1835 my @X = @_;
1836 my @insns = (&$body,&$body);                    # 48 instructions
1837 my $base = "+2*$PUSH8(%rsp)";
1838
1839         &lea    ("%rsp","-$PUSH8(%rsp)")        if (($j%4)==0);
1840         foreach (Xupdate_512_AVX()) {           # 23 instructions
1841             eval;
1842             if ($_ !~ /\;$/) {
1843                 eval(shift(@insns));
1844                 eval(shift(@insns));
1845                 eval(shift(@insns));
1846             }
1847         }
1848         &vpaddq         ($t2,@X[0],16*2*$j-0x80."($Tbl)");
1849           foreach (@insns) { eval; }            # remaining instructions
1850         &vmovdqa        ((32*$j)%$PUSH8."(%rsp)",$t2);
1851 }
1852
1853     for ($i=0,$j=0; $j<8; $j++) {
1854         &AVX2_512_00_47($j,\&bodyx_00_15,@X);
1855         push(@X,shift(@X));                     # rotate(@X)
1856     }
1857         &lea    ($Tbl,16*2*$SZ."($Tbl)");
1858         &cmpb   (($SZ-1-0x80)."($Tbl)",0);
1859         &jne    (".Lavx2_00_47");
1860
1861     for ($i=0; $i<16; ) {
1862         my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
1863         foreach(bodyx_00_15()) { eval; }
1864     }
1865 }
1866 $code.=<<___;
1867         mov     `2*$SZ*$rounds`(%rsp),$ctx      # $_ctx
1868         add     $a1,$A
1869         #mov    `2*$SZ*$rounds+8`(%rsp),$inp    # $_inp
1870         lea     `2*$SZ*($rounds-8)`(%rsp),$Tbl
1871
1872         add     $SZ*0($ctx),$A
1873         add     $SZ*1($ctx),$B
1874         add     $SZ*2($ctx),$C
1875         add     $SZ*3($ctx),$D
1876         add     $SZ*4($ctx),$E
1877         add     $SZ*5($ctx),$F
1878         add     $SZ*6($ctx),$G
1879         add     $SZ*7($ctx),$H
1880
1881         mov     $A,$SZ*0($ctx)
1882         mov     $B,$SZ*1($ctx)
1883         mov     $C,$SZ*2($ctx)
1884         mov     $D,$SZ*3($ctx)
1885         mov     $E,$SZ*4($ctx)
1886         mov     $F,$SZ*5($ctx)
1887         mov     $G,$SZ*6($ctx)
1888         mov     $H,$SZ*7($ctx)
1889
1890         cmp     `$PUSH8+2*8`($Tbl),$inp # $_end
1891         je      .Ldone_avx2
1892
1893         xor     $a1,$a1
1894         mov     $B,$a3
1895         xor     $C,$a3                  # magic
1896         mov     $F,$a4
1897         jmp     .Lower_avx2
1898 .align  16
1899 .Lower_avx2:
1900 ___
1901     for ($i=0; $i<8; ) {
1902         my $base="+16($Tbl)";
1903         foreach(bodyx_00_15()) { eval; }
1904     }
1905 $code.=<<___;
1906         lea     -$PUSH8($Tbl),$Tbl
1907         cmp     %rsp,$Tbl
1908         jae     .Lower_avx2
1909
1910         mov     `2*$SZ*$rounds`(%rsp),$ctx      # $_ctx
1911         add     $a1,$A
1912         #mov    `2*$SZ*$rounds+8`(%rsp),$inp    # $_inp
1913         lea     `2*$SZ*($rounds-8)`(%rsp),%rsp
1914
1915         add     $SZ*0($ctx),$A
1916         add     $SZ*1($ctx),$B
1917         add     $SZ*2($ctx),$C
1918         add     $SZ*3($ctx),$D
1919         add     $SZ*4($ctx),$E
1920         add     $SZ*5($ctx),$F
1921         lea     `2*16*$SZ`($inp),$inp   # inp+=2
1922         add     $SZ*6($ctx),$G
1923         mov     $inp,%r12
1924         add     $SZ*7($ctx),$H
1925         cmp     $_end,$inp
1926
1927         mov     $A,$SZ*0($ctx)
1928         cmove   %rsp,%r12               # next block or stale data
1929         mov     $B,$SZ*1($ctx)
1930         mov     $C,$SZ*2($ctx)
1931         mov     $D,$SZ*3($ctx)
1932         mov     $E,$SZ*4($ctx)
1933         mov     $F,$SZ*5($ctx)
1934         mov     $G,$SZ*6($ctx)
1935         mov     $H,$SZ*7($ctx)
1936
1937         jbe     .Loop_avx2
1938         lea     (%rsp),$Tbl
1939
1940 .Ldone_avx2:
1941         lea     ($Tbl),%rsp
1942         mov     $_rsp,%rsi
1943         vzeroall
1944 ___
1945 $code.=<<___ if ($win64);
1946         movaps  16*$SZ+32(%rsp),%xmm6
1947         movaps  16*$SZ+48(%rsp),%xmm7
1948         movaps  16*$SZ+64(%rsp),%xmm8
1949         movaps  16*$SZ+80(%rsp),%xmm9
1950 ___
1951 $code.=<<___ if ($win64 && $SZ>4);
1952         movaps  16*$SZ+96(%rsp),%xmm10
1953         movaps  16*$SZ+112(%rsp),%xmm11
1954 ___
1955 $code.=<<___;
1956         mov     (%rsi),%r15
1957         mov     8(%rsi),%r14
1958         mov     16(%rsi),%r13
1959         mov     24(%rsi),%r12
1960         mov     32(%rsi),%rbp
1961         mov     40(%rsi),%rbx
1962         lea     48(%rsi),%rsp
1963 .Lepilogue_avx2:
1964         ret
1965 .size   ${func}_avx2,.-${func}_avx2
1966 ___
1967 }}
1968 }}}}}
1969
1970 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1971 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1972 if ($win64) {
1973 $rec="%rcx";
1974 $frame="%rdx";
1975 $context="%r8";
1976 $disp="%r9";
1977
1978 $code.=<<___;
1979 .extern __imp_RtlVirtualUnwind
1980 .type   se_handler,\@abi-omnipotent
1981 .align  16
1982 se_handler:
1983         push    %rsi
1984         push    %rdi
1985         push    %rbx
1986         push    %rbp
1987         push    %r12
1988         push    %r13
1989         push    %r14
1990         push    %r15
1991         pushfq
1992         sub     \$64,%rsp
1993
1994         mov     120($context),%rax      # pull context->Rax
1995         mov     248($context),%rbx      # pull context->Rip
1996
1997         mov     8($disp),%rsi           # disp->ImageBase
1998         mov     56($disp),%r11          # disp->HanderlData
1999
2000         mov     0(%r11),%r10d           # HandlerData[0]
2001         lea     (%rsi,%r10),%r10        # prologue label
2002         cmp     %r10,%rbx               # context->Rip<prologue label
2003         jb      .Lin_prologue
2004
2005         mov     152($context),%rax      # pull context->Rsp
2006
2007         mov     4(%r11),%r10d           # HandlerData[1]
2008         lea     (%rsi,%r10),%r10        # epilogue label
2009         cmp     %r10,%rbx               # context->Rip>=epilogue label
2010         jae     .Lin_prologue
2011 ___
2012 $code.=<<___ if ($avx>1);
2013         lea     .Lavx2_shortcut(%rip),%r10
2014         cmp     %r10,%rbx               # context->Rip<avx2_shortcut
2015         jb      .Lnot_in_avx2
2016
2017         and     \$-256*$SZ,%rax
2018         add     \$`2*$SZ*($rounds-8)`,%rax
2019 .Lnot_in_avx2:
2020 ___
2021 $code.=<<___;
2022         mov     %rax,%rsi               # put aside Rsp
2023         mov     16*$SZ+3*8(%rax),%rax   # pull $_rsp
2024         lea     48(%rax),%rax
2025
2026         mov     -8(%rax),%rbx
2027         mov     -16(%rax),%rbp
2028         mov     -24(%rax),%r12
2029         mov     -32(%rax),%r13
2030         mov     -40(%rax),%r14
2031         mov     -48(%rax),%r15
2032         mov     %rbx,144($context)      # restore context->Rbx
2033         mov     %rbp,160($context)      # restore context->Rbp
2034         mov     %r12,216($context)      # restore context->R12
2035         mov     %r13,224($context)      # restore context->R13
2036         mov     %r14,232($context)      # restore context->R14
2037         mov     %r15,240($context)      # restore context->R15
2038
2039         lea     .Lepilogue(%rip),%r10
2040         cmp     %r10,%rbx
2041         jb      .Lin_prologue           # non-AVX code
2042
2043         lea     16*$SZ+4*8(%rsi),%rsi   # Xmm6- save area
2044         lea     512($context),%rdi      # &context.Xmm6
2045         mov     \$`$SZ==4?8:12`,%ecx
2046         .long   0xa548f3fc              # cld; rep movsq
2047
2048 .Lin_prologue:
2049         mov     8(%rax),%rdi
2050         mov     16(%rax),%rsi
2051         mov     %rax,152($context)      # restore context->Rsp
2052         mov     %rsi,168($context)      # restore context->Rsi
2053         mov     %rdi,176($context)      # restore context->Rdi
2054
2055         mov     40($disp),%rdi          # disp->ContextRecord
2056         mov     $context,%rsi           # context
2057         mov     \$154,%ecx              # sizeof(CONTEXT)
2058         .long   0xa548f3fc              # cld; rep movsq
2059
2060         mov     $disp,%rsi
2061         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
2062         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
2063         mov     0(%rsi),%r8             # arg3, disp->ControlPc
2064         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
2065         mov     40(%rsi),%r10           # disp->ContextRecord
2066         lea     56(%rsi),%r11           # &disp->HandlerData
2067         lea     24(%rsi),%r12           # &disp->EstablisherFrame
2068         mov     %r10,32(%rsp)           # arg5
2069         mov     %r11,40(%rsp)           # arg6
2070         mov     %r12,48(%rsp)           # arg7
2071         mov     %rcx,56(%rsp)           # arg8, (NULL)
2072         call    *__imp_RtlVirtualUnwind(%rip)
2073
2074         mov     \$1,%eax                # ExceptionContinueSearch
2075         add     \$64,%rsp
2076         popfq
2077         pop     %r15
2078         pop     %r14
2079         pop     %r13
2080         pop     %r12
2081         pop     %rbp
2082         pop     %rbx
2083         pop     %rdi
2084         pop     %rsi
2085         ret
2086 .size   se_handler,.-se_handler
2087
2088 .section        .pdata
2089 .align  4
2090         .rva    .LSEH_begin_$func
2091         .rva    .LSEH_end_$func
2092         .rva    .LSEH_info_$func
2093 ___
2094 $code.=<<___ if ($SZ==4);
2095         .rva    .LSEH_begin_${func}_ssse3
2096         .rva    .LSEH_end_${func}_ssse3
2097         .rva    .LSEH_info_${func}_ssse3
2098 ___
2099 $code.=<<___ if ($avx && $SZ==8);
2100         .rva    .LSEH_begin_${func}_xop
2101         .rva    .LSEH_end_${func}_xop
2102         .rva    .LSEH_info_${func}_xop
2103 ___
2104 $code.=<<___ if ($avx);
2105         .rva    .LSEH_begin_${func}_avx
2106         .rva    .LSEH_end_${func}_avx
2107         .rva    .LSEH_info_${func}_avx
2108 ___
2109 $code.=<<___ if ($avx>1);
2110         .rva    .LSEH_begin_${func}_avx2
2111         .rva    .LSEH_end_${func}_avx2
2112         .rva    .LSEH_info_${func}_avx2
2113 ___
2114 $code.=<<___;
2115 .section        .xdata
2116 .align  8
2117 .LSEH_info_$func:
2118         .byte   9,0,0,0
2119         .rva    se_handler
2120         .rva    .Lprologue,.Lepilogue                   # HandlerData[]
2121 ___
2122 $code.=<<___ if ($SZ==4);
2123 .LSEH_info_${func}_ssse3:
2124         .byte   9,0,0,0
2125         .rva    se_handler
2126         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
2127 ___
2128 $code.=<<___ if ($avx && $SZ==8);
2129 .LSEH_info_${func}_xop:
2130         .byte   9,0,0,0
2131         .rva    se_handler
2132         .rva    .Lprologue_xop,.Lepilogue_xop           # HandlerData[]
2133 ___
2134 $code.=<<___ if ($avx);
2135 .LSEH_info_${func}_avx:
2136         .byte   9,0,0,0
2137         .rva    se_handler
2138         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
2139 ___
2140 $code.=<<___ if ($avx>1);
2141 .LSEH_info_${func}_avx2:
2142         .byte   9,0,0,0
2143         .rva    se_handler
2144         .rva    .Lprologue_avx2,.Lepilogue_avx2         # HandlerData[]
2145 ___
2146 }
2147
2148 $code =~ s/\`([^\`]*)\`/eval $1/gem;
2149 print $code;
2150 close STDOUT;