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