~ubuntu-branches/ubuntu/maverick/openssl/maverick

« back to all changes in this revision

Viewing changes to crypto/rc4/asm/rc4-ia64.S

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2005-12-13 21:37:42 UTC
  • mto: (11.1.1 lenny)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20051213213742-d0ydaylf80l16bj1
Tags: upstream-0.9.8a
ImportĀ upstreamĀ versionĀ 0.9.8a

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ====================================================================
 
2
// Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
 
3
// project.
 
4
//
 
5
// Rights for redistribution and usage in source and binary forms are
 
6
// granted according to the OpenSSL license. Warranty of any kind is
 
7
// disclaimed.
 
8
// ====================================================================
 
9
 
 
10
.ident  "rc4-ia64.S, Version 2.0"
 
11
.ident  "IA-64 ISA artwork by Andy Polyakov <appro@fy.chalmers.se>"
 
12
 
 
13
// What's wrong with compiler generated code? Because of the nature of
 
14
// C language, compiler doesn't [dare to] reorder load and stores. But
 
15
// being memory-bound, RC4 should benefit from reorder [on in-order-
 
16
// execution core such as IA-64]. But what can we reorder? At the very
 
17
// least we can safely reorder references to key schedule in respect
 
18
// to input and output streams. Secondly, from the first [close] glance
 
19
// it appeared that it's possible to pull up some references to
 
20
// elements of the key schedule itself. Original rationale ["prior
 
21
// loads are not safe only for "degenerated" key schedule, when some
 
22
// elements equal to the same value"] was kind of sloppy. I should have
 
23
// formulated as it really was: if we assume that pulling up reference
 
24
// to key[x+1] is not safe, then it would mean that key schedule would
 
25
// "degenerate," which is never the case. The problem is that this
 
26
// holds true in respect to references to key[x], but not to key[y].
 
27
// Legitimate "collisions" do occur within every 256^2 bytes window.
 
28
// Fortunately there're enough free instruction slots to keep prior
 
29
// reference to key[x+1], detect "collision" and compensate for it.
 
30
// All this without sacrificing a single clock cycle:-) Throughput is
 
31
// ~210MBps on 900MHz CPU, which is is >3x faster than gcc generated
 
32
// code and +30% - if compared to HP-UX C. Unrolling loop below should
 
33
// give >30% on top of that...
 
34
 
 
35
.text
 
36
.explicit
 
37
 
 
38
#if defined(_HPUX_SOURCE) && !defined(_LP64)
 
39
# define ADDP   addp4
 
40
#else
 
41
# define ADDP   add
 
42
#endif
 
43
 
 
44
#ifndef SZ
 
45
#define SZ      4       // this is set to sizeof(RC4_INT)
 
46
#endif
 
47
// SZ==4 seems to be optimal. At least SZ==8 is not any faster, not for
 
48
// assembler implementation, while SZ==1 code is ~30% slower.
 
49
#if SZ==1       // RC4_INT is unsigned char
 
50
# define        LDKEY   ld1
 
51
# define        STKEY   st1
 
52
# define        OFF     0
 
53
#elif SZ==4     // RC4_INT is unsigned int
 
54
# define        LDKEY   ld4
 
55
# define        STKEY   st4
 
56
# define        OFF     2
 
57
#elif SZ==8     // RC4_INT is unsigned long
 
58
# define        LDKEY   ld8
 
59
# define        STKEY   st8
 
60
# define        OFF     3
 
61
#endif
 
62
 
 
63
out=r8;         // [expanded] output pointer
 
64
inp=r9;         // [expanded] output pointer
 
65
prsave=r10;
 
66
key=r28;        // [expanded] pointer to RC4_KEY
 
67
ksch=r29;       // (key->data+255)[&~(sizeof(key->data)-1)]
 
68
xx=r30;
 
69
yy=r31;
 
70
 
 
71
// void RC4(RC4_KEY *key,size_t len,const void *inp,void *out);
 
72
.global RC4#
 
73
.proc   RC4#
 
74
.align  32
 
75
.skip   16
 
76
RC4:
 
77
        .prologue
 
78
        .fframe 0
 
79
        .save   ar.pfs,r2
 
80
        .save   ar.lc,r3
 
81
        .save   pr,prsave
 
82
{ .mii; alloc   r2=ar.pfs,4,12,0,16
 
83
        mov     prsave=pr
 
84
        ADDP    key=0,in0               };;
 
85
{ .mib; cmp.eq  p6,p0=0,in1                     // len==0?
 
86
        mov     r3=ar.lc
 
87
(p6)    br.ret.spnt.many        b0      };;     // emergency exit
 
88
 
 
89
        .body
 
90
        .rotr   dat[4],key_x[4],tx[2],rnd[2],key_y[2],ty[1];
 
91
 
 
92
{ .mib; LDKEY   xx=[key],SZ                     // load key->x
 
93
        add     in1=-1,in1                      // adjust len for loop counter
 
94
        nop.b   0                       }
 
95
{ .mib; ADDP    inp=0,in2
 
96
        ADDP    out=0,in3
 
97
        brp.loop.imp    .Ltop,.Lexit-16 };;
 
98
{ .mmi; LDKEY   yy=[key]                        // load key->y
 
99
        add     ksch=SZ,key
 
100
        mov     ar.lc=in1               }
 
101
{ .mmi; mov     key_y[1]=r0                     // guarantee inequality
 
102
                                                // in first iteration
 
103
        add     xx=1,xx
 
104
        mov     pr.rot=1<<16            };;
 
105
{ .mii; nop.m   0
 
106
        dep     key_x[1]=xx,r0,OFF,8
 
107
        mov     ar.ec=3                 };;     // note that epilogue counter
 
108
                                                // is off by 1. I compensate
 
109
                                                // for this at exit...
 
110
.Ltop:
 
111
// The loop is scheduled for 4*(n+2) spin-rate on Itanium 2, which
 
112
// theoretically gives asymptotic performance of clock frequency
 
113
// divided by 4 bytes per seconds, or 400MBps on 1.6GHz CPU. This is
 
114
// for sizeof(RC4_INT)==4. For smaller RC4_INT STKEY inadvertently
 
115
// splits the last bundle and you end up with 5*n spin-rate:-(
 
116
// Originally the loop was scheduled for 3*n and relied on key
 
117
// schedule to be aligned at 256*sizeof(RC4_INT) boundary. But
 
118
// *(out++)=dat, which maps to st1, had same effect [inadvertent
 
119
// bundle split] and holded the loop back. Rescheduling for 4*n
 
120
// made it possible to eliminate dependence on specific alignment
 
121
// and allow OpenSSH keep "abusing" our API. Reaching for 3*n would
 
122
// require unrolling, sticking to variable shift instruction for
 
123
// collecting output [to avoid starvation for integer shifter] and
 
124
// copying of key schedule to controlled place in stack [so that
 
125
// deposit instruction can serve as substitute for whole
 
126
// key->data+((x&255)<<log2(sizeof(key->data[0])))]...
 
127
{ .mmi; (p19)   st1     [out]=dat[3],1                  // *(out++)=dat
 
128
        (p16)   add     xx=1,xx                         // x++
 
129
        (p18)   dep     rnd[1]=rnd[1],r0,OFF,8  }       // ((tx+ty)&255)<<OFF
 
130
{ .mmi; (p16)   add     key_x[1]=ksch,key_x[1]          // &key[xx&255]
 
131
        (p17)   add     key_y[1]=ksch,key_y[1]  };;     // &key[yy&255] 
 
132
{ .mmi; (p16)   LDKEY   tx[0]=[key_x[1]]                // tx=key[xx]
 
133
        (p17)   LDKEY   ty[0]=[key_y[1]]                // ty=key[yy]   
 
134
        (p16)   dep     key_x[0]=xx,r0,OFF,8    }       // (xx&255)<<OFF
 
135
{ .mmi; (p18)   add     rnd[1]=ksch,rnd[1]              // &key[(tx+ty)&255]
 
136
        (p16)   cmp.ne.unc p20,p21=key_x[1],key_y[1] };;
 
137
{ .mmi; (p18)   LDKEY   rnd[1]=[rnd[1]]                 // rnd=key[(tx+ty)&255]
 
138
        (p16)   ld1     dat[0]=[inp],1          }       // dat=*(inp++)
 
139
.pred.rel       "mutex",p20,p21
 
140
{ .mmi; (p21)   add     yy=yy,tx[1]                     // (p16)
 
141
        (p20)   add     yy=yy,tx[0]                     // (p16) y+=tx
 
142
        (p21)   mov     tx[0]=tx[1]             };;     // (p16)
 
143
{ .mmi; (p17)   STKEY   [key_y[1]]=tx[1]                // key[yy]=tx
 
144
        (p17)   STKEY   [key_x[2]]=ty[0]                // key[xx]=ty
 
145
        (p16)   dep     key_y[0]=yy,r0,OFF,8    }       // &key[yy&255]
 
146
{ .mmb; (p17)   add     rnd[0]=tx[1],ty[0]              // tx+=ty
 
147
        (p18)   xor     dat[2]=dat[2],rnd[1]            // dat^=rnd
 
148
        br.ctop.sptk    .Ltop                   };;
 
149
.Lexit:
 
150
{ .mib; STKEY   [key]=yy,-SZ                    // save key->y
 
151
        mov     pr=prsave,0x1ffff
 
152
        nop.b   0                       }
 
153
{ .mib; st1     [out]=dat[3],1                  // compensate for truncated
 
154
                                                // epilogue counter
 
155
        add     xx=-1,xx
 
156
        nop.b   0                       };;
 
157
{ .mib; STKEY   [key]=xx                        // save key->x
 
158
        mov     ar.lc=r3
 
159
        br.ret.sptk.many        b0      };;
 
160
.endp   RC4#