[aesni|sha*]-mb-x86_64.pl: add data prefetching.
[openssl.git] / crypto / sha / asm / sha256-mb-x86_64.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9
10 # Multi-buffer SHA256 procedure processes n buffers in parallel by
11 # placing buffer data to designated lane of SIMD register. n is
12 # naturally limited to 4 on pre-AVX2 processors and to 8 on
13 # AVX2-capable processors such as Haswell.
14 #
15 #               this    +aesni(i)       sha256  aesni-sha256    gain(iv)
16 # -------------------------------------------------------------------
17 # Westmere(ii)  23.3/n  +1.28=7.11(n=4) 12.3    +3.75=16.1      +126%
18 # Atom(ii)      ?39.1/n +3.93=13.7(n=4) 20.8    +5.69=26.5      +93%
19 # Sandy Bridge  (20.5   +5.15=25.7)/n   11.6    13.0            +103%
20 # Ivy Bridge    (20.4   +5.14=25.5)/n   10.3    11.6            +82%
21 # Haswell(iii)  (21.0   +5.00=26.0)/n   7.80    8.79            +170%
22 # Bulldozer     (21.6   +5.76=27.4)/n   13.6    13.7            +100%
23 #
24 # (i)   multi-block CBC encrypt with 128-bit key;
25 # (ii)  (HASH+AES)/n does not apply to Westmere for n>3 and Atom,
26 #       because of lower AES-NI instruction throughput, nor is there
27 #       AES-NI-SHA256 stitch for these processors;
28 # (iii) "this" is for n=8, when we gather twice as much data, result
29 #       for n=4 is 20.3+4.44=24.7;
30 # (iv)  presented improvement coefficients are asymptotic limits and
31 #       in real-life application are somewhat lower, e.g. for 2KB 
32 #       fragments they range from 75% to 13% (on Haswell);
33
34 $flavour = shift;
35 $output  = shift;
36 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
37
38 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
39
40 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
41 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
42 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
43 die "can't locate x86_64-xlate.pl";
44
45 $avx=0;
46
47 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
48                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
49         $avx = ($1>=2.19) + ($1>=2.22);
50 }
51
52 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
53            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
54         $avx = ($1>=2.09) + ($1>=2.10);
55 }
56
57 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
58            `ml64 2>&1` =~ /Version ([0-9]+)\./) {
59         $avx = ($1>=10) + ($1>=11);
60 }
61
62 open OUT,"| \"$^X\" $xlate $flavour $output";
63 *STDOUT=*OUT;
64
65 # void sha256_multi_block (
66 #     struct {  unsigned int A[8];
67 #               unsigned int B[8];
68 #               unsigned int C[8];
69 #               unsigned int D[8];
70 #               unsigned int E[8];
71 #               unsigned int F[8];
72 #               unsigned int G[8];
73 #               unsigned int H[8];      } *ctx,
74 #     struct {  void *ptr; int blocks;  } inp[8],
75 #     int num);         /* 1 or 2 */
76 #
77 $ctx="%rdi";    # 1st arg
78 $inp="%rsi";    # 2nd arg
79 $num="%edx";    # 3rd arg
80 @ptr=map("%r$_",(8..11));
81 $Tbl="%rbp";
82
83 @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("%xmm$_",(8..15));
84 ($t1,$t2,$t3,$axb,$bxc,$Xi,$Xn,$sigma)=map("%xmm$_",(0..7));
85
86 $REG_SZ=16;
87
88 sub Xi_off {
89 my $off = shift;
90
91     $off %= 16; $off *= $REG_SZ;
92     $off<256 ? "$off-128(%rax)" : "$off-256-128(%rbx)";
93 }
94
95 sub ROUND_00_15 {
96 my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
97
98 $code.=<<___ if ($i<15);
99         movd            `4*$i`(@ptr[0]),$Xi
100         movd            `4*$i`(@ptr[1]),$t1
101         movd            `4*$i`(@ptr[2]),$t2
102         movd            `4*$i`(@ptr[3]),$t3
103         punpckldq       $t2,$Xi
104         punpckldq       $t3,$t1
105         punpckldq       $t1,$Xi
106         pshufb          $Xn,$Xi
107 ___
108 $code.=<<___ if ($i==15);
109         movd            `4*$i`(@ptr[0]),$Xi
110          lea            `16*4`(@ptr[0]),@ptr[0]
111         movd            `4*$i`(@ptr[1]),$t1
112          lea            `16*4`(@ptr[1]),@ptr[1]
113         movd            `4*$i`(@ptr[2]),$t2
114          lea            `16*4`(@ptr[2]),@ptr[2]
115         movd            `4*$i`(@ptr[3]),$t3
116          lea            `16*4`(@ptr[3]),@ptr[3]
117         punpckldq       $t2,$Xi
118         punpckldq       $t3,$t1
119         punpckldq       $t1,$Xi
120         pshufb          $Xn,$Xi
121 ___
122 $code.=<<___;
123         movdqa  $e,$sigma
124         movdqa  $e,$t3
125         psrld   \$6,$sigma
126         movdqa  $e,$t2
127         pslld   \$7,$t3
128         movdqa  $Xi,`&Xi_off($i)`
129          paddd  $h,$Xi                          # Xi+=h
130
131         psrld   \$11,$t2
132         pxor    $t3,$sigma
133         pslld   \$21-7,$t3
134          paddd  `32*($i%8)-128`($Tbl),$Xi       # Xi+=K[round]
135         pxor    $t2,$sigma
136
137         psrld   \$25-11,$t2
138          movdqa $e,$t1
139          `"prefetch     63(@ptr[0])"            if ($i==15)`
140         pxor    $t3,$sigma
141          movdqa $e,$axb                         # borrow $axb
142         pslld   \$26-21,$t3
143          pandn  $g,$t1
144          pand   $f,$axb
145         pxor    $t2,$sigma
146
147          `"prefetch     63(@ptr[1])"            if ($i==15)`
148         movdqa  $a,$t2
149         pxor    $t3,$sigma                      # Sigma1(e)
150         movdqa  $a,$t3
151         psrld   \$2,$t2
152         paddd   $sigma,$Xi                      # Xi+=Sigma1(e)
153          pxor   $axb,$t1                        # Ch(e,f,g)
154          movdqa $b,$axb
155         movdqa  $a,$sigma
156         pslld   \$10,$t3
157          pxor   $a,$axb                         # a^b, b^c in next round
158
159          `"prefetch     63(@ptr[2])"            if ($i==15)`
160         psrld   \$13,$sigma
161         pxor    $t3,$t2
162          paddd  $t1,$Xi                         # Xi+=Ch(e,f,g)
163         pslld   \$19-10,$t3
164          pand   $axb,$bxc
165         pxor    $sigma,$t2
166
167          `"prefetch     63(@ptr[3])"            if ($i==15)`
168         psrld   \$22-13,$sigma
169         pxor    $t3,$t2
170          movdqa $b,$h
171         pslld   \$30-19,$t3
172         pxor    $t2,$sigma
173          pxor   $bxc,$h                         # h=Maj(a,b,c)=Ch(a^b,c,b)
174          paddd  $Xi,$d                          # d+=Xi
175         pxor    $t3,$sigma                      # Sigma0(a)
176
177         paddd   $Xi,$h                          # h+=Xi
178         paddd   $sigma,$h                       # h+=Sigma0(a)
179 ___
180 $code.=<<___ if (($i%8)==7);
181         lea     `32*8`($Tbl),$Tbl
182 ___
183         ($axb,$bxc)=($bxc,$axb);
184 }
185
186 sub ROUND_16_XX {
187 my $i=shift;
188
189 $code.=<<___;
190         movdqa  `&Xi_off($i+1)`,$Xn
191         paddd   `&Xi_off($i+9)`,$Xi             # Xi+=X[i+9]
192
193         movdqa  $Xn,$sigma
194         movdqa  $Xn,$t2
195         psrld   \$3,$sigma
196         movdqa  $Xn,$t3
197
198         psrld   \$7,$t2
199         movdqa  `&Xi_off($i+14)`,$t1
200         pslld   \$14,$t3
201         pxor    $t2,$sigma
202         psrld   \$18-7,$t2
203         movdqa  $t1,$axb                        # borrow $axb
204         pxor    $t3,$sigma
205         pslld   \$25-14,$t3
206         pxor    $t2,$sigma
207         psrld   \$10,$t1
208         movdqa  $axb,$t2
209
210         psrld   \$17,$axb
211         pxor    $t3,$sigma                      # sigma0(X[i+1])
212         pslld   \$13,$t2
213          paddd  $sigma,$Xi                      # Xi+=sigma0(e)
214         pxor    $axb,$t1
215         psrld   \$19-17,$axb
216         pxor    $t2,$t1
217         pslld   \$15-13,$t2
218         pxor    $axb,$t1
219         pxor    $t2,$t1                         # sigma0(X[i+14])
220         paddd   $t1,$Xi                         # Xi+=sigma1(X[i+14])
221 ___
222         &ROUND_00_15($i,@_);
223         ($Xi,$Xn)=($Xn,$Xi);
224 }
225
226 $code.=<<___;
227 .text
228
229 .extern OPENSSL_ia32cap_P
230
231 .globl  sha256_multi_block
232 .type   sha256_multi_block,\@function,3
233 .align  32
234 sha256_multi_block:
235 ___
236 $code.=<<___ if ($avx);
237         mov     OPENSSL_ia32cap_P+4(%rip),%rcx
238         test    \$`1<<28`,%ecx
239         jnz     _avx_shortcut
240 ___
241 $code.=<<___;
242         mov     %rsp,%rax
243         push    %rbx
244         push    %rbp
245 ___
246 $code.=<<___ if ($win64);
247         lea     -0xa8(%rsp),%rsp
248         movaps  %xmm6,(%rsp)
249         movaps  %xmm7,0x10(%rsp)
250         movaps  %xmm8,0x20(%rsp)
251         movaps  %xmm9,0x30(%rsp)
252         movaps  %xmm10,-0x78(%rax)
253         movaps  %xmm11,-0x68(%rax)
254         movaps  %xmm12,-0x58(%rax)
255         movaps  %xmm13,-0x48(%rax)
256         movaps  %xmm14,-0x38(%rax)
257         movaps  %xmm15,-0x28(%rax)
258 ___
259 $code.=<<___;
260         sub     \$`$REG_SZ*18`, %rsp
261         and     \$-256,%rsp
262         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
263         lea     K256+128(%rip),$Tbl
264         lea     `$REG_SZ*16`(%rsp),%rbx
265         lea     0x80($ctx),$ctx                 # size optimization
266
267 .Loop_grande:
268         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
269         xor     $num,$num
270 ___
271 for($i=0;$i<4;$i++) {
272     $code.=<<___;
273         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
274         mov     `16*$i+8`($inp),%ecx            # number of blocks
275         cmp     $num,%ecx
276         cmovg   %ecx,$num                       # find maximum
277         test    %ecx,%ecx
278         mov     %ecx,`4*$i`(%rbx)               # initialize counters
279         cmovle  $Tbl,@ptr[$i]                   # cancel input
280 ___
281 }
282 $code.=<<___;
283         test    $num,$num
284         jz      .Ldone
285
286         movdqu  0x00-0x80($ctx),$A              # load context
287          lea    128(%rsp),%rax
288         movdqu  0x20-0x80($ctx),$B
289         movdqu  0x40-0x80($ctx),$C
290         movdqu  0x60-0x80($ctx),$D
291         movdqu  0x80-0x80($ctx),$E
292         movdqu  0xa0-0x80($ctx),$F
293         movdqu  0xc0-0x80($ctx),$G
294         movdqu  0xe0-0x80($ctx),$H
295         movdqu  .Lpbswap(%rip),$Xn
296         jmp     .Loop
297
298 .align  32
299 .Loop:
300         movdqa  $C,$bxc
301         pxor    $B,$bxc                         # magic seed
302 ___
303 for($i=0;$i<16;$i++)    { &ROUND_00_15($i,@V); unshift(@V,pop(@V)); }
304 $code.=<<___;
305         movdqu  `&Xi_off($i)`,$Xi
306         mov     \$3,%ecx
307         jmp     .Loop_16_xx
308 .align  32
309 .Loop_16_xx:
310 ___
311 for(;$i<32;$i++)        { &ROUND_16_XX($i,@V); unshift(@V,pop(@V)); }
312 $code.=<<___;
313         dec     %ecx
314         jnz     .Loop_16_xx
315
316         mov     \$1,%ecx
317         lea     K256+128(%rip),$Tbl
318
319         movdqa  (%rbx),$sigma                   # pull counters
320         cmp     4*0(%rbx),%ecx                  # examine counters
321         pxor    $t1,$t1
322         cmovge  $Tbl,@ptr[0]                    # cancel input
323         cmp     4*1(%rbx),%ecx
324         movdqa  $sigma,$Xn
325         cmovge  $Tbl,@ptr[1]
326         cmp     4*2(%rbx),%ecx
327         pcmpgtd $t1,$Xn                         # mask value
328         cmovge  $Tbl,@ptr[2]
329         cmp     4*3(%rbx),%ecx
330         paddd   $Xn,$sigma                      # counters--
331         cmovge  $Tbl,@ptr[3]
332
333         movdqu  0x00-0x80($ctx),$t1
334         pand    $Xn,$A
335         movdqu  0x20-0x80($ctx),$t2
336         pand    $Xn,$B
337         movdqu  0x40-0x80($ctx),$t3
338         pand    $Xn,$C
339         movdqu  0x60-0x80($ctx),$Xi
340         pand    $Xn,$D
341         paddd   $t1,$A
342         movdqu  0x80-0x80($ctx),$t1
343         pand    $Xn,$E
344         paddd   $t2,$B
345         movdqu  0xa0-0x80($ctx),$t2
346         pand    $Xn,$F
347         paddd   $t3,$C
348         movdqu  0xc0-0x80($ctx),$t3
349         pand    $Xn,$G
350         paddd   $Xi,$D
351         movdqu  0xe0-0x80($ctx),$Xi
352         pand    $Xn,$H
353         paddd   $t1,$E
354         paddd   $t2,$F
355         movdqu  $A,0x00-0x80($ctx)
356         paddd   $t3,$G
357         movdqu  $B,0x20-0x80($ctx)
358         paddd   $Xi,$H
359         movdqu  $C,0x40-0x80($ctx)
360         movdqu  $D,0x60-0x80($ctx)
361         movdqu  $E,0x80-0x80($ctx)
362         movdqu  $F,0xa0-0x80($ctx)
363         movdqu  $G,0xc0-0x80($ctx)
364         movdqu  $H,0xe0-0x80($ctx)
365
366         movdqa  $sigma,(%rbx)                   # save counters
367         movdqa  .Lpbswap(%rip),$Xn
368         dec     $num
369         jnz     .Loop
370
371         mov     `$REG_SZ*17+8`(%rsp),$num
372         lea     $REG_SZ($ctx),$ctx
373         lea     `16*$REG_SZ/4`($inp),$inp
374         dec     $num
375         jnz     .Loop_grande
376
377 .Ldone:
378         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
379 ___
380 $code.=<<___ if ($win64);
381         movaps  -0xb8(%rax),%xmm6
382         movaps  -0xa8(%rax),%xmm7
383         movaps  -0x98(%rax),%xmm8
384         movaps  -0x88(%rax),%xmm9
385         movaps  -0x78(%rax),%xmm10
386         movaps  -0x68(%rax),%xmm11
387         movaps  -0x58(%rax),%xmm12
388         movaps  -0x48(%rax),%xmm13
389         movaps  -0x38(%rax),%xmm14
390         movaps  -0x28(%rax),%xmm15
391 ___
392 $code.=<<___;
393         mov     -16(%rax),%rbp
394         mov     -8(%rax),%rbx
395         lea     (%rax),%rsp
396         ret
397 .size   sha256_multi_block,.-sha256_multi_block
398 ___
399                                                 if ($avx) {{{
400 sub ROUND_00_15_avx {
401 my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
402
403 $code.=<<___ if ($i<15 && $REG_SZ==16);
404         vmovd           `4*$i`(@ptr[0]),$Xi
405         vmovd           `4*$i`(@ptr[1]),$t1
406         vpinsrd         \$1,`4*$i`(@ptr[2]),$Xi,$Xi
407         vpinsrd         \$1,`4*$i`(@ptr[3]),$t1,$t1
408         vpunpckldq      $t1,$Xi,$Xi
409         vpshufb         $Xn,$Xi,$Xi
410 ___
411 $code.=<<___ if ($i==15 && $REG_SZ==16);
412         vmovd           `4*$i`(@ptr[0]),$Xi
413          lea            `16*4`(@ptr[0]),@ptr[0]
414         vmovd           `4*$i`(@ptr[1]),$t1
415          lea            `16*4`(@ptr[1]),@ptr[1]
416         vpinsrd         \$1,`4*$i`(@ptr[2]),$Xi,$Xi
417          lea            `16*4`(@ptr[2]),@ptr[2]
418         vpinsrd         \$1,`4*$i`(@ptr[3]),$t1,$t1
419          lea            `16*4`(@ptr[3]),@ptr[3]
420         vpunpckldq      $t1,$Xi,$Xi
421         vpshufb         $Xn,$Xi,$Xi
422 ___
423 $code.=<<___ if ($i<15 && $REG_SZ==32);
424         vmovd           `4*$i`(@ptr[0]),$Xi
425         vmovd           `4*$i`(@ptr[4]),$t1
426         vmovd           `4*$i`(@ptr[1]),$t2
427         vmovd           `4*$i`(@ptr[5]),$t3
428         vpinsrd         \$1,`4*$i`(@ptr[2]),$Xi,$Xi
429         vpinsrd         \$1,`4*$i`(@ptr[6]),$t1,$t1
430         vpinsrd         \$1,`4*$i`(@ptr[3]),$t2,$t2
431         vpunpckldq      $t2,$Xi,$Xi
432         vpinsrd         \$1,`4*$i`(@ptr[7]),$t3,$t3
433         vpunpckldq      $t3,$t1,$t1
434         vinserti128     $t1,$Xi,$Xi
435         vpshufb         $Xn,$Xi,$Xi
436 ___
437 $code.=<<___ if ($i==15 && $REG_SZ==32);
438         vmovd           `4*$i`(@ptr[0]),$Xi
439          lea            `16*4`(@ptr[0]),@ptr[0]
440         vmovd           `4*$i`(@ptr[4]),$t1
441          lea            `16*4`(@ptr[4]),@ptr[4]
442         vmovd           `4*$i`(@ptr[1]),$t2
443          lea            `16*4`(@ptr[1]),@ptr[1]
444         vmovd           `4*$i`(@ptr[5]),$t3
445          lea            `16*4`(@ptr[5]),@ptr[5]
446         vpinsrd         \$1,`4*$i`(@ptr[2]),$Xi,$Xi
447          lea            `16*4`(@ptr[2]),@ptr[2]
448         vpinsrd         \$1,`4*$i`(@ptr[6]),$t1,$t1
449          lea            `16*4`(@ptr[6]),@ptr[6]
450         vpinsrd         \$1,`4*$i`(@ptr[3]),$t2,$t2
451          lea            `16*4`(@ptr[3]),@ptr[3]
452         vpunpckldq      $t2,$Xi,$Xi
453         vpinsrd         \$1,`4*$i`(@ptr[7]),$t3,$t3
454          lea            `16*4`(@ptr[7]),@ptr[7]
455         vpunpckldq      $t3,$t1,$t1
456         vinserti128     $t1,$Xi,$Xi
457         vpshufb         $Xn,$Xi,$Xi
458 ___
459 $code.=<<___;
460         vpsrld  \$6,$e,$sigma
461         vpslld  \$26,$e,$t3
462         vmovdqu $Xi,`&Xi_off($i)`
463          vpaddd $h,$Xi,$Xi                      # Xi+=h
464
465         vpsrld  \$11,$e,$t2
466         vpxor   $t3,$sigma,$sigma
467         vpslld  \$21,$e,$t3
468          vpaddd `32*($i%8)-128`($Tbl),$Xi,$Xi   # Xi+=K[round]
469         vpxor   $t2,$sigma,$sigma
470
471         vpsrld  \$25,$e,$t2
472         vpxor   $t3,$sigma,$sigma
473          `"prefetch     63(@ptr[0])"            if ($i==15)`
474         vpslld  \$7,$e,$t3
475          vpandn $g,$e,$t1
476          vpand  $f,$e,$axb                      # borrow $axb
477          `"prefetch     63(@ptr[1])"            if ($i==15)`
478         vpxor   $t2,$sigma,$sigma
479
480         vpsrld  \$2,$a,$h                       # borrow $h
481         vpxor   $t3,$sigma,$sigma               # Sigma1(e)
482          `"prefetch     63(@ptr[2])"            if ($i==15)`
483         vpslld  \$30,$a,$t2
484          vpxor  $axb,$t1,$t1                    # Ch(e,f,g)
485          vpxor  $a,$b,$axb                      # a^b, b^c in next round
486          `"prefetch     63(@ptr[3])"            if ($i==15)`
487         vpxor   $t2,$h,$h
488         vpaddd  $sigma,$Xi,$Xi                  # Xi+=Sigma1(e)
489
490         vpsrld  \$13,$a,$t2
491          `"prefetch     63(@ptr[4])"            if ($i==15 && $REG_SZ==32)`
492         vpslld  \$19,$a,$t3
493          vpaddd $t1,$Xi,$Xi                     # Xi+=Ch(e,f,g)
494          vpand  $axb,$bxc,$bxc
495          `"prefetch     63(@ptr[5])"            if ($i==15 && $REG_SZ==32)`
496         vpxor   $t2,$h,$sigma
497
498         vpsrld  \$22,$a,$t2
499         vpxor   $t3,$sigma,$sigma
500          `"prefetch     63(@ptr[6])"            if ($i==15 && $REG_SZ==32)`
501         vpslld  \$10,$a,$t3
502          vpxor  $bxc,$b,$h                      # h=Maj(a,b,c)=Ch(a^b,c,b)
503          vpaddd $Xi,$d,$d                       # d+=Xi
504          `"prefetch     63(@ptr[7])"            if ($i==15 && $REG_SZ==32)`
505         vpxor   $t2,$sigma,$sigma
506         vpxor   $t3,$sigma,$sigma               # Sigma0(a)
507
508         vpaddd  $Xi,$h,$h                       # h+=Xi
509         vpaddd  $sigma,$h,$h                    # h+=Sigma0(a)
510 ___
511 $code.=<<___ if (($i%8)==7);
512         add     \$`32*8`,$Tbl
513 ___
514         ($axb,$bxc)=($bxc,$axb);
515 }
516
517 sub ROUND_16_XX_avx {
518 my $i=shift;
519
520 $code.=<<___;
521         vmovdqu `&Xi_off($i+1)`,$Xn
522         vpaddd  `&Xi_off($i+9)`,$Xi,$Xi         # Xi+=X[i+9]
523
524         vpsrld  \$3,$Xn,$sigma
525         vpsrld  \$7,$Xn,$t2
526         vpslld  \$25,$Xn,$t3
527         vpxor   $t2,$sigma,$sigma
528         vpsrld  \$18,$Xn,$t2
529         vpxor   $t3,$sigma,$sigma
530         vpslld  \$14,$Xn,$t3
531         vmovdqu `&Xi_off($i+14)`,$t1
532         vpsrld  \$10,$t1,$axb                   # borrow $axb
533
534         vpxor   $t2,$sigma,$sigma
535         vpsrld  \$17,$t1,$t2
536         vpxor   $t3,$sigma,$sigma               # sigma0(X[i+1])
537         vpslld  \$15,$t1,$t3
538          vpaddd $sigma,$Xi,$Xi                  # Xi+=sigma0(e)
539         vpxor   $t2,$axb,$sigma
540         vpsrld  \$19,$t1,$t2
541         vpxor   $t3,$sigma,$sigma
542         vpslld  \$13,$t1,$t3
543         vpxor   $t2,$sigma,$sigma
544         vpxor   $t3,$sigma,$sigma               # sigma0(X[i+14])
545         vpaddd  $sigma,$Xi,$Xi                  # Xi+=sigma1(X[i+14])
546 ___
547         &ROUND_00_15_avx($i,@_);
548         ($Xi,$Xn)=($Xn,$Xi);
549 }
550
551 $code.=<<___;
552 .type   sha256_multi_block_avx,\@function,3
553 .align  32
554 sha256_multi_block_avx:
555 _avx_shortcut:
556 ___
557 $code.=<<___ if ($avx>1);
558         shr     \$32,%rcx
559         cmp     \$2,$num
560         jb      .Lavx
561         test    \$`1<<5`,%ecx
562         jnz     _avx2_shortcut
563         jmp     .Lavx
564 .align  32
565 .Lavx:
566 ___
567 $code.=<<___;
568         mov     %rsp,%rax
569         push    %rbx
570         push    %rbp
571 ___
572 $code.=<<___ if ($win64);
573         lea     -0xa8(%rsp),%rsp
574         movaps  %xmm6,(%rsp)
575         movaps  %xmm7,0x10(%rsp)
576         movaps  %xmm8,0x20(%rsp)
577         movaps  %xmm9,0x30(%rsp)
578         movaps  %xmm10,-0x78(%rax)
579         movaps  %xmm11,-0x68(%rax)
580         movaps  %xmm12,-0x58(%rax)
581         movaps  %xmm13,-0x48(%rax)
582         movaps  %xmm14,-0x38(%rax)
583         movaps  %xmm15,-0x28(%rax)
584 ___
585 $code.=<<___;
586         sub     \$`$REG_SZ*18`, %rsp
587         and     \$-256,%rsp
588         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
589         lea     K256+128(%rip),$Tbl
590         lea     `$REG_SZ*16`(%rsp),%rbx
591         lea     0x80($ctx),$ctx                 # size optimization
592
593 .Loop_grande_avx:
594         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
595         xor     $num,$num
596 ___
597 for($i=0;$i<4;$i++) {
598     $code.=<<___;
599         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
600         mov     `16*$i+8`($inp),%ecx            # number of blocks
601         cmp     $num,%ecx
602         cmovg   %ecx,$num                       # find maximum
603         test    %ecx,%ecx
604         mov     %ecx,`4*$i`(%rbx)               # initialize counters
605         cmovle  $Tbl,@ptr[$i]                   # cancel input
606 ___
607 }
608 $code.=<<___;
609         test    $num,$num
610         jz      .Ldone_avx
611
612         vmovdqu 0x00-0x80($ctx),$A              # load context
613          lea    128(%rsp),%rax
614         vmovdqu 0x20-0x80($ctx),$B
615         vmovdqu 0x40-0x80($ctx),$C
616         vmovdqu 0x60-0x80($ctx),$D
617         vmovdqu 0x80-0x80($ctx),$E
618         vmovdqu 0xa0-0x80($ctx),$F
619         vmovdqu 0xc0-0x80($ctx),$G
620         vmovdqu 0xe0-0x80($ctx),$H
621         vmovdqu .Lpbswap(%rip),$Xn
622         jmp     .Loop_avx
623
624 .align  32
625 .Loop_avx:
626         vpxor   $B,$C,$bxc                      # magic seed
627 ___
628 for($i=0;$i<16;$i++)    { &ROUND_00_15_avx($i,@V); unshift(@V,pop(@V)); }
629 $code.=<<___;
630         vmovdqu `&Xi_off($i)`,$Xi
631         mov     \$3,%ecx
632         jmp     .Loop_16_xx_avx
633 .align  32
634 .Loop_16_xx_avx:
635 ___
636 for(;$i<32;$i++)        { &ROUND_16_XX_avx($i,@V); unshift(@V,pop(@V)); }
637 $code.=<<___;
638         dec     %ecx
639         jnz     .Loop_16_xx_avx
640
641         mov     \$1,%ecx
642         lea     K256+128(%rip),$Tbl
643 ___
644 for($i=0;$i<4;$i++) {
645     $code.=<<___;
646         cmp     `4*$i`(%rbx),%ecx               # examine counters
647         cmovge  $Tbl,@ptr[$i]                   # cancel input
648 ___
649 }
650 $code.=<<___;
651         vmovdqa (%rbx),$sigma                   # pull counters
652         vpxor   $t1,$t1,$t1
653         vmovdqa $sigma,$Xn
654         vpcmpgtd $t1,$Xn,$Xn                    # mask value
655         vpaddd  $Xn,$sigma,$sigma               # counters--
656
657         vmovdqu 0x00-0x80($ctx),$t1
658         vpand   $Xn,$A,$A
659         vmovdqu 0x20-0x80($ctx),$t2
660         vpand   $Xn,$B,$B
661         vmovdqu 0x40-0x80($ctx),$t3
662         vpand   $Xn,$C,$C
663         vmovdqu 0x60-0x80($ctx),$Xi
664         vpand   $Xn,$D,$D
665         vpaddd  $t1,$A,$A
666         vmovdqu 0x80-0x80($ctx),$t1
667         vpand   $Xn,$E,$E
668         vpaddd  $t2,$B,$B
669         vmovdqu 0xa0-0x80($ctx),$t2
670         vpand   $Xn,$F,$F
671         vpaddd  $t3,$C,$C
672         vmovdqu 0xc0-0x80($ctx),$t3
673         vpand   $Xn,$G,$G
674         vpaddd  $Xi,$D,$D
675         vmovdqu 0xe0-0x80($ctx),$Xi
676         vpand   $Xn,$H,$H
677         vpaddd  $t1,$E,$E
678         vpaddd  $t2,$F,$F
679         vmovdqu $A,0x00-0x80($ctx)
680         vpaddd  $t3,$G,$G
681         vmovdqu $B,0x20-0x80($ctx)
682         vpaddd  $Xi,$H,$H
683         vmovdqu $C,0x40-0x80($ctx)
684         vmovdqu $D,0x60-0x80($ctx)
685         vmovdqu $E,0x80-0x80($ctx)
686         vmovdqu $F,0xa0-0x80($ctx)
687         vmovdqu $G,0xc0-0x80($ctx)
688         vmovdqu $H,0xe0-0x80($ctx)
689
690         vmovdqu $sigma,(%rbx)                   # save counters
691         vmovdqu .Lpbswap(%rip),$Xn
692         dec     $num
693         jnz     .Loop_avx
694
695         mov     `$REG_SZ*17+8`(%rsp),$num
696         lea     $REG_SZ($ctx),$ctx
697         lea     `16*$REG_SZ/4`($inp),$inp
698         dec     $num
699         jnz     .Loop_grande_avx
700
701 .Ldone_avx:
702         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
703         vzeroupper
704 ___
705 $code.=<<___ if ($win64);
706         movaps  -0xb8(%rax),%xmm6
707         movaps  -0xa8(%rax),%xmm7
708         movaps  -0x98(%rax),%xmm8
709         movaps  -0x88(%rax),%xmm9
710         movaps  -0x78(%rax),%xmm10
711         movaps  -0x68(%rax),%xmm11
712         movaps  -0x58(%rax),%xmm12
713         movaps  -0x48(%rax),%xmm13
714         movaps  -0x38(%rax),%xmm14
715         movaps  -0x28(%rax),%xmm15
716 ___
717 $code.=<<___;
718         mov     -16(%rax),%rbp
719         mov     -8(%rax),%rbx
720         lea     (%rax),%rsp
721         ret
722 .size   sha256_multi_block_avx,.-sha256_multi_block_avx
723 ___
724                                                 if ($avx>1) {
725 $code =~ s/\`([^\`]*)\`/eval $1/gem;
726
727 $REG_SZ=32;
728 @ptr=map("%r$_",(12..15,8..11));
729
730 @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("%ymm$_",(8..15));
731 ($t1,$t2,$t3,$axb,$bxc,$Xi,$Xn,$sigma)=map("%ymm$_",(0..7));
732
733 $code.=<<___;
734 .type   sha256_multi_block_avx2,\@function,3
735 .align  32
736 sha256_multi_block_avx2:
737 _avx2_shortcut:
738         mov     %rsp,%rax
739         push    %rbx
740         push    %rbp
741         push    %r12
742         push    %r13
743         push    %r14
744         push    %r15
745 ___
746 $code.=<<___ if ($win64);
747         lea     -0xa8(%rsp),%rsp
748         movaps  %xmm6,(%rsp)
749         movaps  %xmm7,0x10(%rsp)
750         movaps  %xmm8,0x20(%rsp)
751         movaps  %xmm9,0x30(%rsp)
752         movaps  %xmm10,0x40(%rsp)
753         movaps  %xmm11,0x50(%rsp)
754         movaps  %xmm12,-0x78(%rax)
755         movaps  %xmm13,-0x68(%rax)
756         movaps  %xmm14,-0x58(%rax)
757         movaps  %xmm15,-0x48(%rax)
758 ___
759 $code.=<<___;
760         sub     \$`$REG_SZ*18`, %rsp
761         and     \$-256,%rsp
762         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
763         lea     K256+128(%rip),$Tbl
764         lea     0x80($ctx),$ctx                 # size optimization
765
766 .Loop_grande_avx2:
767         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
768         xor     $num,$num
769         lea     `$REG_SZ*16`(%rsp),%rbx
770 ___
771 for($i=0;$i<8;$i++) {
772     $code.=<<___;
773         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
774         mov     `16*$i+8`($inp),%ecx            # number of blocks
775         cmp     $num,%ecx
776         cmovg   %ecx,$num                       # find maximum
777         test    %ecx,%ecx
778         mov     %ecx,`4*$i`(%rbx)               # initialize counters
779         cmovle  $Tbl,@ptr[$i]                   # cancel input
780 ___
781 }
782 $code.=<<___;
783         vmovdqu 0x00-0x80($ctx),$A              # load context
784          lea    128(%rsp),%rax
785         vmovdqu 0x20-0x80($ctx),$B
786          lea    256+128(%rsp),%rbx
787         vmovdqu 0x40-0x80($ctx),$C
788         vmovdqu 0x60-0x80($ctx),$D
789         vmovdqu 0x80-0x80($ctx),$E
790         vmovdqu 0xa0-0x80($ctx),$F
791         vmovdqu 0xc0-0x80($ctx),$G
792         vmovdqu 0xe0-0x80($ctx),$H
793         vmovdqu .Lpbswap(%rip),$Xn
794         jmp     .Loop_avx2
795
796 .align  32
797 .Loop_avx2:
798         vpxor   $B,$C,$bxc                      # magic seed
799 ___
800 for($i=0;$i<16;$i++)    { &ROUND_00_15_avx($i,@V); unshift(@V,pop(@V)); }
801 $code.=<<___;
802         vmovdqu `&Xi_off($i)`,$Xi
803         mov     \$3,%ecx
804         jmp     .Loop_16_xx_avx2
805 .align  32
806 .Loop_16_xx_avx2:
807 ___
808 for(;$i<32;$i++)        { &ROUND_16_XX_avx($i,@V); unshift(@V,pop(@V)); }
809 $code.=<<___;
810         dec     %ecx
811         jnz     .Loop_16_xx_avx2
812
813         mov     \$1,%ecx
814         lea     `$REG_SZ*16`(%rsp),%rbx
815         lea     K256+128(%rip),$Tbl
816 ___
817 for($i=0;$i<8;$i++) {
818     $code.=<<___;
819         cmp     `4*$i`(%rbx),%ecx               # examine counters
820         cmovge  $Tbl,@ptr[$i]                   # cancel input
821 ___
822 }
823 $code.=<<___;
824         vmovdqa (%rbx),$sigma                   # pull counters
825         vpxor   $t1,$t1,$t1
826         vmovdqa $sigma,$Xn
827         vpcmpgtd $t1,$Xn,$Xn                    # mask value
828         vpaddd  $Xn,$sigma,$sigma               # counters--
829
830         vmovdqu 0x00-0x80($ctx),$t1
831         vpand   $Xn,$A,$A
832         vmovdqu 0x20-0x80($ctx),$t2
833         vpand   $Xn,$B,$B
834         vmovdqu 0x40-0x80($ctx),$t3
835         vpand   $Xn,$C,$C
836         vmovdqu 0x60-0x80($ctx),$Xi
837         vpand   $Xn,$D,$D
838         vpaddd  $t1,$A,$A
839         vmovdqu 0x80-0x80($ctx),$t1
840         vpand   $Xn,$E,$E
841         vpaddd  $t2,$B,$B
842         vmovdqu 0xa0-0x80($ctx),$t2
843         vpand   $Xn,$F,$F
844         vpaddd  $t3,$C,$C
845         vmovdqu 0xc0-0x80($ctx),$t3
846         vpand   $Xn,$G,$G
847         vpaddd  $Xi,$D,$D
848         vmovdqu 0xe0-0x80($ctx),$Xi
849         vpand   $Xn,$H,$H
850         vpaddd  $t1,$E,$E
851         vpaddd  $t2,$F,$F
852         vmovdqu $A,0x00-0x80($ctx)
853         vpaddd  $t3,$G,$G
854         vmovdqu $B,0x20-0x80($ctx)
855         vpaddd  $Xi,$H,$H
856         vmovdqu $C,0x40-0x80($ctx)
857         vmovdqu $D,0x60-0x80($ctx)
858         vmovdqu $E,0x80-0x80($ctx)
859         vmovdqu $F,0xa0-0x80($ctx)
860         vmovdqu $G,0xc0-0x80($ctx)
861         vmovdqu $H,0xe0-0x80($ctx)
862
863         vmovdqu $sigma,(%rbx)                   # save counters
864         lea     256+128(%rsp),%rbx
865         vmovdqu .Lpbswap(%rip),$Xn
866         dec     $num
867         jnz     .Loop_avx2
868
869         #mov    `$REG_SZ*17+8`(%rsp),$num
870         #lea    $REG_SZ($ctx),$ctx
871         #lea    `16*$REG_SZ/4`($inp),$inp
872         #dec    $num
873         #jnz    .Loop_grande_avx2
874
875 .Ldone_avx2:
876         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
877         vzeroupper
878 ___
879 $code.=<<___ if ($win64);
880         movaps  -0xd8(%rax),%xmm6
881         movaps  -0xc8(%rax),%xmm7
882         movaps  -0xb8(%rax),%xmm8
883         movaps  -0xa8(%rax),%xmm9
884         movaps  -0x98(%rax),%xmm10
885         movaps  -0x88(%rax),%xmm11
886         movaps  -0x78(%rax),%xmm12
887         movaps  -0x68(%rax),%xmm13
888         movaps  -0x58(%rax),%xmm14
889         movaps  -0x48(%rax),%xmm15
890 ___
891 $code.=<<___;
892         mov     -48(%rax),%r15
893         mov     -40(%rax),%r14
894         mov     -32(%rax),%r13
895         mov     -24(%rax),%r12
896         mov     -16(%rax),%rbp
897         mov     -8(%rax),%rbx
898         lea     (%rax),%rsp
899         ret
900 .size   sha256_multi_block_avx2,.-sha256_multi_block_avx2
901 ___
902                                         }       }}}
903 $code.=<<___;
904 .align  256
905 K256:
906 ___
907 sub TABLE {
908     foreach (@_) {
909         $code.=<<___;
910         .long   $_,$_,$_,$_
911         .long   $_,$_,$_,$_
912 ___
913     }
914 }
915 &TABLE( 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,
916         0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
917         0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,
918         0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
919         0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,
920         0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
921         0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,
922         0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
923         0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,
924         0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
925         0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,
926         0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
927         0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,
928         0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
929         0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,
930         0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 );
931 $code.=<<___;
932 .Lpbswap:
933         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap
934         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap
935 ___
936
937 foreach (split("\n",$code)) {
938         s/\`([^\`]*)\`/eval($1)/ge;
939
940         s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go          or
941         s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go         or
942         s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+),%ymm([0-9]+)/$1$2%xmm$3,%xmm$4/go    or
943         s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go        or
944         s/\b(vinserti128)\b(\s+)%ymm/$1$2\$1,%xmm/go            or
945         s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
946         print $_,"\n";
947 }
948
949 close STDOUT;