# vectorized Xupdate on MIPSIII/IV, but the goal was to code MIPS32-
# compatible subroutine. There is room for minor optimization on
# little-endian platforms...
+
+# September 2012.
+#
+# Add MIPS32r2 code (>25% less instructions).
+
+######################################################################
+# There is a number of MIPS ABI in use, O32 and N32/64 are most
+# widely used. Then there is a new contender: NUBI. It appears that if
+# one picks the latter, it's possible to arrange code in ABI neutral
+# manner. Therefore let's stick to NUBI register layout:
+#
+($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
+($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
+($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
+($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
+#
+# The return value is placed in $a0. Following coding rules facilitate
+# interoperability:
+#
+# - never ever touch $tp, "thread pointer", former $gp;
+# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
+# old code];
+# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
+#
+# For reference here is register layout for N32/64 MIPS ABIs:
+#
+# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
+# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
+# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
+# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
+# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
+#
+$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
+
+if ($flavour =~ /64|n32/i) {
+ $PTR_ADD="dadd"; # incidentally works even on n32
+ $PTR_SUB="dsub"; # incidentally works even on n32
+ $REG_S="sd";
+ $REG_L="ld";
+ $PTR_SLL="dsll"; # incidentally works even on n32
+ $SZREG=8;
+} else {
+ $PTR_ADD="add";
+ $PTR_SUB="sub";
+ $REG_S="sw";
+ $REG_L="lw";
+ $PTR_SLL="sll";
+ $SZREG=4;
+}
+#
+# <appro@openssl.org>
#
-# The code is somewhat IRIX-centric, i.e. is likely to require minor
-# adaptations for other OSes...
+######################################################################
+
+$big_endian=(`echo MIPSEL | $ENV{CC} -E -`=~/MIPSEL/)?1:0 if ($ENV{CC});
+
+for (@ARGV) { $output=$_ if (/\w[\w\-]*\.\w+$/); }
+open STDOUT,">$output";
-for (@ARGV) { $big_endian=1 if (/\-DB_ENDIAN/);
- $big_endian=0 if (/\-DL_ENDIAN/); }
if (!defined($big_endian))
{ $big_endian=(unpack('L',pack('N',1))==1); }
$MSB=$big_endian?0:3;
$LSB=3&~$MSB;
-@X=( "\$8", "\$9", "\$10", "\$11", "\$12", "\$13", "\$14", "\$15",
- "\$16", "\$17", "\$18", "\$19", "\$20", "\$21", "\$22", "\$23");
-$ctx="\$4"; # a0
-$inp="\$5"; # a1
-$num="\$6"; # a2
+@X=map("\$$_",(8..23)); # a4-a7,s0-s11
+
+$ctx=$a0;
+$inp=$a1;
+$num=$a2;
$A="\$1";
$B="\$2";
$C="\$3";
$D="\$7";
$E="\$24"; @V=($A,$B,$C,$D,$E);
-$t0="\$25"; # jp,t9
-$t1="\$28"; # gp
-$t2="\$30"; # fp,s8
+$t0="\$25";
+$t1=$num; # $num is offloaded to stack
+$t2="\$30"; # fp
$K="\$31"; # ra
-$FRAMESIZE=16;
-
sub BODY_00_14 {
my ($i,$a,$b,$c,$d,$e)=@_;
my $j=$i+1;
$code.=<<___ if (!$big_endian);
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ wsbh @X[$i],@X[$i] # byte swap($i)
+ rotr @X[$i],@X[$i],16
+#else
srl $t0,@X[$i],24 # byte swap($i)
srl $t1,@X[$i],8
andi $t2,@X[$i],0xFF00
andi $t1,0xFF00
sll $t2,$t2,8
or @X[$i],$t0
+ or $t1,$t2
or @X[$i],$t1
- or @X[$i],$t2
+#endif
___
$code.=<<___;
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ addu $e,$K # $i
+ xor $t0,$c,$d
+ rotr $t1,$a,27
+ lwl @X[$j],$j*4+$MSB($inp)
+ and $t0,$b
+ addu $e,$t1
+ lwr @X[$j],$j*4+$LSB($inp)
+ xor $t0,$d
+ addu $e,@X[$i]
+ rotr $b,$b,2
+ addu $e,$t0
+#else
lwl @X[$j],$j*4+$MSB($inp)
sll $t0,$a,5 # $i
addu $e,$K
addu $e,@X[$i]
or $b,$t2
addu $e,$t0
+#endif
___
}
my $j=$i+1;
$code.=<<___ if (!$big_endian && $i==15);
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ wsbh @X[$i],@X[$i] # byte swap($i)
+ rotr @X[$i],@X[$i],16
+#else
srl $t0,@X[$i],24 # byte swap($i)
srl $t1,@X[$i],8
andi $t2,@X[$i],0xFF00
or @X[$i],$t0
or @X[$i],$t1
or @X[$i],$t2
+#endif
___
$code.=<<___;
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ addu $e,$K # $i
+ xor @X[$j%16],@X[($j+2)%16]
+ xor $t0,$c,$d
+ rotr $t1,$a,27
+ xor @X[$j%16],@X[($j+8)%16]
+ and $t0,$b
+ addu $e,$t1
+ xor @X[$j%16],@X[($j+13)%16]
+ xor $t0,$d
+ addu $e,@X[$i%16]
+ rotr @X[$j%16],@X[$j%16],31
+ rotr $b,$b,2
+ addu $e,$t0
+#else
xor @X[$j%16],@X[($j+2)%16]
sll $t0,$a,5 # $i
addu $e,$K
addu $e,@X[$i%16]
or $b,$t2
addu $e,$t0
+#endif
___
}
my ($i,$a,$b,$c,$d,$e)=@_;
my $j=$i+1;
$code.=<<___ if ($i<79);
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ xor @X[$j%16],@X[($j+2)%16]
+ addu $e,$K # $i
+ rotr $t1,$a,27
+ xor @X[$j%16],@X[($j+8)%16]
+ xor $t0,$c,$d
+ addu $e,$t1
+ xor @X[$j%16],@X[($j+13)%16]
+ xor $t0,$b
+ addu $e,@X[$i%16]
+ rotr @X[$j%16],@X[$j%16],31
+ rotr $b,$b,2
+ addu $e,$t0
+#else
xor @X[$j%16],@X[($j+2)%16]
sll $t0,$a,5 # $i
addu $e,$K
or @X[$j%16],$t1
or $b,$t2
addu $e,$t0
+#endif
___
$code.=<<___ if ($i==79);
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ lw @X[0],0($ctx)
+ addu $e,$K # $i
+ lw @X[1],4($ctx)
+ rotr $t1,$a,27
+ lw @X[2],8($ctx)
+ xor $t0,$c,$d
+ addu $e,$t1
+ lw @X[3],12($ctx)
+ xor $t0,$b
+ addu $e,@X[$i%16]
+ lw @X[4],16($ctx)
+ rotr $b,$b,2
+ addu $e,$t0
+#else
lw @X[0],0($ctx)
sll $t0,$a,5 # $i
addu $e,$K
addu $e,@X[$i%16]
or $b,$t2
addu $e,$t0
+#endif
___
}
my ($i,$a,$b,$c,$d,$e)=@_;
my $j=$i+1;
$code.=<<___ if ($i<79);
+#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
+ addu $e,$K # $i
+ and $t0,$c,$d
+ xor @X[$j%16],@X[($j+2)%16]
+ rotr $t1,$a,27
+ addu $e,$t0
+ xor @X[$j%16],@X[($j+8)%16]
+ xor $t0,$c,$d
+ addu $e,$t1
+ xor @X[$j%16],@X[($j+13)%16]
+ and $t0,$b
+ addu $e,@X[$i%16]
+ rotr @X[$j%16],@X[$j%16],31
+ rotr $b,$b,2
+ addu $e,$t0
+#else
xor @X[$j%16],@X[($j+2)%16]
sll $t0,$a,5 # $i
addu $e,$K
addu $e,@X[$i%16]
or $b,$t2
addu $e,$t0
+#endif
___
}
+$FRAMESIZE=16; # large enough to accommodate NUBI saved registers
+$SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0xc0fff008" : "0xc0ff0000";
+
$code=<<___;
-#include <asm.h>
-#include <regdef.h>
+#ifdef OPENSSL_FIPSCANISTER
+# include <openssl/fipssyms.h>
+#endif
+
+#if defined(__mips_smartmips) && !defined(_MIPS_ARCH_MIPS32R2)
+#define _MIPS_ARCH_MIPS32R2
+#endif
.text
.globl sha1_block_data_order
.ent sha1_block_data_order
sha1_block_data_order:
- .frame sp,$FRAMESIZE*SZREG,zero
- .mask 0xd0ff0000,-$FRAMESIZE*SZREG
+ .frame $sp,$FRAMESIZE*$SZREG,$ra
+ .mask $SAVED_REGS_MASK,-$SZREG
.set noreorder
- PTR_SUB sp,$FRAMESIZE*SZREG
- REG_S \$31,($FRAMESIZE-1)*SZREG(sp)
- REG_S \$30,($FRAMESIZE-2)*SZREG(sp)
- REG_S \$28,($FRAMESIZE-3)*SZREG(sp)
- REG_S \$23,($FRAMESIZE-4)*SZREG(sp)
- REG_S \$22,($FRAMESIZE-5)*SZREG(sp)
- REG_S \$21,($FRAMESIZE-6)*SZREG(sp)
- REG_S \$20,($FRAMESIZE-7)*SZREG(sp)
- REG_S \$19,($FRAMESIZE-8)*SZREG(sp)
- REG_S \$18,($FRAMESIZE-9)*SZREG(sp)
- REG_S \$17,($FRAMESIZE-10)*SZREG(sp)
- REG_S \$16,($FRAMESIZE-11)*SZREG(sp)
-
+ $PTR_SUB $sp,$FRAMESIZE*$SZREG
+ $REG_S $ra,($FRAMESIZE-1)*$SZREG($sp)
+ $REG_S $fp,($FRAMESIZE-2)*$SZREG($sp)
+ $REG_S $s11,($FRAMESIZE-3)*$SZREG($sp)
+ $REG_S $s10,($FRAMESIZE-4)*$SZREG($sp)
+ $REG_S $s9,($FRAMESIZE-5)*$SZREG($sp)
+ $REG_S $s8,($FRAMESIZE-6)*$SZREG($sp)
+ $REG_S $s7,($FRAMESIZE-7)*$SZREG($sp)
+ $REG_S $s6,($FRAMESIZE-8)*$SZREG($sp)
+ $REG_S $s5,($FRAMESIZE-9)*$SZREG($sp)
+ $REG_S $s4,($FRAMESIZE-10)*$SZREG($sp)
+___
+$code.=<<___ if ($flavour =~ /nubi/i); # optimize non-nubi prologue
+ $REG_S $s3,($FRAMESIZE-11)*$SZREG($sp)
+ $REG_S $s2,($FRAMESIZE-12)*$SZREG($sp)
+ $REG_S $s1,($FRAMESIZE-13)*$SZREG($sp)
+ $REG_S $s0,($FRAMESIZE-14)*$SZREG($sp)
+ $REG_S $gp,($FRAMESIZE-15)*$SZREG($sp)
+___
+$code.=<<___;
+ $PTR_SLL $num,6
+ $PTR_ADD $num,$inp
+ $REG_S $num,0($sp)
lw $A,0($ctx)
lw $B,4($ctx)
lw $C,8($ctx)
___
for (;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
$code.=<<___;
+ $PTR_ADD $inp,64
+ $REG_L $num,0($sp)
+
addu $A,$X[0]
addu $B,$X[1]
sw $A,0($ctx)
addu $D,$X[3]
sw $B,4($ctx)
addu $E,$X[4]
- PTR_SUB $num,1
sw $C,8($ctx)
sw $D,12($ctx)
sw $E,16($ctx)
.set noreorder
- bnez $num,.Loop
- PTR_ADD $inp,64
+ bne $inp,$num,.Loop
+ nop
.set noreorder
- REG_L \$31,($FRAMESIZE-1)*SZREG(sp)
- REG_L \$30,($FRAMESIZE-2)*SZREG(sp)
- REG_L \$28,($FRAMESIZE-3)*SZREG(sp)
- REG_L \$23,($FRAMESIZE-4)*SZREG(sp)
- REG_L \$22,($FRAMESIZE-5)*SZREG(sp)
- REG_L \$21,($FRAMESIZE-6)*SZREG(sp)
- REG_L \$20,($FRAMESIZE-7)*SZREG(sp)
- REG_L \$19,($FRAMESIZE-8)*SZREG(sp)
- REG_L \$18,($FRAMESIZE-9)*SZREG(sp)
- REG_L \$17,($FRAMESIZE-10)*SZREG(sp)
- REG_L \$16,($FRAMESIZE-11)*SZREG(sp)
- jr ra
- PTR_ADD sp,$FRAMESIZE*SZREG
+ $REG_L $ra,($FRAMESIZE-1)*$SZREG($sp)
+ $REG_L $fp,($FRAMESIZE-2)*$SZREG($sp)
+ $REG_L $s11,($FRAMESIZE-3)*$SZREG($sp)
+ $REG_L $s10,($FRAMESIZE-4)*$SZREG($sp)
+ $REG_L $s9,($FRAMESIZE-5)*$SZREG($sp)
+ $REG_L $s8,($FRAMESIZE-6)*$SZREG($sp)
+ $REG_L $s7,($FRAMESIZE-7)*$SZREG($sp)
+ $REG_L $s6,($FRAMESIZE-8)*$SZREG($sp)
+ $REG_L $s5,($FRAMESIZE-9)*$SZREG($sp)
+ $REG_L $s4,($FRAMESIZE-10)*$SZREG($sp)
+___
+$code.=<<___ if ($flavour =~ /nubi/i);
+ $REG_L $s3,($FRAMESIZE-11)*$SZREG($sp)
+ $REG_L $s2,($FRAMESIZE-12)*$SZREG($sp)
+ $REG_L $s1,($FRAMESIZE-13)*$SZREG($sp)
+ $REG_L $s0,($FRAMESIZE-14)*$SZREG($sp)
+ $REG_L $gp,($FRAMESIZE-15)*$SZREG($sp)
+___
+$code.=<<___;
+ jr $ra
+ $PTR_ADD $sp,$FRAMESIZE*$SZREG
.end sha1_block_data_order
+.rdata
+.asciiz "SHA1 for MIPS, CRYPTOGAMS by <appro\@openssl.org>"
___
print $code;
close STDOUT;