+20% performance improvement of P4-specific RC4_CHAR loop.
[openssl.git] / crypto / rc4 / asm / rc4-586.pl
index dbe3803f55b018c90baf5d2c0f5ac811d71896e8..22bda4b451e9915297177780599499e5f22ec624 100644 (file)
@@ -1,6 +1,27 @@
 #!/usr/local/bin/perl
 
-# define for pentium pro friendly version
+# At some point it became apparent that the original SSLeay RC4
+# assembler implementation performs suboptimaly on latest IA-32
+# microarchitectures. After re-tuning performance has changed as
+# following:
+#
+# Pentium      +0%
+# Pentium III  +17%
+# AMD          +52%(*)
+# P4           +180%(**)
+#
+# (*)  This number is actually a trade-off:-) It's possible to
+#      achieve +72%, but at the cost of -48% off PIII performance.
+#      In other words code performing further 13% faster on AMD
+#      would perform almost 2 times slower on Intel PIII...
+#      For reference! This code delivers ~80% of rc4-amd64.pl
+#      performance on the same Opteron machine.
+# (**) This number requires compressed key schedule set up by
+#      RC4_set_key and therefore doesn't apply to 0.9.7 [option for
+#      compressed key schedule is implemented in 0.9.8 and later,
+#      see commentary section in rc4_skey.c for further details].
+#
+#                                      <appro@fy.chalmers.se>
 
 push(@INC,"perlasm","../../perlasm");
 require "x86asm.pl";
@@ -46,20 +67,16 @@ sub RC4_loop
        # Moved out
        # &mov( $tx,            &DWP(0,$d,$x,4)) if $p < 0;
 
-        &add(  $y,             $tx);
-       &and(   $y,             0xff);
-        &inc(  $x);                    # NEXT ROUND 
+       &add(   &LB($y),        &LB($tx));
        &mov(   $ty,            &DWP(0,$d,$y,4));
         # XXX
-       &mov(   &DWP(-4,$d,$x,4),$ty);                  # AGI
+       &mov(   &DWP(0,$d,$x,4),$ty);
         &add(  $ty,            $tx);
-       &and(   $x,             0xff);  # NEXT ROUND
-        &and(  $ty,            0xff);
        &mov(   &DWP(0,$d,$y,4),$tx);
-        &nop();
-       &mov(   $ty,            &DWP(0,$d,$ty,4));
-        &mov(  $tx,            &DWP(0,$d,$x,4)) if $p < 1; # NEXT ROUND
-        # XXX
+        &and(  $ty,            0xff);
+        &inc(  &LB($x));                       # NEXT ROUND
+       &mov(   $tx,            &DWP(0,$d,$x,4)) if $p < 1; # NEXT ROUND
+        &mov(  $ty,            &DWP(0,$d,$ty,4));
 
        if (!$char)
                {
@@ -99,21 +116,24 @@ sub RC4
        &push("ebp");
         &push("ebx");
        &push("esi");
-        &push("edi");
+        &xor(  $x,     $x);            # avoid partial register stalls
+       &push("edi");
+        &xor(  $y,     $y);            # avoid partial register stalls
        &mov(   $d,     &wparam(0));    # key
         &mov(  $in,    &wparam(2));
 
-       &mov(   $x,     &DWP(0,$d,"",1));
-        &mov(  $y,     &DWP(4,$d,"",1));
+       &movb(  &LB($x),        &BP(0,$d,"",1));
+        &movb( &LB($y),        &BP(4,$d,"",1));
 
        &mov(   $out,   &wparam(3));
-        &inc(  $x);
+        &inc(  &LB($x));
 
        &stack_push(3); # 3 temp variables
         &add(  $d,     8);
-       &and(   $x,             0xff);
 
        # detect compressed schedule, see commentary section in rc4_skey.c...
+       # in 0.9.7 context ~50 bytes below RC4_CHAR label remain redundant,
+       # as compressed key schedule is set up in 0.9.8 and later.
        &cmp(&DWP(256,$d),-1);
        &je(&label("RC4_CHAR"));
 
@@ -174,33 +194,35 @@ sub RC4
        &jmp(&label("finished"));
 
        &align(16);
-       # this is essentially Intel P4 specific codepath, see rc4_skey.c...
+       # this is essentially Intel P4 specific codepath, see rc4_skey.c,
+       # and is engaged in 0.9.8 and later context...
        &set_label("RC4_CHAR");
 
        &lea    ($ty,&DWP(0,$in,$ty));
        &mov    (&swtmp(2),$ty);
+       &movz   ($tx,&BP(0,$d,$x));
 
        # strangely enough unrolled loop performs over 20% slower...
        &set_label("RC4_CHAR_loop");
-               &movz   ($tx,&BP(0,$d,$x));
                &add    (&LB($y),&LB($tx));
                &movz   ($ty,&BP(0,$d,$y));
                &movb   (&BP(0,$d,$y),&LB($tx));
                &movb   (&BP(0,$d,$x),&LB($ty));
                &add    (&LB($ty),&LB($tx));
                &movz   ($ty,&BP(0,$d,$ty));
+               &add    (&LB($x),1);
                &xorb   (&LB($ty),&BP(0,$in));
-               &movb   (&BP(0,$out),&LB($ty));
-               &inc    (&LB($x));
-               &inc    ($in);
-               &inc    ($out);
+               &lea    ($in,&BP(1,$in));
+               &movz   ($tx,&BP(0,$d,$x));
                &cmp    ($in,&swtmp(2));
+               &movb   (&BP(0,$out),&LB($ty));
+               &lea    ($out,&BP(1,$out));
        &jb     (&label("RC4_CHAR_loop"));
 
        &set_label("finished");
        &dec(   $x);
         &stack_pop(3);
-       &mov(   &DWP(-4,$d,"",0),$y);
+       &movb(  &BP(-4,$d,"",0),&LB($y));
         &movb( &BP(-8,$d,"",0),&LB($x));
 
        &function_end($name);