d7b67b8593750e4e9f9e3a5172aa197637d97fc4
[openssl.git] / crypto / poly1305 / asm / poly1305-sparcv9.pl
1 #! /usr/bin/env perl
2 # Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 #
10 # ====================================================================
11 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
12 # project. The module is, however, dual licensed under OpenSSL and
13 # CRYPTOGAMS licenses depending on where you obtain it. For further
14 # details see http://www.openssl.org/~appro/cryptogams/.
15 # ====================================================================
16 #
17 # This module implements Poly1305 hash for SPARCv9, vanilla, as well
18 # as VIS3 and FMA extensions.
19 #
20 # May, August 2015
21 #
22 # Numbers are cycles per processed byte with poly1305_blocks alone.
23 #
24 #                       IALU(*)         FMA
25 #
26 # UltraSPARC III        12.3(**)
27 # SPARC T3              7.92
28 # SPARC T4              1.70(***)       6.55
29 # SPARC64 X             5.60            3.64
30 #
31 # (*)   Comparison to compiler-generated code is really problematic,
32 #       because latter's performance varies too much depending on too
33 #       many variables. For example, one can measure from 5x to 15x
34 #       improvement on T4 for gcc-4.6. Well, in T4 case it's a bit
35 #       unfair comparison, because compiler doesn't use VIS3, but
36 #       given same initial conditions coefficient varies from 3x to 9x.
37 # (**)  Pre-III performance should be even worse; floating-point
38 #       performance for UltraSPARC I-IV on the other hand is reported
39 #       to be 4.25 for hand-coded assembly, but they are just too old
40 #       to care about.
41 # (***) Multi-process benchmark saturates at ~12.5x single-process
42 #       result on 8-core processor, or ~21GBps per 2.85GHz socket.
43
44 # $output is the last argument if it looks like a file (it has an extension)
45 my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
46
47 open STDOUT,">$output" if $output;
48
49 my ($ctx,$inp,$len,$padbit,$shl,$shr)   = map("%i$_",(0..5));
50 my ($r0,$r1,$r2,$r3,$s1,$s2,$s3,$h4)    = map("%l$_",(0..7));
51 my ($h0,$h1,$h2,$h3, $t0,$t1,$t2)       = map("%o$_",(0..5,7));
52 my ($d0,$d1,$d2,$d3)                    = map("%g$_",(1..4));
53
54 $code.=<<___;
55 #include "sparc_arch.h"
56
57 #ifdef  __arch64__
58 .register       %g2,#scratch
59 .register       %g3,#scratch
60 # define        STPTR   stx
61 # define        SIZE_T  8
62 #else
63 # define        STPTR   st
64 # define        SIZE_T  4
65 #endif
66 #define LOCALS  (STACK_BIAS+STACK_FRAME)
67
68 .section        ".text",#alloc,#execinstr
69
70 #ifdef __PIC__
71 SPARC_PIC_THUNK(%g1)
72 #endif
73
74 .globl  poly1305_init
75 .align  32
76 poly1305_init:
77         save    %sp,-STACK_FRAME-16,%sp
78         nop
79
80         SPARC_LOAD_ADDRESS(OPENSSL_sparcv9cap_P,%g1)
81         ld      [%g1],%g1
82
83         and     %g1,SPARCV9_FMADD|SPARCV9_VIS3,%g1
84         cmp     %g1,SPARCV9_FMADD
85         be      .Lpoly1305_init_fma
86         nop
87
88         stx     %g0,[$ctx+0]
89         stx     %g0,[$ctx+8]            ! zero hash value
90         brz,pn  $inp,.Lno_key
91         stx     %g0,[$ctx+16]
92
93         and     $inp,7,$shr             ! alignment factor
94         andn    $inp,7,$inp
95         sll     $shr,3,$shr             ! *8
96         neg     $shr,$shl
97
98         sethi   %hi(0x0ffffffc),$t0
99         set     8,$h1
100         or      $t0,%lo(0x0ffffffc),$t0
101         set     16,$h2
102         sllx    $t0,32,$t1
103         or      $t0,$t1,$t1             ! 0x0ffffffc0ffffffc
104         or      $t1,3,$t0               ! 0x0ffffffc0fffffff
105
106         ldxa    [$inp+%g0]0x88,$h0      ! load little-endian key
107         brz,pt  $shr,.Lkey_aligned
108         ldxa    [$inp+$h1]0x88,$h1
109
110         ldxa    [$inp+$h2]0x88,$h2
111         srlx    $h0,$shr,$h0
112         sllx    $h1,$shl,$t2
113         srlx    $h1,$shr,$h1
114         or      $t2,$h0,$h0
115         sllx    $h2,$shl,$h2
116         or      $h2,$h1,$h1
117
118 .Lkey_aligned:
119         and     $t0,$h0,$h0
120         and     $t1,$h1,$h1
121         stx     $h0,[$ctx+32+0]         ! store key
122         stx     $h1,[$ctx+32+8]
123
124         andcc   %g1,SPARCV9_VIS3,%g0
125         be      .Lno_key
126         nop
127
128 1:      call    .+8
129         add     %o7,poly1305_blocks_vis3-1b,%o7
130
131         add     %o7,poly1305_emit-poly1305_blocks_vis3,%o5
132         STPTR   %o7,[%i2]
133         STPTR   %o5,[%i2+SIZE_T]
134
135         ret
136         restore %g0,1,%o0               ! return 1
137
138 .Lno_key:
139         ret
140         restore %g0,%g0,%o0             ! return 0
141 .type   poly1305_init,#function
142 .size   poly1305_init,.-poly1305_init
143
144 .globl  poly1305_blocks
145 .align  32
146 poly1305_blocks:
147         save    %sp,-STACK_FRAME,%sp
148         srln    $len,4,$len
149
150         brz,pn  $len,.Lno_data
151         nop
152
153         ld      [$ctx+32+0],$r1         ! load key
154         ld      [$ctx+32+4],$r0
155         ld      [$ctx+32+8],$r3
156         ld      [$ctx+32+12],$r2
157
158         ld      [$ctx+0],$h1            ! load hash value
159         ld      [$ctx+4],$h0
160         ld      [$ctx+8],$h3
161         ld      [$ctx+12],$h2
162         ld      [$ctx+16],$h4
163
164         and     $inp,7,$shr             ! alignment factor
165         andn    $inp,7,$inp
166         set     8,$d1
167         sll     $shr,3,$shr             ! *8
168         set     16,$d2
169         neg     $shr,$shl
170
171         srl     $r1,2,$s1
172         srl     $r2,2,$s2
173         add     $r1,$s1,$s1
174         srl     $r3,2,$s3
175         add     $r2,$s2,$s2
176         add     $r3,$s3,$s3
177
178 .Loop:
179         ldxa    [$inp+%g0]0x88,$d0      ! load little-endian input
180         brz,pt  $shr,.Linp_aligned
181         ldxa    [$inp+$d1]0x88,$d1
182
183         ldxa    [$inp+$d2]0x88,$d2
184         srlx    $d0,$shr,$d0
185         sllx    $d1,$shl,$t1
186         srlx    $d1,$shr,$d1
187         or      $t1,$d0,$d0
188         sllx    $d2,$shl,$d2
189         or      $d2,$d1,$d1
190
191 .Linp_aligned:
192         srlx    $d0,32,$t0
193         addcc   $d0,$h0,$h0             ! accumulate input
194         srlx    $d1,32,$t1
195         addccc  $t0,$h1,$h1
196         addccc  $d1,$h2,$h2
197         addccc  $t1,$h3,$h3
198         addc    $padbit,$h4,$h4
199
200         umul    $r0,$h0,$d0
201         umul    $r1,$h0,$d1
202         umul    $r2,$h0,$d2
203         umul    $r3,$h0,$d3
204          sub    $len,1,$len
205          add    $inp,16,$inp
206
207         umul    $s3,$h1,$t0
208         umul    $r0,$h1,$t1
209         umul    $r1,$h1,$t2
210         add     $t0,$d0,$d0
211         add     $t1,$d1,$d1
212         umul    $r2,$h1,$t0
213         add     $t2,$d2,$d2
214         add     $t0,$d3,$d3
215
216         umul    $s2,$h2,$t1
217         umul    $s3,$h2,$t2
218         umul    $r0,$h2,$t0
219         add     $t1,$d0,$d0
220         add     $t2,$d1,$d1
221         umul    $r1,$h2,$t1
222         add     $t0,$d2,$d2
223         add     $t1,$d3,$d3
224
225         umul    $s1,$h3,$t2
226         umul    $s2,$h3,$t0
227         umul    $s3,$h3,$t1
228         add     $t2,$d0,$d0
229         add     $t0,$d1,$d1
230         umul    $r0,$h3,$t2
231         add     $t1,$d2,$d2
232         add     $t2,$d3,$d3
233
234         umul    $s1,$h4,$t0
235         umul    $s2,$h4,$t1
236         umul    $s3,$h4,$t2
237         umul    $r0,$h4,$h4
238         add     $t0,$d1,$d1
239         add     $t1,$d2,$d2
240         srlx    $d0,32,$h1
241         add     $t2,$d3,$d3
242         srlx    $d1,32,$h2
243
244         addcc   $d1,$h1,$h1
245         srlx    $d2,32,$h3
246          set    8,$d1
247         addccc  $d2,$h2,$h2
248         srlx    $d3,32,$t0
249          set    16,$d2
250         addccc  $d3,$h3,$h3
251         addc    $t0,$h4,$h4
252
253         srl     $h4,2,$t0               ! final reduction step
254         andn    $h4,3,$t1
255         and     $h4,3,$h4
256         add     $t1,$t0,$t0
257
258         addcc   $t0,$d0,$h0
259         addccc  %g0,$h1,$h1
260         addccc  %g0,$h2,$h2
261         addccc  %g0,$h3,$h3
262         brnz,pt $len,.Loop
263         addc    %g0,$h4,$h4
264
265         st      $h1,[$ctx+0]            ! store hash value
266         st      $h0,[$ctx+4]
267         st      $h3,[$ctx+8]
268         st      $h2,[$ctx+12]
269         st      $h4,[$ctx+16]
270
271 .Lno_data:
272         ret
273         restore
274 .type   poly1305_blocks,#function
275 .size   poly1305_blocks,.-poly1305_blocks
276 ___
277 ########################################################################
278 # VIS3 has umulxhi and addxc...
279 {
280 my ($H0,$H1,$H2,$R0,$R1,$S1,$T1) = map("%o$_",(0..5,7));
281 my ($D0,$D1,$D2,$T0) = map("%g$_",(1..4));
282
283 $code.=<<___;
284 .align  32
285 poly1305_blocks_vis3:
286         save    %sp,-STACK_FRAME,%sp
287         srln    $len,4,$len
288
289         brz,pn  $len,.Lno_data
290         nop
291
292         ldx     [$ctx+32+0],$R0         ! load key
293         ldx     [$ctx+32+8],$R1
294
295         ldx     [$ctx+0],$H0            ! load hash value
296         ldx     [$ctx+8],$H1
297         ld      [$ctx+16],$H2
298
299         and     $inp,7,$shr             ! alignment factor
300         andn    $inp,7,$inp
301         set     8,$r1
302         sll     $shr,3,$shr             ! *8
303         set     16,$r2
304         neg     $shr,$shl
305
306         srlx    $R1,2,$S1
307         b       .Loop_vis3
308         add     $R1,$S1,$S1
309
310 .Loop_vis3:
311         ldxa    [$inp+%g0]0x88,$D0      ! load little-endian input
312         brz,pt  $shr,.Linp_aligned_vis3
313         ldxa    [$inp+$r1]0x88,$D1
314
315         ldxa    [$inp+$r2]0x88,$D2
316         srlx    $D0,$shr,$D0
317         sllx    $D1,$shl,$T1
318         srlx    $D1,$shr,$D1
319         or      $T1,$D0,$D0
320         sllx    $D2,$shl,$D2
321         or      $D2,$D1,$D1
322
323 .Linp_aligned_vis3:
324         addcc   $D0,$H0,$H0             ! accumulate input
325          sub    $len,1,$len
326         addxccc $D1,$H1,$H1
327          add    $inp,16,$inp
328
329         mulx    $R0,$H0,$D0             ! r0*h0
330         addxc   $padbit,$H2,$H2
331         umulxhi $R0,$H0,$D1
332         mulx    $S1,$H1,$T0             ! s1*h1
333         umulxhi $S1,$H1,$T1
334         addcc   $T0,$D0,$D0
335         mulx    $R1,$H0,$T0             ! r1*h0
336         addxc   $T1,$D1,$D1
337         umulxhi $R1,$H0,$D2
338         addcc   $T0,$D1,$D1
339         mulx    $R0,$H1,$T0             ! r0*h1
340         addxc   %g0,$D2,$D2
341         umulxhi $R0,$H1,$T1
342         addcc   $T0,$D1,$D1
343         mulx    $S1,$H2,$T0             ! s1*h2
344         addxc   $T1,$D2,$D2
345         mulx    $R0,$H2,$T1             ! r0*h2
346         addcc   $T0,$D1,$D1
347         addxc   $T1,$D2,$D2
348
349         srlx    $D2,2,$T0               ! final reduction step
350         andn    $D2,3,$T1
351         and     $D2,3,$H2
352         add     $T1,$T0,$T0
353
354         addcc   $T0,$D0,$H0
355         addxccc %g0,$D1,$H1
356         brnz,pt $len,.Loop_vis3
357         addxc   %g0,$H2,$H2
358
359         stx     $H0,[$ctx+0]            ! store hash value
360         stx     $H1,[$ctx+8]
361         st      $H2,[$ctx+16]
362
363         ret
364         restore
365 .type   poly1305_blocks_vis3,#function
366 .size   poly1305_blocks_vis3,.-poly1305_blocks_vis3
367 ___
368 }
369 my ($mac,$nonce) = ($inp,$len);
370
371 $code.=<<___;
372 .globl  poly1305_emit
373 .align  32
374 poly1305_emit:
375         save    %sp,-STACK_FRAME,%sp
376
377         ld      [$ctx+0],$h1            ! load hash value
378         ld      [$ctx+4],$h0
379         ld      [$ctx+8],$h3
380         ld      [$ctx+12],$h2
381         ld      [$ctx+16],$h4
382
383         addcc   $h0,5,$r0               ! compare to modulus
384         addccc  $h1,0,$r1
385         addccc  $h2,0,$r2
386         addccc  $h3,0,$r3
387         addc    $h4,0,$h4
388         andcc   $h4,4,%g0               ! did it carry/borrow?
389
390         movnz   %icc,$r0,$h0
391         ld      [$nonce+0],$r0          ! load nonce
392         movnz   %icc,$r1,$h1
393         ld      [$nonce+4],$r1
394         movnz   %icc,$r2,$h2
395         ld      [$nonce+8],$r2
396         movnz   %icc,$r3,$h3
397         ld      [$nonce+12],$r3
398
399         addcc   $r0,$h0,$h0             ! accumulate nonce
400         addccc  $r1,$h1,$h1
401         addccc  $r2,$h2,$h2
402         addc    $r3,$h3,$h3
403
404         srl     $h0,8,$r0
405         stb     $h0,[$mac+0]            ! store little-endian result
406         srl     $h0,16,$r1
407         stb     $r0,[$mac+1]
408         srl     $h0,24,$r2
409         stb     $r1,[$mac+2]
410         stb     $r2,[$mac+3]
411
412         srl     $h1,8,$r0
413         stb     $h1,[$mac+4]
414         srl     $h1,16,$r1
415         stb     $r0,[$mac+5]
416         srl     $h1,24,$r2
417         stb     $r1,[$mac+6]
418         stb     $r2,[$mac+7]
419
420         srl     $h2,8,$r0
421         stb     $h2,[$mac+8]
422         srl     $h2,16,$r1
423         stb     $r0,[$mac+9]
424         srl     $h2,24,$r2
425         stb     $r1,[$mac+10]
426         stb     $r2,[$mac+11]
427
428         srl     $h3,8,$r0
429         stb     $h3,[$mac+12]
430         srl     $h3,16,$r1
431         stb     $r0,[$mac+13]
432         srl     $h3,24,$r2
433         stb     $r1,[$mac+14]
434         stb     $r2,[$mac+15]
435
436         ret
437         restore
438 .type   poly1305_emit,#function
439 .size   poly1305_emit,.-poly1305_emit
440 ___
441
442 {
443 my ($ctx,$inp,$len,$padbit) = map("%i$_",(0..3));
444 my ($in0,$in1,$in2,$in3,$in4) = map("%o$_",(0..4));
445 my ($i1,$step,$shr,$shl) = map("%l$_",(0..7));
446 my $i2=$step;
447
448 my ($h0lo,$h0hi,$h1lo,$h1hi,$h2lo,$h2hi,$h3lo,$h3hi,
449     $two0,$two32,$two64,$two96,$two130,$five_two130,
450     $r0lo,$r0hi,$r1lo,$r1hi,$r2lo,$r2hi,
451     $s2lo,$s2hi,$s3lo,$s3hi,
452     $c0lo,$c0hi,$c1lo,$c1hi,$c2lo,$c2hi,$c3lo,$c3hi) = map("%f".2*$_,(0..31));
453 # borrowings
454 my ($r3lo,$r3hi,$s1lo,$s1hi) = ($c0lo,$c0hi,$c1lo,$c1hi);
455 my ($x0,$x1,$x2,$x3) = ($c2lo,$c2hi,$c3lo,$c3hi);
456 my ($y0,$y1,$y2,$y3) = ($c1lo,$c1hi,$c3hi,$c3lo);
457
458 $code.=<<___;
459 .align  32
460 poly1305_init_fma:
461         save    %sp,-STACK_FRAME-16,%sp
462         nop
463
464 .Lpoly1305_init_fma:
465 1:      call    .+8
466         add     %o7,.Lconsts_fma-1b,%o7
467
468         ldd     [%o7+8*0],$two0                 ! load constants
469         ldd     [%o7+8*1],$two32
470         ldd     [%o7+8*2],$two64
471         ldd     [%o7+8*3],$two96
472         ldd     [%o7+8*5],$five_two130
473
474         std     $two0,[$ctx+8*0]                ! initial hash value, biased 0
475         std     $two32,[$ctx+8*1]
476         std     $two64,[$ctx+8*2]
477         std     $two96,[$ctx+8*3]
478
479         brz,pn  $inp,.Lno_key_fma
480         nop
481
482         stx     %fsr,[%sp+LOCALS]               ! save original %fsr
483         ldx     [%o7+8*6],%fsr                  ! load new %fsr
484
485         std     $two0,[$ctx+8*4]                ! key "template"
486         std     $two32,[$ctx+8*5]
487         std     $two64,[$ctx+8*6]
488         std     $two96,[$ctx+8*7]
489
490         and     $inp,7,$shr
491         andn    $inp,7,$inp                     ! align pointer
492         mov     8,$i1
493         sll     $shr,3,$shr
494         mov     16,$i2
495         neg     $shr,$shl
496
497         ldxa    [$inp+%g0]0x88,$in0             ! load little-endian key
498         ldxa    [$inp+$i1]0x88,$in2
499
500         brz     $shr,.Lkey_aligned_fma
501         sethi   %hi(0xf0000000),$i1             !   0xf0000000
502
503         ldxa    [$inp+$i2]0x88,$in4
504
505         srlx    $in0,$shr,$in0                  ! align data
506         sllx    $in2,$shl,$in1
507         srlx    $in2,$shr,$in2
508         or      $in1,$in0,$in0
509         sllx    $in4,$shl,$in3
510         or      $in3,$in2,$in2
511
512 .Lkey_aligned_fma:
513         or      $i1,3,$i2                       !   0xf0000003
514         srlx    $in0,32,$in1
515         andn    $in0,$i1,$in0                   ! &=0x0fffffff
516         andn    $in1,$i2,$in1                   ! &=0x0ffffffc
517         srlx    $in2,32,$in3
518         andn    $in2,$i2,$in2
519         andn    $in3,$i2,$in3
520
521         st      $in0,[$ctx+`8*4+4`]             ! fill "template"
522         st      $in1,[$ctx+`8*5+4`]
523         st      $in2,[$ctx+`8*6+4`]
524         st      $in3,[$ctx+`8*7+4`]
525
526         ldd     [$ctx+8*4],$h0lo                ! load [biased] key
527         ldd     [$ctx+8*5],$h1lo
528         ldd     [$ctx+8*6],$h2lo
529         ldd     [$ctx+8*7],$h3lo
530
531         fsubd   $h0lo,$two0, $h0lo              ! r0
532          ldd    [%o7+8*7],$two0                 ! more constants
533         fsubd   $h1lo,$two32,$h1lo              ! r1
534          ldd    [%o7+8*8],$two32
535         fsubd   $h2lo,$two64,$h2lo              ! r2
536          ldd    [%o7+8*9],$two64
537         fsubd   $h3lo,$two96,$h3lo              ! r3
538          ldd    [%o7+8*10],$two96
539
540         fmuld   $five_two130,$h1lo,$s1lo        ! s1
541         fmuld   $five_two130,$h2lo,$s2lo        ! s2
542         fmuld   $five_two130,$h3lo,$s3lo        ! s3
543
544         faddd   $h0lo,$two0, $h0hi
545         faddd   $h1lo,$two32,$h1hi
546         faddd   $h2lo,$two64,$h2hi
547         faddd   $h3lo,$two96,$h3hi
548
549         fsubd   $h0hi,$two0, $h0hi
550          ldd    [%o7+8*11],$two0                ! more constants
551         fsubd   $h1hi,$two32,$h1hi
552          ldd    [%o7+8*12],$two32
553         fsubd   $h2hi,$two64,$h2hi
554          ldd    [%o7+8*13],$two64
555         fsubd   $h3hi,$two96,$h3hi
556
557         fsubd   $h0lo,$h0hi,$h0lo
558          std    $h0hi,[$ctx+8*5]                ! r0hi
559         fsubd   $h1lo,$h1hi,$h1lo
560          std    $h1hi,[$ctx+8*7]                ! r1hi
561         fsubd   $h2lo,$h2hi,$h2lo
562          std    $h2hi,[$ctx+8*9]                ! r2hi
563         fsubd   $h3lo,$h3hi,$h3lo
564          std    $h3hi,[$ctx+8*11]               ! r3hi
565
566         faddd   $s1lo,$two0, $s1hi
567         faddd   $s2lo,$two32,$s2hi
568         faddd   $s3lo,$two64,$s3hi
569
570         fsubd   $s1hi,$two0, $s1hi
571         fsubd   $s2hi,$two32,$s2hi
572         fsubd   $s3hi,$two64,$s3hi
573
574         fsubd   $s1lo,$s1hi,$s1lo
575         fsubd   $s2lo,$s2hi,$s2lo
576         fsubd   $s3lo,$s3hi,$s3lo
577
578         ldx     [%sp+LOCALS],%fsr               ! restore %fsr
579
580         std     $h0lo,[$ctx+8*4]                ! r0lo
581         std     $h1lo,[$ctx+8*6]                ! r1lo
582         std     $h2lo,[$ctx+8*8]                ! r2lo
583         std     $h3lo,[$ctx+8*10]               ! r3lo
584
585         std     $s1hi,[$ctx+8*13]
586         std     $s2hi,[$ctx+8*15]
587         std     $s3hi,[$ctx+8*17]
588
589         std     $s1lo,[$ctx+8*12]
590         std     $s2lo,[$ctx+8*14]
591         std     $s3lo,[$ctx+8*16]
592
593         add     %o7,poly1305_blocks_fma-.Lconsts_fma,%o0
594         add     %o7,poly1305_emit_fma-.Lconsts_fma,%o1
595         STPTR   %o0,[%i2]
596         STPTR   %o1,[%i2+SIZE_T]
597
598         ret
599         restore %g0,1,%o0                       ! return 1
600
601 .Lno_key_fma:
602         ret
603         restore %g0,%g0,%o0                     ! return 0
604 .type   poly1305_init_fma,#function
605 .size   poly1305_init_fma,.-poly1305_init_fma
606
607 .align  32
608 poly1305_blocks_fma:
609         save    %sp,-STACK_FRAME-48,%sp
610         srln    $len,4,$len
611
612         brz,pn  $len,.Labort
613         sub     $len,1,$len
614
615 1:      call    .+8
616         add     %o7,.Lconsts_fma-1b,%o7
617
618         ldd     [%o7+8*0],$two0                 ! load constants
619         ldd     [%o7+8*1],$two32
620         ldd     [%o7+8*2],$two64
621         ldd     [%o7+8*3],$two96
622         ldd     [%o7+8*4],$two130
623         ldd     [%o7+8*5],$five_two130
624
625         ldd     [$ctx+8*0],$h0lo                ! load [biased] hash value
626         ldd     [$ctx+8*1],$h1lo
627         ldd     [$ctx+8*2],$h2lo
628         ldd     [$ctx+8*3],$h3lo
629
630         std     $two0,[%sp+LOCALS+8*0]          ! input "template"
631         sethi   %hi((1023+52+96)<<20),$in3
632         std     $two32,[%sp+LOCALS+8*1]
633         or      $padbit,$in3,$in3
634         std     $two64,[%sp+LOCALS+8*2]
635         st      $in3,[%sp+LOCALS+8*3]
636
637         and     $inp,7,$shr
638         andn    $inp,7,$inp                     ! align pointer
639         mov     8,$i1
640         sll     $shr,3,$shr
641         mov     16,$step
642         neg     $shr,$shl
643
644         ldxa    [$inp+%g0]0x88,$in0             ! load little-endian input
645         brz     $shr,.Linp_aligned_fma
646         ldxa    [$inp+$i1]0x88,$in2
647
648         ldxa    [$inp+$step]0x88,$in4
649         add     $inp,8,$inp
650
651         srlx    $in0,$shr,$in0                  ! align data
652         sllx    $in2,$shl,$in1
653         srlx    $in2,$shr,$in2
654         or      $in1,$in0,$in0
655         sllx    $in4,$shl,$in3
656         srlx    $in4,$shr,$in4                  ! pre-shift
657         or      $in3,$in2,$in2
658
659 .Linp_aligned_fma:
660         srlx    $in0,32,$in1
661         movrz   $len,0,$step
662         srlx    $in2,32,$in3
663         add     $step,$inp,$inp                 ! conditional advance
664
665         st      $in0,[%sp+LOCALS+8*0+4]         ! fill "template"
666         st      $in1,[%sp+LOCALS+8*1+4]
667         st      $in2,[%sp+LOCALS+8*2+4]
668         st      $in3,[%sp+LOCALS+8*3+4]
669
670         ldd     [$ctx+8*4],$r0lo                ! load key
671         ldd     [$ctx+8*5],$r0hi
672         ldd     [$ctx+8*6],$r1lo
673         ldd     [$ctx+8*7],$r1hi
674         ldd     [$ctx+8*8],$r2lo
675         ldd     [$ctx+8*9],$r2hi
676         ldd     [$ctx+8*10],$r3lo
677         ldd     [$ctx+8*11],$r3hi
678         ldd     [$ctx+8*12],$s1lo
679         ldd     [$ctx+8*13],$s1hi
680         ldd     [$ctx+8*14],$s2lo
681         ldd     [$ctx+8*15],$s2hi
682         ldd     [$ctx+8*16],$s3lo
683         ldd     [$ctx+8*17],$s3hi
684
685         stx     %fsr,[%sp+LOCALS+8*4]           ! save original %fsr
686         ldx     [%o7+8*6],%fsr                  ! load new %fsr
687
688         subcc   $len,1,$len
689         movrz   $len,0,$step
690
691         ldd     [%sp+LOCALS+8*0],$x0            ! load biased input
692         ldd     [%sp+LOCALS+8*1],$x1
693         ldd     [%sp+LOCALS+8*2],$x2
694         ldd     [%sp+LOCALS+8*3],$x3
695
696         fsubd   $h0lo,$two0, $h0lo              ! de-bias hash value
697         fsubd   $h1lo,$two32,$h1lo
698          ldxa   [$inp+%g0]0x88,$in0             ! modulo-scheduled input load
699         fsubd   $h2lo,$two64,$h2lo
700         fsubd   $h3lo,$two96,$h3lo
701          ldxa   [$inp+$i1]0x88,$in2
702
703         fsubd   $x0,$two0, $x0                  ! de-bias input
704         fsubd   $x1,$two32,$x1
705         fsubd   $x2,$two64,$x2
706         fsubd   $x3,$two96,$x3
707
708         brz     $shr,.Linp_aligned_fma2
709         add     $step,$inp,$inp                 ! conditional advance
710
711         sllx    $in0,$shl,$in1                  ! align data
712         srlx    $in0,$shr,$in3
713         or      $in1,$in4,$in0
714         sllx    $in2,$shl,$in1
715         srlx    $in2,$shr,$in4                  ! pre-shift
716         or      $in3,$in1,$in2
717 .Linp_aligned_fma2:
718         srlx    $in0,32,$in1
719         srlx    $in2,32,$in3
720
721         faddd   $h0lo,$x0,$x0                   ! accumulate input
722          stw    $in0,[%sp+LOCALS+8*0+4]
723         faddd   $h1lo,$x1,$x1
724          stw    $in1,[%sp+LOCALS+8*1+4]
725         faddd   $h2lo,$x2,$x2
726          stw    $in2,[%sp+LOCALS+8*2+4]
727         faddd   $h3lo,$x3,$x3
728          stw    $in3,[%sp+LOCALS+8*3+4]
729
730         b       .Lentry_fma
731         nop
732
733 .align  16
734 .Loop_fma:
735         ldxa    [$inp+%g0]0x88,$in0             ! modulo-scheduled input load
736         ldxa    [$inp+$i1]0x88,$in2
737         movrz   $len,0,$step
738
739         faddd   $y0,$h0lo,$h0lo                 ! accumulate input
740         faddd   $y1,$h0hi,$h0hi
741         faddd   $y2,$h2lo,$h2lo
742         faddd   $y3,$h2hi,$h2hi
743
744         brz,pn  $shr,.Linp_aligned_fma3
745         add     $step,$inp,$inp                 ! conditional advance
746
747         sllx    $in0,$shl,$in1                  ! align data
748         srlx    $in0,$shr,$in3
749         or      $in1,$in4,$in0
750         sllx    $in2,$shl,$in1
751         srlx    $in2,$shr,$in4                  ! pre-shift
752         or      $in3,$in1,$in2
753
754 .Linp_aligned_fma3:
755         !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! base 2^48 -> base 2^32
756         faddd   $two64,$h1lo,$c1lo
757          srlx   $in0,32,$in1
758         faddd   $two64,$h1hi,$c1hi
759          srlx   $in2,32,$in3
760         faddd   $two130,$h3lo,$c3lo
761          st     $in0,[%sp+LOCALS+8*0+4]         ! fill "template"
762         faddd   $two130,$h3hi,$c3hi
763          st     $in1,[%sp+LOCALS+8*1+4]
764         faddd   $two32,$h0lo,$c0lo
765          st     $in2,[%sp+LOCALS+8*2+4]
766         faddd   $two32,$h0hi,$c0hi
767          st     $in3,[%sp+LOCALS+8*3+4]
768         faddd   $two96,$h2lo,$c2lo
769         faddd   $two96,$h2hi,$c2hi
770
771         fsubd   $c1lo,$two64,$c1lo
772         fsubd   $c1hi,$two64,$c1hi
773         fsubd   $c3lo,$two130,$c3lo
774         fsubd   $c3hi,$two130,$c3hi
775         fsubd   $c0lo,$two32,$c0lo
776         fsubd   $c0hi,$two32,$c0hi
777         fsubd   $c2lo,$two96,$c2lo
778         fsubd   $c2hi,$two96,$c2hi
779
780         fsubd   $h1lo,$c1lo,$h1lo
781         fsubd   $h1hi,$c1hi,$h1hi
782         fsubd   $h3lo,$c3lo,$h3lo
783         fsubd   $h3hi,$c3hi,$h3hi
784         fsubd   $h2lo,$c2lo,$h2lo
785         fsubd   $h2hi,$c2hi,$h2hi
786         fsubd   $h0lo,$c0lo,$h0lo
787         fsubd   $h0hi,$c0hi,$h0hi
788
789         faddd   $h1lo,$c0lo,$h1lo
790         faddd   $h1hi,$c0hi,$h1hi
791         faddd   $h3lo,$c2lo,$h3lo
792         faddd   $h3hi,$c2hi,$h3hi
793         faddd   $h2lo,$c1lo,$h2lo
794         faddd   $h2hi,$c1hi,$h2hi
795         fmaddd  $five_two130,$c3lo,$h0lo,$h0lo
796         fmaddd  $five_two130,$c3hi,$h0hi,$h0hi
797
798         faddd   $h1lo,$h1hi,$x1
799          ldd    [$ctx+8*12],$s1lo               ! reload constants
800         faddd   $h3lo,$h3hi,$x3
801          ldd    [$ctx+8*13],$s1hi
802         faddd   $h2lo,$h2hi,$x2
803          ldd    [$ctx+8*10],$r3lo
804         faddd   $h0lo,$h0hi,$x0
805          ldd    [$ctx+8*11],$r3hi
806
807 .Lentry_fma:
808         fmuld   $x1,$s3lo,$h0lo
809         fmuld   $x1,$s3hi,$h0hi
810         fmuld   $x1,$r1lo,$h2lo
811         fmuld   $x1,$r1hi,$h2hi
812         fmuld   $x1,$r0lo,$h1lo
813         fmuld   $x1,$r0hi,$h1hi
814         fmuld   $x1,$r2lo,$h3lo
815         fmuld   $x1,$r2hi,$h3hi
816
817         fmaddd  $x3,$s1lo,$h0lo,$h0lo
818         fmaddd  $x3,$s1hi,$h0hi,$h0hi
819         fmaddd  $x3,$s3lo,$h2lo,$h2lo
820         fmaddd  $x3,$s3hi,$h2hi,$h2hi
821         fmaddd  $x3,$s2lo,$h1lo,$h1lo
822         fmaddd  $x3,$s2hi,$h1hi,$h1hi
823         fmaddd  $x3,$r0lo,$h3lo,$h3lo
824         fmaddd  $x3,$r0hi,$h3hi,$h3hi
825
826         fmaddd  $x2,$s2lo,$h0lo,$h0lo
827         fmaddd  $x2,$s2hi,$h0hi,$h0hi
828         fmaddd  $x2,$r0lo,$h2lo,$h2lo
829         fmaddd  $x2,$r0hi,$h2hi,$h2hi
830         fmaddd  $x2,$s3lo,$h1lo,$h1lo
831          ldd    [%sp+LOCALS+8*0],$y0            ! load [biased] input
832         fmaddd  $x2,$s3hi,$h1hi,$h1hi
833          ldd    [%sp+LOCALS+8*1],$y1
834         fmaddd  $x2,$r1lo,$h3lo,$h3lo
835          ldd    [%sp+LOCALS+8*2],$y2
836         fmaddd  $x2,$r1hi,$h3hi,$h3hi
837          ldd    [%sp+LOCALS+8*3],$y3
838
839         fmaddd  $x0,$r0lo,$h0lo,$h0lo
840          fsubd  $y0,$two0, $y0                  ! de-bias input
841         fmaddd  $x0,$r0hi,$h0hi,$h0hi
842          fsubd  $y1,$two32,$y1
843         fmaddd  $x0,$r2lo,$h2lo,$h2lo
844          fsubd  $y2,$two64,$y2
845         fmaddd  $x0,$r2hi,$h2hi,$h2hi
846          fsubd  $y3,$two96,$y3
847         fmaddd  $x0,$r1lo,$h1lo,$h1lo
848         fmaddd  $x0,$r1hi,$h1hi,$h1hi
849         fmaddd  $x0,$r3lo,$h3lo,$h3lo
850         fmaddd  $x0,$r3hi,$h3hi,$h3hi
851
852         bcc     SIZE_T_CC,.Loop_fma
853         subcc   $len,1,$len
854
855         !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! base 2^48 -> base 2^32
856         faddd   $h0lo,$two32,$c0lo
857         faddd   $h0hi,$two32,$c0hi
858         faddd   $h2lo,$two96,$c2lo
859         faddd   $h2hi,$two96,$c2hi
860         faddd   $h1lo,$two64,$c1lo
861         faddd   $h1hi,$two64,$c1hi
862         faddd   $h3lo,$two130,$c3lo
863         faddd   $h3hi,$two130,$c3hi
864
865         fsubd   $c0lo,$two32,$c0lo
866         fsubd   $c0hi,$two32,$c0hi
867         fsubd   $c2lo,$two96,$c2lo
868         fsubd   $c2hi,$two96,$c2hi
869         fsubd   $c1lo,$two64,$c1lo
870         fsubd   $c1hi,$two64,$c1hi
871         fsubd   $c3lo,$two130,$c3lo
872         fsubd   $c3hi,$two130,$c3hi
873
874         fsubd   $h1lo,$c1lo,$h1lo
875         fsubd   $h1hi,$c1hi,$h1hi
876         fsubd   $h3lo,$c3lo,$h3lo
877         fsubd   $h3hi,$c3hi,$h3hi
878         fsubd   $h2lo,$c2lo,$h2lo
879         fsubd   $h2hi,$c2hi,$h2hi
880         fsubd   $h0lo,$c0lo,$h0lo
881         fsubd   $h0hi,$c0hi,$h0hi
882
883         faddd   $h1lo,$c0lo,$h1lo
884         faddd   $h1hi,$c0hi,$h1hi
885         faddd   $h3lo,$c2lo,$h3lo
886         faddd   $h3hi,$c2hi,$h3hi
887         faddd   $h2lo,$c1lo,$h2lo
888         faddd   $h2hi,$c1hi,$h2hi
889         fmaddd  $five_two130,$c3lo,$h0lo,$h0lo
890         fmaddd  $five_two130,$c3hi,$h0hi,$h0hi
891
892         faddd   $h1lo,$h1hi,$x1
893         faddd   $h3lo,$h3hi,$x3
894         faddd   $h2lo,$h2hi,$x2
895         faddd   $h0lo,$h0hi,$x0
896
897         faddd   $x1,$two32,$x1                  ! bias
898         faddd   $x3,$two96,$x3
899         faddd   $x2,$two64,$x2
900         faddd   $x0,$two0, $x0
901
902         ldx     [%sp+LOCALS+8*4],%fsr           ! restore saved %fsr
903
904         std     $x1,[$ctx+8*1]                  ! store [biased] hash value
905         std     $x3,[$ctx+8*3]
906         std     $x2,[$ctx+8*2]
907         std     $x0,[$ctx+8*0]
908
909 .Labort:
910         ret
911         restore
912 .type   poly1305_blocks_fma,#function
913 .size   poly1305_blocks_fma,.-poly1305_blocks_fma
914 ___
915 {
916 my ($mac,$nonce)=($inp,$len);
917
918 my ($h0,$h1,$h2,$h3,$h4, $d0,$d1,$d2,$d3, $mask
919    ) = (map("%l$_",(0..5)),map("%o$_",(0..4)));
920
921 $code.=<<___;
922 .align  32
923 poly1305_emit_fma:
924         save    %sp,-STACK_FRAME,%sp
925
926         ld      [$ctx+8*0+0],$d0                ! load hash
927         ld      [$ctx+8*0+4],$h0
928         ld      [$ctx+8*1+0],$d1
929         ld      [$ctx+8*1+4],$h1
930         ld      [$ctx+8*2+0],$d2
931         ld      [$ctx+8*2+4],$h2
932         ld      [$ctx+8*3+0],$d3
933         ld      [$ctx+8*3+4],$h3
934
935         sethi   %hi(0xfff00000),$mask
936         andn    $d0,$mask,$d0                   ! mask exponent
937         andn    $d1,$mask,$d1
938         andn    $d2,$mask,$d2
939         andn    $d3,$mask,$d3                   ! can be partially reduced...
940         mov     3,$mask
941
942         srl     $d3,2,$padbit                   ! ... so reduce
943         and     $d3,$mask,$h4
944         andn    $d3,$mask,$d3
945         add     $padbit,$d3,$d3
946
947         addcc   $d3,$h0,$h0
948         addccc  $d0,$h1,$h1
949         addccc  $d1,$h2,$h2
950         addccc  $d2,$h3,$h3
951         addc    %g0,$h4,$h4
952
953         addcc   $h0,5,$d0                       ! compare to modulus
954         addccc  $h1,0,$d1
955         addccc  $h2,0,$d2
956         addccc  $h3,0,$d3
957         addc    $h4,0,$mask
958
959         srl     $mask,2,$mask                   ! did it carry/borrow?
960         neg     $mask,$mask
961         sra     $mask,31,$mask                  ! mask
962
963         andn    $h0,$mask,$h0
964         and     $d0,$mask,$d0
965         andn    $h1,$mask,$h1
966         and     $d1,$mask,$d1
967         or      $d0,$h0,$h0
968         ld      [$nonce+0],$d0                  ! load nonce
969         andn    $h2,$mask,$h2
970         and     $d2,$mask,$d2
971         or      $d1,$h1,$h1
972         ld      [$nonce+4],$d1
973         andn    $h3,$mask,$h3
974         and     $d3,$mask,$d3
975         or      $d2,$h2,$h2
976         ld      [$nonce+8],$d2
977         or      $d3,$h3,$h3
978         ld      [$nonce+12],$d3
979
980         addcc   $d0,$h0,$h0                     ! accumulate nonce
981         addccc  $d1,$h1,$h1
982         addccc  $d2,$h2,$h2
983         addc    $d3,$h3,$h3
984
985         stb     $h0,[$mac+0]                    ! write little-endian result
986         srl     $h0,8,$h0
987         stb     $h1,[$mac+4]
988         srl     $h1,8,$h1
989         stb     $h2,[$mac+8]
990         srl     $h2,8,$h2
991         stb     $h3,[$mac+12]
992         srl     $h3,8,$h3
993
994         stb     $h0,[$mac+1]
995         srl     $h0,8,$h0
996         stb     $h1,[$mac+5]
997         srl     $h1,8,$h1
998         stb     $h2,[$mac+9]
999         srl     $h2,8,$h2
1000         stb     $h3,[$mac+13]
1001         srl     $h3,8,$h3
1002
1003         stb     $h0,[$mac+2]
1004         srl     $h0,8,$h0
1005         stb     $h1,[$mac+6]
1006         srl     $h1,8,$h1
1007         stb     $h2,[$mac+10]
1008         srl     $h2,8,$h2
1009         stb     $h3,[$mac+14]
1010         srl     $h3,8,$h3
1011
1012         stb     $h0,[$mac+3]
1013         stb     $h1,[$mac+7]
1014         stb     $h2,[$mac+11]
1015         stb     $h3,[$mac+15]
1016
1017         ret
1018         restore
1019 .type   poly1305_emit_fma,#function
1020 .size   poly1305_emit_fma,.-poly1305_emit_fma
1021 ___
1022 }
1023
1024 $code.=<<___;
1025 .align  64
1026 .Lconsts_fma:
1027 .word   0x43300000,0x00000000           ! 2^(52+0)
1028 .word   0x45300000,0x00000000           ! 2^(52+32)
1029 .word   0x47300000,0x00000000           ! 2^(52+64)
1030 .word   0x49300000,0x00000000           ! 2^(52+96)
1031 .word   0x4b500000,0x00000000           ! 2^(52+130)
1032
1033 .word   0x37f40000,0x00000000           ! 5/2^130
1034 .word   0,1<<30                         ! fsr: truncate, no exceptions
1035
1036 .word   0x44300000,0x00000000           ! 2^(52+16+0)
1037 .word   0x46300000,0x00000000           ! 2^(52+16+32)
1038 .word   0x48300000,0x00000000           ! 2^(52+16+64)
1039 .word   0x4a300000,0x00000000           ! 2^(52+16+96)
1040 .word   0x3e300000,0x00000000           ! 2^(52+16+0-96)
1041 .word   0x40300000,0x00000000           ! 2^(52+16+32-96)
1042 .word   0x42300000,0x00000000           ! 2^(52+16+64-96)
1043 .asciz  "Poly1305 for SPARCv9/VIS3/FMA, CRYPTOGAMS by <appro\@openssl.org>"
1044 .align  4
1045 ___
1046 }
1047 \f
1048 # Purpose of these subroutines is to explicitly encode VIS instructions,
1049 # so that one can compile the module without having to specify VIS
1050 # extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
1051 # Idea is to reserve for option to produce "universal" binary and let
1052 # programmer detect if current CPU is VIS capable at run-time.
1053 sub unvis3 {
1054 my ($mnemonic,$rs1,$rs2,$rd)=@_;
1055 my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
1056 my ($ref,$opf);
1057 my %visopf = (  "addxc"         => 0x011,
1058                 "addxccc"       => 0x013,
1059                 "umulxhi"       => 0x016        );
1060
1061     $ref = "$mnemonic\t$rs1,$rs2,$rd";
1062
1063     if ($opf=$visopf{$mnemonic}) {
1064         foreach ($rs1,$rs2,$rd) {
1065             return $ref if (!/%([goli])([0-9])/);
1066             $_=$bias{$1}+$2;
1067         }
1068
1069         return  sprintf ".word\t0x%08x !%s",
1070                         0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
1071                         $ref;
1072     } else {
1073         return $ref;
1074     }
1075 }
1076
1077 sub unfma {
1078 my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
1079 my ($ref,$opf);
1080 my %fmaopf = (  "fmadds"        => 0x1,
1081                 "fmaddd"        => 0x2,
1082                 "fmsubs"        => 0x5,
1083                 "fmsubd"        => 0x6          );
1084
1085     $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
1086
1087     if ($opf=$fmaopf{$mnemonic}) {
1088         foreach ($rs1,$rs2,$rs3,$rd) {
1089             return $ref if (!/%f([0-9]{1,2})/);
1090             $_=$1;
1091             if ($1>=32) {
1092                 return $ref if ($1&1);
1093                 # re-encode for upper double register addressing
1094                 $_=($1|$1>>5)&31;
1095             }
1096         }
1097
1098         return  sprintf ".word\t0x%08x !%s",
1099                         0x81b80000|$rd<<25|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
1100                         $ref;
1101     } else {
1102         return $ref;
1103     }
1104 }
1105
1106 foreach (split("\n",$code)) {
1107         s/\`([^\`]*)\`/eval $1/ge;
1108
1109         s/\b(umulxhi|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
1110                 &unvis3($1,$2,$3,$4)
1111          /ge    or
1112         s/\b(fmadd[sd])\s+(%f[0-9]+),\s*(%f[0-9]+),\s*(%f[0-9]+),\s*(%f[0-9]+)/
1113                 &unfma($1,$2,$3,$4,$5)
1114          /ge;
1115
1116         print $_,"\n";
1117 }
1118
1119 close STDOUT;