Add OpenSSL copyright to .pl files
[openssl.git] / crypto / md5 / asm / md5-sparcv9.pl
index c9ce0b94ada7b39971157bc286a5987bd695d110..09e6d7139a8b678d351ae3909b170460985e6172 100644 (file)
@@ -1,21 +1,30 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
 
 # ====================================================================
-# Written by Andy Polyakov <appro@opensl.org> for the OpenSSL
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
 # project. The module is, however, dual licensed under OpenSSL and
 # CRYPTOGAMS licenses depending on where you obtain it. For further
 # details see http://www.openssl.org/~appro/cryptogams/.
+#
+# Hardware SPARC T4 support by David S. Miller <davem@davemloft.net>.
 # ====================================================================
 
-# MD5 for SPARCv9, 7.5 cycles per byte on UltraSPARC, >40% faster than
+# MD5 for SPARCv9, 6.9 cycles per byte on UltraSPARC, >40% faster than
 # code generated by Sun C 5.2.
 
-$bits=32;
-for (@ARGV)    { $bits=64 if (/\-m64/ || /\-xarch\=v9/); }
-if ($bits==64) { $bias=2047; $frame=192; }
-else           { $bias=0;    $frame=112; }
+# SPARC T4 MD5 hardware achieves 3.20 cycles per byte, which is 2.1x
+# faster than software. Multi-process benchmark saturates at 12x
+# single-process result on 8-core processor, or ~11GBps per 2.85GHz
+# socket.
 
-$output=shift;
+$output=pop;
 open STDOUT,">$output";
 
 use integer;
@@ -191,17 +200,105 @@ $code.=<<___;
 ___
 }
 
-$code.=<<___ if ($bits==64);
+$code.=<<___;
+#include "sparc_arch.h"
+
+#ifdef __arch64__
 .register      %g2,#scratch
 .register      %g3,#scratch
-___
-$code.=<<___;
+#endif
+
 .section       ".text",#alloc,#execinstr
 
+#ifdef __PIC__
+SPARC_PIC_THUNK(%g1)
+#endif
+
 .globl md5_block_asm_data_order
 .align 32
 md5_block_asm_data_order:
-       save    %sp,-$frame,%sp
+       SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
+       ld      [%g1+4],%g1             ! OPENSSL_sparcv9cap_P[1]
+
+       andcc   %g1, CFR_MD5, %g0
+       be      .Lsoftware
+       nop
+
+       mov     4, %g1
+       andcc   %o1, 0x7, %g0
+       lda     [%o0 + %g0]0x88, %f0            ! load context
+       lda     [%o0 + %g1]0x88, %f1
+       add     %o0, 8, %o0
+       lda     [%o0 + %g0]0x88, %f2
+       lda     [%o0 + %g1]0x88, %f3
+       bne,pn  %icc, .Lhwunaligned
+       sub     %o0, 8, %o0
+
+.Lhw_loop:
+       ldd     [%o1 + 0x00], %f8
+       ldd     [%o1 + 0x08], %f10
+       ldd     [%o1 + 0x10], %f12
+       ldd     [%o1 + 0x18], %f14
+       ldd     [%o1 + 0x20], %f16
+       ldd     [%o1 + 0x28], %f18
+       ldd     [%o1 + 0x30], %f20
+       subcc   %o2, 1, %o2             ! done yet? 
+       ldd     [%o1 + 0x38], %f22
+       add     %o1, 0x40, %o1
+       prefetch [%o1 + 63], 20
+
+       .word   0x81b02800              ! MD5
+
+       bne,pt  SIZE_T_CC, .Lhw_loop
+       nop
+
+.Lhwfinish:
+       sta     %f0, [%o0 + %g0]0x88    ! store context
+       sta     %f1, [%o0 + %g1]0x88
+       add     %o0, 8, %o0
+       sta     %f2, [%o0 + %g0]0x88
+       sta     %f3, [%o0 + %g1]0x88
+       retl
+       nop
+
+.align 8
+.Lhwunaligned:
+       alignaddr %o1, %g0, %o1
+
+       ldd     [%o1 + 0x00], %f10
+.Lhwunaligned_loop:
+       ldd     [%o1 + 0x08], %f12
+       ldd     [%o1 + 0x10], %f14
+       ldd     [%o1 + 0x18], %f16
+       ldd     [%o1 + 0x20], %f18
+       ldd     [%o1 + 0x28], %f20
+       ldd     [%o1 + 0x30], %f22
+       ldd     [%o1 + 0x38], %f24
+       subcc   %o2, 1, %o2             ! done yet?
+       ldd     [%o1 + 0x40], %f26
+       add     %o1, 0x40, %o1
+       prefetch [%o1 + 63], 20
+
+       faligndata %f10, %f12, %f8
+       faligndata %f12, %f14, %f10
+       faligndata %f14, %f16, %f12
+       faligndata %f16, %f18, %f14
+       faligndata %f18, %f20, %f16
+       faligndata %f20, %f22, %f18
+       faligndata %f22, %f24, %f20
+       faligndata %f24, %f26, %f22
+
+       .word   0x81b02800              ! MD5
+
+       bne,pt  SIZE_T_CC, .Lhwunaligned_loop
+       for     %f26, %f26, %f10        ! %f10=%f26
+
+       ba      .Lhwfinish
+       nop
+
+.align 16
+.Lsoftware:
+       save    %sp,-STACK_FRAME,%sp
 
        rd      %asi,$saved_asi
        wr      %g0,0x88,%asi           ! ASI_PRIMARY_LITTLE
@@ -261,7 +358,7 @@ $code.=<<___;
        add     $t2,$C,$C
        add     $CD,$D,$D
        srl     $B,0,$B                 ! clruw $B
-       bne     `$bits==64?"%xcc":"%icc"`,.Loop
+       bne     SIZE_T_CC,.Loop
        srl     $D,0,$D                 ! clruw $D
 
        st      $A,[$ctx+0]             ! write out ctx
@@ -279,6 +376,62 @@ $code.=<<___;
 .align 4
 ___
 
-$code =~ s/\`([^\`]*)\`/eval $1/gem;
-print $code;
+# Purpose of these subroutines is to explicitly encode VIS instructions,
+# so that one can compile the module without having to specify VIS
+# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
+# Idea is to reserve for option to produce "universal" binary and let
+# programmer detect if current CPU is VIS capable at run-time.
+sub unvis {
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my $ref,$opf;
+my %visopf = ( "faligndata"    => 0x048,
+               "for"           => 0x07c        );
+
+    $ref = "$mnemonic\t$rs1,$rs2,$rd";
+
+    if ($opf=$visopf{$mnemonic}) {
+       foreach ($rs1,$rs2,$rd) {
+           return $ref if (!/%f([0-9]{1,2})/);
+           $_=$1;
+           if ($1>=32) {
+               return $ref if ($1&1);
+               # re-encode for upper double register addressing
+               $_=($1|$1>>5)&31;
+           }
+       }
+
+       return  sprintf ".word\t0x%08x !%s",
+                       0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
+                       $ref;
+    } else {
+       return $ref;
+    }
+}
+sub unalignaddr {
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
+my $ref="$mnemonic\t$rs1,$rs2,$rd";
+
+    foreach ($rs1,$rs2,$rd) {
+       if (/%([goli])([0-7])/) { $_=$bias{$1}+$2; }
+       else                    { return $ref; }
+    }
+    return  sprintf ".word\t0x%08x !%s",
+                   0x81b00300|$rd<<25|$rs1<<14|$rs2,
+                   $ref;
+}
+
+foreach (split("\n",$code)) {
+       s/\`([^\`]*)\`/eval $1/ge;
+
+       s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
+               &unvis($1,$2,$3,$4)
+        /ge;
+       s/\b(alignaddr)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
+               &unalignaddr($1,$2,$3,$4)
+        /ge;
+
+       print $_,"\n";
+}
+
 close STDOUT;