sha/asm/sha*-mb-x86_64.pl: commentary update.
[openssl.git] / crypto / sha / asm / sha1-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 SHA1 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)       sha1    aesni-sha1      gain(iv)
16 # -------------------------------------------------------------------
17 # Westmere(ii)  10.4/n  +1.28=3.88(n=4) 5.44    6.58            +70%
18 # Atom(ii)      18.9/n  +3.93=8.66(n=4) 10.0    14.0            +62%
19 # Sandy Bridge  (8.16   +5.15=13.3)/n   4.99    5.98            +80%
20 # Ivy Bridge    (8.03   +5.14=13.2)/n   4.60    5.54            +68%
21 # Haswell(iii)  (8.96   +5.00=14.0)/n   3.57    4.55            +160%
22 # Bulldozer     (9.75   +5.76=15.5)/n   5.95    6.37            +64%
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;
27 # (iii) "this" is for n=8, when we gather twice as much data, result
28 #       for n=4 is 7.98+4.44=12.4;
29 # (iv)  improvement coefficients in real-life application are somewhat
30 #       lower and range from 30% to 100% (on Haswell);
31
32 $flavour = shift;
33 $output  = shift;
34 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
35
36 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
37
38 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
39 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
40 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
41 die "can't locate x86_64-xlate.pl";
42
43 $avx=0;
44
45 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
46                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
47         $avx = ($1>=2.19) + ($1>=2.22);
48 }
49
50 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
51            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
52         $avx = ($1>=2.09) + ($1>=2.10);
53 }
54
55 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
56            `ml64 2>&1` =~ /Version ([0-9]+)\./) {
57         $avx = ($1>=10) + ($1>=11);
58 }
59
60 open OUT,"| \"$^X\" $xlate $flavour $output";
61 *STDOUT=*OUT;
62
63 # void sha1_multi_block (
64 #     struct {  unsigned int A[8];
65 #               unsigned int B[8];
66 #               unsigned int C[8];
67 #               unsigned int D[8];
68 #               unsigned int E[8];      } *ctx,
69 #     struct {  void *ptr; int blocks;  } inp[8],
70 #     int num);         /* 1 or 2 */
71 #
72 $ctx="%rdi";    # 1st arg
73 $inp="%rsi";    # 2nd arg
74 $num="%edx";
75 @ptr=map("%r$_",(8..11));
76 $Tbl="%rbp";
77
78 @V=($A,$B,$C,$D,$E)=map("%xmm$_",(0..4));
79 ($t0,$t1,$t2,$t3,$tx)=map("%xmm$_",(5..9));
80 @Xi=map("%xmm$_",(10..14));
81 $K="%xmm15";
82
83 $REG_SZ=16;
84
85 sub Xi_off {
86 my $off = shift;
87
88     $off %= 16; $off *= $REG_SZ;
89     $off<256 ? "$off-128(%rax)" : "$off-256-128(%rbx)";
90 }
91
92 sub BODY_00_19 {
93 my ($i,$a,$b,$c,$d,$e)=@_;
94 my $j=$i+1;
95 my $k=$i+2;
96
97 $code.=<<___ if ($i==0);
98         movd            (@ptr[0]),@Xi[0]
99          lea            `16*4`(@ptr[0]),@ptr[0]
100         movd            (@ptr[1]),@Xi[2]        # borrow @Xi[2]
101          lea            `16*4`(@ptr[1]),@ptr[1]
102         movd            (@ptr[2]),@Xi[3]        # borrow @Xi[3]
103          lea            `16*4`(@ptr[2]),@ptr[2]
104         movd            (@ptr[3]),@Xi[4]        # borrow @Xi[4]
105          lea            `16*4`(@ptr[3]),@ptr[3]
106         punpckldq       @Xi[3],@Xi[0]
107          movd           `4*$j-16*4`(@ptr[0]),@Xi[1]
108         punpckldq       @Xi[4],@Xi[2]
109          movd           `4*$j-16*4`(@ptr[1]),$t3
110         punpckldq       @Xi[2],@Xi[0]
111          movd           `4*$j-16*4`(@ptr[2]),$t2
112         pshufb          $tx,@Xi[0]
113 ___
114 $code.=<<___ if ($i<14);                        # just load input
115          movd           `4*$j-16*4`(@ptr[3]),$t1
116          punpckldq      $t2,@Xi[1]
117         movdqa  $a,$t2
118         paddd   $K,$e                           # e+=K_00_19
119          punpckldq      $t1,$t3
120         movdqa  $b,$t1
121         movdqa  $b,$t0
122         pslld   \$5,$t2
123         pandn   $d,$t1
124         pand    $c,$t0
125          punpckldq      $t3,@Xi[1]
126         movdqa  $a,$t3
127
128         movdqa  @Xi[0],`&Xi_off($i)`
129         paddd   @Xi[0],$e                       # e+=X[i]
130          movd           `4*$k-16*4`(@ptr[0]),@Xi[2]
131         psrld   \$27,$t3
132         pxor    $t1,$t0                         # Ch(b,c,d)
133         movdqa  $b,$t1
134
135         por     $t3,$t2                         # rol(a,5)
136          movd           `4*$k-16*4`(@ptr[1]),$t3
137         pslld   \$30,$t1
138         paddd   $t0,$e                          # e+=Ch(b,c,d)
139
140         psrld   \$2,$b
141         paddd   $t2,$e                          # e+=rol(a,5)
142          movd           `4*$j-16*4`(@ptr[2]),$t2
143          pshufb $tx,@Xi[1]
144         por     $t1,$b                          # b=rol(b,30)
145 ___
146 $code.=<<___ if ($i==14);                       # just load input
147          movd           `4*$j-16*4`(@ptr[3]),$t1
148          punpckldq      $t2,@Xi[1]
149         movdqa  $a,$t2
150         paddd   $K,$e                           # e+=K_00_19
151          punpckldq      $t1,$t3
152         movdqa  $b,$t1
153         movdqa  $b,$t0
154         pslld   \$5,$t2
155         pandn   $d,$t1
156         pand    $c,$t0
157          punpckldq      $t3,@Xi[1]
158         movdqa  $a,$t3
159
160         movdqa  @Xi[0],`&Xi_off($i)`
161         paddd   @Xi[0],$e                       # e+=X[i]
162         psrld   \$27,$t3
163         pxor    $t1,$t0                         # Ch(b,c,d)
164         movdqa  $b,$t1
165
166         por     $t3,$t2                         # rol(a,5)
167         pslld   \$30,$t1
168         paddd   $t0,$e                          # e+=Ch(b,c,d)
169
170         psrld   \$2,$b
171         paddd   $t2,$e                          # e+=rol(a,5)
172          pshufb $tx,@Xi[1]
173         por     $t1,$b                          # b=rol(b,30)
174 ___
175 $code.=<<___ if ($i>=13 && $i<15);
176         movdqa  `&Xi_off($j+2)`,@Xi[3]          # preload "X[2]"
177 ___
178 $code.=<<___ if ($i>=15);                       # apply Xupdate
179         pxor    @Xi[-2],@Xi[1]                  # "X[13]"
180         movdqa  `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
181
182         movdqa  $a,$t2
183          pxor   `&Xi_off($j+8)`,@Xi[1]
184         paddd   $K,$e                           # e+=K_00_19
185         movdqa  $b,$t1
186         pslld   \$5,$t2
187          pxor   @Xi[3],@Xi[1]
188         movdqa  $b,$t0
189         pandn   $d,$t1
190          movdqa @Xi[1],$tx
191         pand    $c,$t0
192         movdqa  $a,$t3
193          psrld  \$31,$tx
194          paddd  @Xi[1],@Xi[1]
195
196         movdqa  @Xi[0],`&Xi_off($i)`
197         paddd   @Xi[0],$e                       # e+=X[i]
198         psrld   \$27,$t3
199         pxor    $t1,$t0                         # Ch(b,c,d)
200
201         movdqa  $b,$t1
202         por     $t3,$t2                         # rol(a,5)
203         pslld   \$30,$t1
204         paddd   $t0,$e                          # e+=Ch(b,c,d)
205
206         psrld   \$2,$b
207         paddd   $t2,$e                          # e+=rol(a,5)
208          por    $tx,@Xi[1]                      # rol   \$1,@Xi[1]
209         por     $t1,$b                          # b=rol(b,30)
210 ___
211 push(@Xi,shift(@Xi));
212 }
213
214 sub BODY_20_39 {
215 my ($i,$a,$b,$c,$d,$e)=@_;
216 my $j=$i+1;
217
218 $code.=<<___ if ($i<79);
219         pxor    @Xi[-2],@Xi[1]                  # "X[13]"
220         movdqa  `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
221
222         movdqa  $a,$t2
223         movdqa  $d,$t0
224          pxor   `&Xi_off($j+8)`,@Xi[1]
225         paddd   $K,$e                           # e+=K_20_39
226         pslld   \$5,$t2
227         pxor    $b,$t0
228
229         movdqa  $a,$t3
230 ___
231 $code.=<<___ if ($i<72);
232         movdqa  @Xi[0],`&Xi_off($i)`
233 ___
234 $code.=<<___ if ($i<79);
235         paddd   @Xi[0],$e                       # e+=X[i]
236          pxor   @Xi[3],@Xi[1]
237         psrld   \$27,$t3
238         pxor    $c,$t0                          # Parity(b,c,d)
239         movdqa  $b,$t1
240
241         pslld   \$30,$t1
242          movdqa @Xi[1],$tx
243         por     $t3,$t2                         # rol(a,5)
244          psrld  \$31,$tx
245         paddd   $t0,$e                          # e+=Parity(b,c,d)
246          paddd  @Xi[1],@Xi[1]
247
248         psrld   \$2,$b
249         paddd   $t2,$e                          # e+=rol(a,5)
250          por    $tx,@Xi[1]                      # rol(@Xi[1],1)
251         por     $t1,$b                          # b=rol(b,30)
252 ___
253 $code.=<<___ if ($i==79);
254         movdqa  $a,$t2
255         paddd   $K,$e                           # e+=K_20_39
256         movdqa  $d,$t0
257         pslld   \$5,$t2
258         pxor    $b,$t0
259
260         movdqa  $a,$t3
261         paddd   @Xi[0],$e                       # e+=X[i]
262         psrld   \$27,$t3
263         movdqa  $b,$t1
264         pxor    $c,$t0                          # Parity(b,c,d)
265
266         pslld   \$30,$t1
267         por     $t3,$t2                         # rol(a,5)
268         paddd   $t0,$e                          # e+=Parity(b,c,d)
269
270         psrld   \$2,$b
271         paddd   $t2,$e                          # e+=rol(a,5)
272         por     $t1,$b                          # b=rol(b,30)
273 ___
274 push(@Xi,shift(@Xi));
275 }
276
277 sub BODY_40_59 {
278 my ($i,$a,$b,$c,$d,$e)=@_;
279 my $j=$i+1;
280
281 $code.=<<___;
282         pxor    @Xi[-2],@Xi[1]                  # "X[13]"
283         movdqa  `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
284
285         movdqa  $a,$t2
286         movdqa  $d,$t1
287          pxor   `&Xi_off($j+8)`,@Xi[1]
288         pxor    @Xi[3],@Xi[1]
289         paddd   $K,$e                           # e+=K_40_59
290         pslld   \$5,$t2
291         movdqa  $a,$t3
292         pand    $c,$t1
293
294         movdqa  $d,$t0
295          movdqa @Xi[1],$tx
296         psrld   \$27,$t3
297         paddd   $t1,$e
298         pxor    $c,$t0
299
300         movdqa  @Xi[0],`&Xi_off($i)`
301         paddd   @Xi[0],$e                       # e+=X[i]
302         por     $t3,$t2                         # rol(a,5)
303          psrld  \$31,$tx
304         pand    $b,$t0
305         movdqa  $b,$t1
306
307         pslld   \$30,$t1
308          paddd  @Xi[1],@Xi[1]
309         paddd   $t0,$e                          # e+=Maj(b,d,c)
310
311         psrld   \$2,$b
312         paddd   $t2,$e                          # e+=rol(a,5)
313          por    $tx,@Xi[1]                      # rol(@X[1],1)
314         por     $t1,$b                          # b=rol(b,30)
315 ___
316 push(@Xi,shift(@Xi));
317 }
318
319 $code.=<<___;
320 .text
321
322 .extern OPENSSL_ia32cap_P
323
324 .globl  sha1_multi_block
325 .type   sha1_multi_block,\@function,3
326 .align  32
327 sha1_multi_block:
328 ___
329 $code.=<<___ if ($avx);
330         mov     OPENSSL_ia32cap_P+4(%rip),%rcx
331         test    \$`1<<28`,%ecx
332         jnz     _avx_shortcut
333 ___
334 $code.=<<___;
335         mov     %rsp,%rax
336         push    %rbx
337         push    %rbp
338 ___
339 $code.=<<___ if ($win64);
340         lea     -0xa8(%rsp),%rsp
341         movaps  %xmm6,(%rsp)
342         movaps  %xmm7,0x10(%rsp)
343         movaps  %xmm8,0x20(%rsp)
344         movaps  %xmm9,0x30(%rsp)
345         movaps  %xmm10,-0x78(%rax)
346         movaps  %xmm11,-0x68(%rax)
347         movaps  %xmm12,-0x58(%rax)
348         movaps  %xmm13,-0x48(%rax)
349         movaps  %xmm14,-0x38(%rax)
350         movaps  %xmm15,-0x28(%rax)
351 ___
352 $code.=<<___;
353         sub     \$`$REG_SZ*18`,%rsp
354         and     \$-256,%rsp
355         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
356         lea     K_XX_XX(%rip),$Tbl
357         lea     `$REG_SZ*16`(%rsp),%rbx
358
359 .Loop_grande:
360         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
361         xor     $num,$num
362 ___
363 for($i=0;$i<4;$i++) {
364     $code.=<<___;
365         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
366         mov     `16*$i+8`($inp),%ecx            # number of blocks
367         cmp     $num,%ecx
368         cmovg   %ecx,$num                       # find maximum
369         test    %ecx,%ecx
370         mov     %ecx,`4*$i`(%rbx)               # initialize counters
371         cmovle  $Tbl,@ptr[$i]                   # cancel input
372 ___
373 }
374 $code.=<<___;
375         test    $num,$num
376         jz      .Ldone
377
378         movdqu  0x00($ctx),$A                   # load context
379          lea    128(%rsp),%rax
380         movdqu  0x20($ctx),$B
381         movdqu  0x40($ctx),$C
382         movdqu  0x60($ctx),$D
383         movdqu  0x80($ctx),$E
384         movdqa  0x60($Tbl),$tx                  # pbswap_mask
385         jmp     .Loop
386
387 .align  32
388 .Loop:
389 ___
390 $code.="        movdqa  -0x20($Tbl),$K\n";      # K_00_19
391 for($i=0;$i<20;$i++)    { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
392 $code.="        movdqa  0x00($Tbl),$K\n";       # K_20_39
393 for(;$i<40;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
394 $code.="        movdqa  0x20($Tbl),$K\n";       # K_40_59
395 for(;$i<60;$i++)        { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
396 $code.="        movdqa  0x40($Tbl),$K\n";       # K_60_79
397 for(;$i<80;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
398 $code.=<<___;
399         movdqa  (%rbx),@Xi[0]                   # pull counters
400         mov     \$1,%ecx
401         cmp     4*0(%rbx),%ecx                  # examinte counters
402         pxor    $t2,$t2
403         cmovge  $Tbl,@ptr[0]                    # cancel input
404         cmp     4*1(%rbx),%ecx
405         movdqa  @Xi[0],@Xi[1]
406         cmovge  $Tbl,@ptr[1]
407         cmp     4*2(%rbx),%ecx
408         pcmpgtd $t2,@Xi[1]                      # mask value
409         cmovge  $Tbl,@ptr[2]
410         cmp     4*3(%rbx),%ecx
411         paddd   @Xi[1],@Xi[0]                   # counters--
412         cmovge  $Tbl,@ptr[3]
413
414         movdqu  0x00($ctx),$t0
415         pand    @Xi[1],$A
416         movdqu  0x20($ctx),$t1
417         pand    @Xi[1],$B
418         paddd   $t0,$A
419         movdqu  0x40($ctx),$t2
420         pand    @Xi[1],$C
421         paddd   $t1,$B
422         movdqu  0x60($ctx),$t3
423         pand    @Xi[1],$D
424         paddd   $t2,$C
425         movdqu  0x80($ctx),$tx
426         pand    @Xi[1],$E
427         movdqu  $A,0x00($ctx)
428         paddd   $t3,$D
429         movdqu  $B,0x20($ctx)
430         paddd   $tx,$E
431         movdqu  $C,0x40($ctx)
432         movdqu  $D,0x60($ctx)
433         movdqu  $E,0x80($ctx)
434
435         movdqa  @Xi[0],(%rbx)                   # save counters
436         movdqa  0x60($Tbl),$tx                  # pbswap_mask
437         dec     $num
438         jnz     .Loop
439
440         mov     `$REG_SZ*17+8`(%rsp),$num
441         lea     $REG_SZ($ctx),$ctx
442         lea     `16*$REG_SZ/4`($inp),$inp
443         dec     $num
444         jnz     .Loop_grande
445
446 .Ldone:
447         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
448 ___
449 $code.=<<___ if ($win64);
450         movaps  -0xb8(%rax),%xmm6
451         movaps  -0xa8(%rax),%xmm7
452         movaps  -0x98(%rax),%xmm8
453         movaps  -0x88(%rax),%xmm9
454         movaps  -0x78(%rax),%xmm10
455         movaps  -0x68(%rax),%xmm11
456         movaps  -0x58(%rax),%xmm12
457         movaps  -0x48(%rax),%xmm13
458         movaps  -0x38(%rax),%xmm14
459         movaps  -0x28(%rax),%xmm15
460 ___
461 $code.=<<___;
462         mov     -16(%rax),%rbp
463         mov     -8(%rax),%rbx
464         lea     (%rax),%rsp
465         ret
466 .size   sha1_multi_block,.-sha1_multi_block
467 ___
468
469                                                 if ($avx) {{{
470 sub BODY_00_19_avx {
471 my ($i,$a,$b,$c,$d,$e)=@_;
472 my $j=$i+1;
473 my $k=$i+2;
474 my $vpack = $REG_SZ==16 ? "vpunpckldq" : "vinserti128";
475 my $ptr_n = $REG_SZ==16 ? @ptr[1] : @ptr[4];
476
477 $code.=<<___ if ($i==0 && $REG_SZ==16);
478         vmovd           (@ptr[0]),@Xi[0]
479          lea            `16*4`(@ptr[0]),@ptr[0]
480         vmovd           (@ptr[1]),@Xi[2]        # borrow Xi[2]
481          lea            `16*4`(@ptr[1]),@ptr[1]
482         vpinsrd         \$1,(@ptr[2]),@Xi[0],@Xi[0]
483          lea            `16*4`(@ptr[2]),@ptr[2]
484         vpinsrd         \$1,(@ptr[3]),@Xi[2],@Xi[2]
485          lea            `16*4`(@ptr[3]),@ptr[3]
486          vmovd          `4*$j-16*4`(@ptr[0]),@Xi[1]
487         vpunpckldq      @Xi[2],@Xi[0],@Xi[0]
488          vmovd          `4*$j-16*4`($ptr_n),$t3
489         vpshufb         $tx,@Xi[0],@Xi[0]
490 ___
491 $code.=<<___ if ($i<15 && $REG_SZ==16);         # just load input
492          vpinsrd        \$1,`4*$j-16*4`(@ptr[2]),@Xi[1],@Xi[1]
493          vpinsrd        \$1,`4*$j-16*4`(@ptr[3]),$t3,$t3
494 ___
495 $code.=<<___ if ($i==0 && $REG_SZ==32);
496         vmovd           (@ptr[0]),@Xi[0]
497          lea            `16*4`(@ptr[0]),@ptr[0]
498         vmovd           (@ptr[4]),@Xi[2]        # borrow Xi[2]
499          lea            `16*4`(@ptr[4]),@ptr[4]
500         vmovd           (@ptr[1]),$t2
501          lea            `16*4`(@ptr[1]),@ptr[1]
502         vmovd           (@ptr[5]),$t1
503          lea            `16*4`(@ptr[5]),@ptr[5]
504         vpinsrd         \$1,(@ptr[2]),@Xi[0],@Xi[0]
505          lea            `16*4`(@ptr[2]),@ptr[2]
506         vpinsrd         \$1,(@ptr[6]),@Xi[2],@Xi[2]
507          lea            `16*4`(@ptr[6]),@ptr[6]
508         vpinsrd         \$1,(@ptr[3]),$t2,$t2
509          lea            `16*4`(@ptr[3]),@ptr[3]
510         vpunpckldq      $t2,@Xi[0],@Xi[0]
511         vpinsrd         \$1,(@ptr[7]),$t1,$t1
512          lea            `16*4`(@ptr[7]),@ptr[7]
513         vpunpckldq      $t1,@Xi[2],@Xi[2]
514          vmovd          `4*$j-16*4`(@ptr[0]),@Xi[1]
515         vinserti128     @Xi[2],@Xi[0],@Xi[0]
516          vmovd          `4*$j-16*4`($ptr_n),$t3
517         vpshufb         $tx,@Xi[0],@Xi[0]
518 ___
519 $code.=<<___ if ($i<15 && $REG_SZ==32);         # just load input
520          vmovd          `4*$j-16*4`(@ptr[1]),$t2
521          vmovd          `4*$j-16*4`(@ptr[5]),$t1
522          vpinsrd        \$1,`4*$j-16*4`(@ptr[2]),@Xi[1],@Xi[1]
523          vpinsrd        \$1,`4*$j-16*4`(@ptr[6]),$t3,$t3
524          vpinsrd        \$1,`4*$j-16*4`(@ptr[3]),$t2,$t2
525          vpunpckldq     $t2,@Xi[1],@Xi[1]
526          vpinsrd        \$1,`4*$j-16*4`(@ptr[7]),$t1,$t1
527          vpunpckldq     $t1,$t3,$t3
528 ___
529 $code.=<<___ if ($i<14);
530         vpaddd  $K,$e,$e                        # e+=K_00_19
531         vpslld  \$5,$a,$t2
532         vpandn  $d,$b,$t1
533         vpand   $c,$b,$t0
534
535         vmovdqa @Xi[0],`&Xi_off($i)`
536         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
537          $vpack         $t3,@Xi[1],@Xi[1]
538         vpsrld  \$27,$a,$t3
539         vpxor   $t1,$t0,$t0                     # Ch(b,c,d)
540          vmovd          `4*$k-16*4`(@ptr[0]),@Xi[2]
541
542         vpslld  \$30,$b,$t1
543         vpor    $t3,$t2,$t2                     # rol(a,5)
544          vmovd          `4*$k-16*4`($ptr_n),$t3
545         vpaddd  $t0,$e,$e                       # e+=Ch(b,c,d)
546
547         vpsrld  \$2,$b,$b
548         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
549          vpshufb        $tx,@Xi[1],@Xi[1]
550         vpor    $t1,$b,$b                       # b=rol(b,30)
551 ___
552 $code.=<<___ if ($i==14);
553         vpaddd  $K,$e,$e                        # e+=K_00_19
554         vpslld  \$5,$a,$t2
555         vpandn  $d,$b,$t1
556         vpand   $c,$b,$t0
557
558         vmovdqa @Xi[0],`&Xi_off($i)`
559         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
560          $vpack         $t3,@Xi[1],@Xi[1]
561         vpsrld  \$27,$a,$t3
562         vpxor   $t1,$t0,$t0                     # Ch(b,c,d)
563
564         vpslld  \$30,$b,$t1
565         vpor    $t3,$t2,$t2                     # rol(a,5)
566         vpaddd  $t0,$e,$e                       # e+=Ch(b,c,d)
567
568         vpsrld  \$2,$b,$b
569         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
570          vpshufb        $tx,@Xi[1],@Xi[1]
571         vpor    $t1,$b,$b                       # b=rol(b,30)
572 ___
573 $code.=<<___ if ($i>=13 && $i<15);
574         vmovdqa `&Xi_off($j+2)`,@Xi[3]          # preload "X[2]"
575 ___
576 $code.=<<___ if ($i>=15);                       # apply Xupdate
577         vpxor   @Xi[-2],@Xi[1],@Xi[1]           # "X[13]"
578         vmovdqa `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
579
580         vpaddd  $K,$e,$e                        # e+=K_00_19
581         vpslld  \$5,$a,$t2
582         vpandn  $d,$b,$t1
583         vpand   $c,$b,$t0
584
585         vmovdqa @Xi[0],`&Xi_off($i)`
586         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
587          vpxor  `&Xi_off($j+8)`,@Xi[1],@Xi[1]
588         vpsrld  \$27,$a,$t3
589         vpxor   $t1,$t0,$t0                     # Ch(b,c,d)
590          vpxor  @Xi[3],@Xi[1],@Xi[1]
591
592         vpslld  \$30,$b,$t1
593         vpor    $t3,$t2,$t2                     # rol(a,5)
594         vpaddd  $t0,$e,$e                       # e+=Ch(b,c,d)
595          vpsrld \$31,@Xi[1],$tx
596          vpaddd @Xi[1],@Xi[1],@Xi[1]
597
598         vpsrld  \$2,$b,$b
599         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
600          vpor   $tx,@Xi[1],@Xi[1]               # rol   \$1,@Xi[1]
601         vpor    $t1,$b,$b                       # b=rol(b,30)
602 ___
603 push(@Xi,shift(@Xi));
604 }
605
606 sub BODY_20_39_avx {
607 my ($i,$a,$b,$c,$d,$e)=@_;
608 my $j=$i+1;
609
610 $code.=<<___ if ($i<79);
611         vpxor   @Xi[-2],@Xi[1],@Xi[1]           # "X[13]"
612         vmovdqa `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
613
614         vpslld  \$5,$a,$t2
615         vpaddd  $K,$e,$e                        # e+=K_20_39
616         vpxor   $b,$d,$t0
617 ___
618 $code.=<<___ if ($i<72);
619         vmovdqa @Xi[0],`&Xi_off($i)`
620 ___
621 $code.=<<___ if ($i<79);
622         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
623          vpxor  `&Xi_off($j+8)`,@Xi[1],@Xi[1]
624         vpsrld  \$27,$a,$t3
625         vpxor   $c,$t0,$t0                      # Parity(b,c,d)
626          vpxor  @Xi[3],@Xi[1],@Xi[1]
627
628         vpslld  \$30,$b,$t1
629         vpor    $t3,$t2,$t2                     # rol(a,5)
630         vpaddd  $t0,$e,$e                       # e+=Parity(b,c,d)
631          vpsrld \$31,@Xi[1],$tx
632          vpaddd @Xi[1],@Xi[1],@Xi[1]
633
634         vpsrld  \$2,$b,$b
635         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
636          vpor   $tx,@Xi[1],@Xi[1]               # rol(@Xi[1],1)
637         vpor    $t1,$b,$b                       # b=rol(b,30)
638 ___
639 $code.=<<___ if ($i==79);
640         vpslld  \$5,$a,$t2
641         vpaddd  $K,$e,$e                        # e+=K_20_39
642         vpxor   $b,$d,$t0
643
644         vpsrld  \$27,$a,$t3
645         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
646         vpxor   $c,$t0,$t0                      # Parity(b,c,d)
647
648         vpslld  \$30,$b,$t1
649         vpor    $t3,$t2,$t2                     # rol(a,5)
650         vpaddd  $t0,$e,$e                       # e+=Parity(b,c,d)
651
652         vpsrld  \$2,$b,$b
653         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
654         vpor    $t1,$b,$b                       # b=rol(b,30)
655 ___
656 push(@Xi,shift(@Xi));
657 }
658
659 sub BODY_40_59_avx {
660 my ($i,$a,$b,$c,$d,$e)=@_;
661 my $j=$i+1;
662
663 $code.=<<___;
664         vpxor   @Xi[-2],@Xi[1],@Xi[1]           # "X[13]"
665         vmovdqa `&Xi_off($j+2)`,@Xi[3]          # "X[2]"
666
667         vpaddd  $K,$e,$e                        # e+=K_40_59
668         vpslld  \$5,$a,$t2
669         vpand   $c,$d,$t1
670          vpxor  `&Xi_off($j+8)`,@Xi[1],@Xi[1]
671
672         vpaddd  $t1,$e,$e
673         vpsrld  \$27,$a,$t3
674         vpxor   $c,$d,$t0
675          vpxor  @Xi[3],@Xi[1],@Xi[1]
676
677         vmovdqu @Xi[0],`&Xi_off($i)`
678         vpaddd  @Xi[0],$e,$e                    # e+=X[i]
679         vpor    $t3,$t2,$t2                     # rol(a,5)
680          vpsrld \$31,@Xi[1],$tx
681         vpand   $b,$t0,$t0
682          vpaddd @Xi[1],@Xi[1],@Xi[1]
683
684         vpslld  \$30,$b,$t1
685         vpaddd  $t0,$e,$e                       # e+=Maj(b,d,c)
686
687         vpsrld  \$2,$b,$b
688         vpaddd  $t2,$e,$e                       # e+=rol(a,5)
689          vpor   $tx,@Xi[1],@Xi[1]               # rol(@X[1],1)
690         vpor    $t1,$b,$b                       # b=rol(b,30)
691 ___
692 push(@Xi,shift(@Xi));
693 }
694
695 $code.=<<___;
696 .type   sha1_multi_block_avx,\@function,3
697 .align  32
698 sha1_multi_block_avx:
699 _avx_shortcut:
700 ___
701 $code.=<<___ if ($avx>1);
702         shr     \$32,%rcx
703         cmp     \$2,$num
704         jb      .Lavx
705         test    \$`1<<5`,%ecx
706         jnz     _avx2_shortcut
707         jmp     .Lavx
708 .align  32
709 .Lavx:
710 ___
711 $code.=<<___;
712         mov     %rsp,%rax
713         push    %rbx
714         push    %rbp
715 ___
716 $code.=<<___ if ($win64);
717         lea     -0xa8(%rsp),%rsp
718         movaps  %xmm6,(%rsp)
719         movaps  %xmm7,0x10(%rsp)
720         movaps  %xmm8,0x20(%rsp)
721         movaps  %xmm9,0x30(%rsp)
722         movaps  %xmm10,-0x78(%rax)
723         movaps  %xmm11,-0x68(%rax)
724         movaps  %xmm12,-0x58(%rax)
725         movaps  %xmm13,-0x48(%rax)
726         movaps  %xmm14,-0x38(%rax)
727         movaps  %xmm15,-0x28(%rax)
728 ___
729 $code.=<<___;
730         sub     \$`$REG_SZ*18`, %rsp
731         and     \$-256,%rsp
732         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
733         lea     K_XX_XX(%rip),$Tbl
734         lea     `$REG_SZ*16`(%rsp),%rbx
735
736         vzeroupper
737 .Loop_grande_avx:
738         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
739         xor     $num,$num
740 ___
741 for($i=0;$i<4;$i++) {
742     $code.=<<___;
743         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
744         mov     `16*$i+8`($inp),%ecx            # number of blocks
745         cmp     $num,%ecx
746         cmovg   %ecx,$num                       # find maximum
747         test    %ecx,%ecx
748         mov     %ecx,`4*$i`(%rbx)               # initialize counters
749         cmovle  $Tbl,@ptr[$i]                   # cancel input
750 ___
751 }
752 $code.=<<___;
753         test    $num,$num
754         jz      .Ldone_avx
755
756         vmovdqu 0x00($ctx),$A                   # load context
757          lea    128(%rsp),%rax
758         vmovdqu 0x20($ctx),$B
759         vmovdqu 0x40($ctx),$C
760         vmovdqu 0x60($ctx),$D
761         vmovdqu 0x80($ctx),$E
762         vmovdqu 0x60($Tbl),$tx                  # pbswap_mask
763         jmp     .Loop_avx
764
765 .align  32
766 .Loop_avx:
767 ___
768 $code.="        vmovdqa -0x20($Tbl),$K\n";      # K_00_19
769 for($i=0;$i<20;$i++)    { &BODY_00_19_avx($i,@V); unshift(@V,pop(@V)); }
770 $code.="        vmovdqa 0x00($Tbl),$K\n";       # K_20_39
771 for(;$i<40;$i++)        { &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
772 $code.="        vmovdqa 0x20($Tbl),$K\n";       # K_40_59
773 for(;$i<60;$i++)        { &BODY_40_59_avx($i,@V); unshift(@V,pop(@V)); }
774 $code.="        vmovdqa 0x40($Tbl),$K\n";       # K_60_79
775 for(;$i<80;$i++)        { &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
776 $code.=<<___;
777         mov     \$1,%ecx
778 ___
779 for($i=0;$i<4;$i++) {
780     $code.=<<___;
781         cmp     `4*$i`(%rbx),%ecx               # examine counters
782         cmovge  $Tbl,@ptr[$i]                   # cancel input
783 ___
784 }
785 $code.=<<___;
786         vmovdqu (%rbx),$t0                      # pull counters
787         vpxor   $t2,$t2,$t2
788         vmovdqa $t0,$t1
789         vpcmpgtd $t2,$t1,$t1                    # mask value
790         vpaddd  $t1,$t0,$t0                     # counters--
791
792         vpand   $t1,$A,$A
793         vpand   $t1,$B,$B
794         vpaddd  0x00($ctx),$A,$A
795         vpand   $t1,$C,$C
796         vpaddd  0x20($ctx),$B,$B
797         vpand   $t1,$D,$D
798         vpaddd  0x40($ctx),$C,$C
799         vpand   $t1,$E,$E
800         vpaddd  0x60($ctx),$D,$D
801         vpaddd  0x80($ctx),$E,$E
802         vmovdqu $A,0x00($ctx)
803         vmovdqu $B,0x20($ctx)
804         vmovdqu $C,0x40($ctx)
805         vmovdqu $D,0x60($ctx)
806         vmovdqu $E,0x80($ctx)
807
808         vmovdqu $t0,(%rbx)                      # save counters
809         vmovdqu 0x60($Tbl),$tx                  # pbswap_mask
810         dec     $num
811         jnz     .Loop_avx
812
813         mov     `$REG_SZ*17+8`(%rsp),$num
814         lea     $REG_SZ($ctx),$ctx
815         lea     `16*$REG_SZ/4`($inp),$inp
816         dec     $num
817         jnz     .Loop_grande_avx
818
819 .Ldone_avx:
820         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
821         vzeroupper
822 ___
823 $code.=<<___ if ($win64);
824         movaps  -0xb8(%rax),%xmm6
825         movaps  -0xa8(%rax),%xmm7
826         movaps  -0x98(%rax),%xmm8
827         movaps  -0x88(%rax),%xmm9
828         movaps  -0x78(%rax),%xmm10
829         movaps  -0x68(%rax),%xmm11
830         movaps  -0x58(%rax),%xmm12
831         movaps  -0x48(%rax),%xmm13
832         movaps  -0x38(%rax),%xmm14
833         movaps  -0x28(%rax),%xmm15
834 ___
835 $code.=<<___;
836         mov     -16(%rax),%rbp
837         mov     -8(%rax),%rbx
838         lea     (%rax),%rsp
839         ret
840 .size   sha1_multi_block_avx,.-sha1_multi_block_avx
841 ___
842
843                                                 if ($avx>1) {
844 $code =~ s/\`([^\`]*)\`/eval $1/gem;
845
846 $REG_SZ=32;
847
848 @ptr=map("%r$_",(12..15,8..11));
849
850 @V=($A,$B,$C,$D,$E)=map("%ymm$_",(0..4));
851 ($t0,$t1,$t2,$t3,$tx)=map("%ymm$_",(5..9));
852 @Xi=map("%ymm$_",(10..14));
853 $K="%ymm15";
854
855 $code.=<<___;
856 .type   sha1_multi_block_avx2,\@function,3
857 .align  32
858 sha1_multi_block_avx2:
859 _avx2_shortcut:
860         mov     %rsp,%rax
861         push    %rbx
862         push    %rbp
863         push    %r12
864         push    %r13
865         push    %r14
866         push    %r15
867 ___
868 $code.=<<___ if ($win64);
869         lea     -0xa8(%rsp),%rsp
870         movaps  %xmm6,(%rsp)
871         movaps  %xmm7,0x10(%rsp)
872         movaps  %xmm8,0x20(%rsp)
873         movaps  %xmm9,0x30(%rsp)
874         movaps  %xmm10,0x40(%rsp)
875         movaps  %xmm11,0x50(%rsp)
876         movaps  %xmm12,-0x78(%rax)
877         movaps  %xmm13,-0x68(%rax)
878         movaps  %xmm14,-0x58(%rax)
879         movaps  %xmm15,-0x48(%rax)
880 ___
881 $code.=<<___;
882         sub     \$`$REG_SZ*18`, %rsp
883         and     \$-256,%rsp
884         mov     %rax,`$REG_SZ*17`(%rsp)         # original %rsp
885         lea     K_XX_XX(%rip),$Tbl
886         shr     \$1,$num
887
888         vzeroupper
889 .Loop_grande_avx2:
890         mov     $num,`$REG_SZ*17+8`(%rsp)       # original $num
891         xor     $num,$num
892         lea     `$REG_SZ*16`(%rsp),%rbx
893 ___
894 for($i=0;$i<8;$i++) {
895     $code.=<<___;
896         mov     `16*$i+0`($inp),@ptr[$i]        # input pointer
897         mov     `16*$i+8`($inp),%ecx            # number of blocks
898         cmp     $num,%ecx
899         cmovg   %ecx,$num                       # find maximum
900         test    %ecx,%ecx
901         mov     %ecx,`4*$i`(%rbx)               # initialize counters
902         cmovle  $Tbl,@ptr[$i]                   # cancel input
903 ___
904 }
905 $code.=<<___;
906         vmovdqu 0x00($ctx),$A                   # load context
907          lea    128(%rsp),%rax
908         vmovdqu 0x20($ctx),$B
909          lea    256+128(%rsp),%rbx
910         vmovdqu 0x40($ctx),$C
911         vmovdqu 0x60($ctx),$D
912         vmovdqu 0x80($ctx),$E
913         vmovdqu 0x60($Tbl),$tx                  # pbswap_mask
914         jmp     .Loop_avx2
915
916 .align  32
917 .Loop_avx2:
918 ___
919 $code.="        vmovdqa -0x20($Tbl),$K\n";      # K_00_19
920 for($i=0;$i<20;$i++)    { &BODY_00_19_avx($i,@V); unshift(@V,pop(@V)); }
921 $code.="        vmovdqa 0x00($Tbl),$K\n";       # K_20_39
922 for(;$i<40;$i++)        { &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
923 $code.="        vmovdqa 0x20($Tbl),$K\n";       # K_40_59
924 for(;$i<60;$i++)        { &BODY_40_59_avx($i,@V); unshift(@V,pop(@V)); }
925 $code.="        vmovdqa 0x40($Tbl),$K\n";       # K_60_79
926 for(;$i<80;$i++)        { &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
927 $code.=<<___;
928         mov     \$1,%ecx
929         lea     `$REG_SZ*16`(%rsp),%rbx
930 ___
931 for($i=0;$i<8;$i++) {
932     $code.=<<___;
933         cmp     `4*$i`(%rbx),%ecx               # examine counters
934         cmovge  $Tbl,@ptr[$i]                   # cancel input
935 ___
936 }
937 $code.=<<___;
938         vmovdqu (%rbx),$t0              # pull counters
939         vpxor   $t2,$t2,$t2
940         vmovdqa $t0,$t1
941         vpcmpgtd $t2,$t1,$t1                    # mask value
942         vpaddd  $t1,$t0,$t0                     # counters--
943
944         vpand   $t1,$A,$A
945         vpand   $t1,$B,$B
946         vpaddd  0x00($ctx),$A,$A
947         vpand   $t1,$C,$C
948         vpaddd  0x20($ctx),$B,$B
949         vpand   $t1,$D,$D
950         vpaddd  0x40($ctx),$C,$C
951         vpand   $t1,$E,$E
952         vpaddd  0x60($ctx),$D,$D
953         vpaddd  0x80($ctx),$E,$E
954         vmovdqu $A,0x00($ctx)
955         vmovdqu $B,0x20($ctx)
956         vmovdqu $C,0x40($ctx)
957         vmovdqu $D,0x60($ctx)
958         vmovdqu $E,0x80($ctx)
959
960         vmovdqu $t0,(%rbx)                      # save counters
961         lea     256+128(%rsp),%rbx
962         vmovdqu 0x60($Tbl),$tx                  # pbswap_mask
963         dec     $num
964         jnz     .Loop_avx2
965
966         #mov    `$REG_SZ*17+8`(%rsp),$num
967         #lea    $REG_SZ($ctx),$ctx
968         #lea    `16*$REG_SZ/4`($inp),$inp
969         #dec    $num
970         #jnz    .Loop_grande_avx2
971
972 .Ldone_avx2:
973         mov     `$REG_SZ*17`(%rsp),%rax         # orignal %rsp
974         vzeroupper
975 ___
976 $code.=<<___ if ($win64);
977         movaps  -0xd8(%rax),%xmm6
978         movaps  -0xc8(%rax),%xmm7
979         movaps  -0xb8(%rax),%xmm8
980         movaps  -0xa8(%rax),%xmm9
981         movaps  -0x98(%rax),%xmm10
982         movaps  -0x88(%rax),%xmm11
983         movaps  -0x78(%rax),%xmm12
984         movaps  -0x68(%rax),%xmm13
985         movaps  -0x58(%rax),%xmm14
986         movaps  -0x48(%rax),%xmm15
987 ___
988 $code.=<<___;
989         mov     -48(%rax),%r15
990         mov     -40(%rax),%r14
991         mov     -32(%rax),%r13
992         mov     -24(%rax),%r12
993         mov     -16(%rax),%rbp
994         mov     -8(%rax),%rbx
995         lea     (%rax),%rsp
996         ret
997 .size   sha1_multi_block_avx2,.-sha1_multi_block_avx2
998 ___
999                                                 }       }}}
1000 $code.=<<___;
1001
1002 .align  256
1003         .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1004         .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1005 K_XX_XX:
1006         .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1007         .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1008         .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1009         .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1010         .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1011         .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1012         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap
1013         .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap
1014 ___
1015
1016 foreach (split("\n",$code)) {
1017         s/\`([^\`]*)\`/eval($1)/ge;
1018
1019         s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go          or
1020         s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go         or
1021         s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+),%ymm([0-9]+)/$1$2%xmm$3,%xmm$4/go    or
1022         s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go        or
1023         s/\b(vinserti128)\b(\s+)%ymm/$1$2\$1,%xmm/go            or
1024         s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
1025         print $_,"\n";
1026 }
1027
1028 close STDOUT;