From e66055b8f7db68c4ecdd01c13f2b3bd9f91c833e Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Fri, 28 Sep 2012 09:34:09 +0000 Subject: [PATCH] md5-sparcv9.pl: add hardware SPARC T4 support. Submitted by: David Miller --- crypto/md5/asm/md5-sparcv9.pl | 151 +++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/crypto/md5/asm/md5-sparcv9.pl b/crypto/md5/asm/md5-sparcv9.pl index 7f53e78a47..5875779101 100644 --- a/crypto/md5/asm/md5-sparcv9.pl +++ b/crypto/md5/asm/md5-sparcv9.pl @@ -5,11 +5,18 @@ # 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 . # ==================================================================== # MD5 for SPARCv9, 6.9 cycles per byte on UltraSPARC, >40% faster than # code generated by Sun C 5.2. +# SPARC T4 MD5 hardware achieves 3.24 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. + $bits=32; for (@ARGV) { $bits=64 if (/\-m64/ || /\-xarch\=v9/); } if ($bits==64) { $bias=2047; $frame=192; } @@ -196,11 +203,95 @@ $code.=<<___ if ($bits==64); .register %g3,#scratch ___ $code.=<<___; +#include "sparc_arch.h" + .section ".text",#alloc,#execinstr +#ifdef __PIC__ +SPARC_PIC_THUNK(%g1) +#endif + .globl md5_block_asm_data_order .align 32 md5_block_asm_data_order: + 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 + + rd %asi, %g5 + wr %g0, 0x88, %asi ! ASI_PRIMARY_LITTLE + + lda [%o0 + 0x00] %asi, %f0 ! load context + lda [%o0 + 0x04] %asi, %f1 + andcc %o1, 0x7, %g0 + lda [%o0 + 0x08] %asi, %f2 + bne,pn %icc, .Lhwunaligned + lda [%o0 + 0x0c] %asi, %f3 + +.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 + + .word 0x81b02800 ! MD5 + + bne,pt `$bits==64?"%xcc":"%icc"`, .Lhw_loop + nop + +.Lhwfinish: + sta %f0, [%o0 + 0x00] %asi ! store context + sta %f1, [%o0 + 0x04] %asi + sta %f2, [%o0 + 0x08] %asi + sta %f3, [%o0 + 0x0c] %asi + retl + wr %g5, 0x0, %asi ! restore %asi + +.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 + + 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 `$bits==64?"%xcc":"%icc"`, .Lhwunaligned_loop + for %f26, %f26, %f10 ! %f10=%f26 + + ba .Lhwfinish + nop + +.align 16 +.Lsoftware: save %sp,-$frame,%sp rd %asi,$saved_asi @@ -279,6 +370,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 +# extentions 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; -- 2.34.1