RC4 tune-up for Intel P4 core, both 32- and 64-bit ones. As it's
[openssl.git] / crypto / rc4 / asm / rc4-amd64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. Rights for redistribution and usage in source and binary
6 # forms are granted according to the OpenSSL license.
7 # ====================================================================
8 #
9 # 2.22x RC4 tune-up:-) It should be noted though that my hand [as in
10 # "hand-coded assembler"] doesn't stand for the whole improvement
11 # coefficient. It turned out that eliminating RC4_CHAR from config
12 # line results in ~40% improvement (yes, even for C implementation).
13 # Presumably it has everything to do with AMD cache architecture and
14 # RAW or whatever penalties. Once again! The module *requires* config
15 # line *without* RC4_CHAR! As for coding "secret," I bet on partial
16 # register arithmetics. For example instead of 'inc %r8; and $255,%r8'
17 # I simply 'inc %r8b'. Even though optimization manual discourages
18 # to operate on partial registers, it turned out to be the best bet.
19 # At least for AMD... How IA32E would perform remains to be seen...
20
21 # As was shown by Marc Bevand reordering of couple of load operations
22 # results in even higher performance gain of 3.3x:-) At least on
23 # Opteron... For reference, 1x in this case is RC4_CHAR C-code
24 # compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock.
25 # Latter means that if you want to *estimate* what to expect from
26 # *your* CPU, then multiply 54 by 3.3 and clock frequency in GHz.
27
28 # Intel P4 EM64T core was found to run the AMD64 code really slow...
29 # The only way to achieve comparable performance on P4 is to keep
30 # RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to
31 # compose blended code, which would perform even within 30% marginal
32 # on either AMD and Intel platforms, I implement both cases. See
33 # rc4_skey.c for further details...
34
35 $output=shift;
36
37 $win64a=1 if ($output =~ /win64a.[s|asm]/);
38
39 open STDOUT,">$output" || die "can't open $output: $!";
40
41 if (defined($win64a)) {
42     $dat="%rcx";        # arg1
43     $len="%rdx";        # arg2
44     $inp="%rsi";        # r8, arg3 moves here
45     $out="%rdi";        # r9, arg4 moves here
46 } else {
47     $dat="%rdi";        # arg1
48     $len="%rsi";        # arg2
49     $inp="%rdx";        # arg3
50     $out="%rcx";        # arg4
51 }
52
53 $XX="%r10";
54 $TX="%r8";
55 $YY="%r11";
56 $TY="%r9";
57
58 sub PTR() {
59     my $ret=shift;
60     if (defined($win64a)) {
61         $ret =~ s/\[([\S]+)\+([\S]+)\]/[$2+$1]/g;   # [%rN+%rM*4]->[%rM*4+%rN]
62         $ret =~ s/:([^\[]+)\[([^\]]+)\]/:[$2+$1]/g; # :off[ea]->:[ea+off]
63     } else {
64         $ret =~ s/[\+\*]/,/g;           # [%rN+%rM*4]->[%rN,%rM,4]
65         $ret =~ s/\[([^\]]+)\]/($1)/g;  # [%rN]->(%rN)
66     }
67     $ret;
68 }
69
70 $code=<<___ if (!defined($win64a));
71 .text
72
73 .globl  RC4
74 .type   RC4,\@function
75 .align  16
76 RC4:    or      $len,$len
77         jne     .Lentry
78         repret
79 .Lentry:
80 ___
81 $code=<<___ if (defined($win64a));
82 _TEXT   SEGMENT
83 PUBLIC  RC4
84 ALIGN   16
85 RC4     PROC
86         or      $len,$len
87         jne     .Lentry
88         repret
89 .Lentry:
90         push    %rdi
91         push    %rsi
92         sub     \$40,%rsp
93         mov     %r8,$inp
94         mov     %r9,$out
95 ___
96 $code.=<<___;
97         add     \$8,$dat
98         movl    `&PTR("DWORD:-8[$dat]")`,$XX#d
99         movl    `&PTR("DWORD:-4[$dat]")`,$YY#d
100         cmpl    \$-1,`&PTR("DWORD:256[$dat]")`
101         je      .LRC4_CHAR
102         test    \$-8,$len
103         jz      .Lloop1
104 .align  16
105 .Lloop8:
106         inc     $XX#b
107         movl    `&PTR("DWORD:[$dat+$XX*4]")`,$TX#d
108         add     $TX#b,$YY#b
109         movl    `&PTR("DWORD:[$dat+$YY*4]")`,$TY#d
110         movl    $TX#d,`&PTR("DWORD:[$dat+$YY*4]")`
111         movl    $TY#d,`&PTR("DWORD:[$dat+$XX*4]")`
112         add     $TX#b,$TY#b
113         inc     $XX#b
114         movl    `&PTR("DWORD:[$dat+$XX*4]")`,$TX#d
115         movb    `&PTR("BYTE:[$dat+$TY*4]")`,%al
116 ___
117 for ($i=1;$i<=6;$i++) {
118 $code.=<<___;
119         add     $TX#b,$YY#b
120         ror     \$8,%rax
121         movl    `&PTR("DWORD:[$dat+$YY*4]")`,$TY#d
122         movl    $TX#d,`&PTR("DWORD:[$dat+$YY*4]")`
123         movl    $TY#d,`&PTR("DWORD:[$dat+$XX*4]")`
124         add     $TX#b,$TY#b
125         inc     $XX#b
126         movl    `&PTR("DWORD:[$dat+$XX*4]")`,$TX#d
127         movb    `&PTR("BYTE:[$dat+$TY*4]")`,%al
128 ___
129 }
130 $code.=<<___;
131         add     $TX#b,$YY#b
132         ror     \$8,%rax
133         movl    `&PTR("DWORD:[$dat+$YY*4]")`,$TY#d
134         movl    $TX#d,`&PTR("DWORD:[$dat+$YY*4]")`
135         movl    $TY#d,`&PTR("DWORD:[$dat+$XX*4]")`
136         sub     \$8,$len
137         add     $TY#b,$TX#b
138         movb    `&PTR("BYTE:[$dat+$TX*4]")`,%al
139         ror     \$8,%rax
140         add     \$8,$inp
141         add     \$8,$out
142
143         xor     `&PTR("QWORD:-8[$inp]")`,%rax
144         mov     %rax,`&PTR("QWORD:-8[$out]")`
145
146         test    \$-8,$len
147         jnz     .Lloop8
148         cmp     \$0,$len
149         jne     .Lloop1
150 .Lexit:
151         movl    $XX#d,`&PTR("DWORD:-8[$dat]")`
152         movl    $YY#d,`&PTR("DWORD:-4[$dat]")`
153 ___
154 $code.=<<___ if (defined($win64a));
155         add     \$40,%rsp
156         pop     %rsi
157         pop     %rdi
158 ___
159 $code.=<<___;
160         repret
161 .align  16
162 .Lloop1:
163         movzb   `&PTR("BYTE:[$inp]")`,%eax
164         inc     $XX#b
165         movl    `&PTR("DWORD:[$dat+$XX*4]")`,$TX#d
166         add     $TX#b,$YY#b
167         movl    `&PTR("DWORD:[$dat+$YY*4]")`,$TY#d
168         movl    $TX#d,`&PTR("DWORD:[$dat+$YY*4]")`
169         movl    $TY#d,`&PTR("DWORD:[$dat+$XX*4]")`
170         add     $TY#b,$TX#b
171         movl    `&PTR("DWORD:[$dat+$TX*4]")`,$TY#d
172         xor     $TY,%rax
173         inc     $inp
174         movb    %al,`&PTR("BYTE:[$out]")`
175         inc     $out
176         dec     $len
177         jnz     .Lloop1
178         jmp     .Lexit
179
180 .align  16
181 .LRC4_CHAR:
182         inc     $XX#b
183         movzb   `&PTR("BYTE:[$dat+$XX]")`,$TX#d
184         add     $TX#b,$YY#b
185         movzb   `&PTR("BYTE:[$dat+$YY]")`,$TY#d
186         movb    $TX#b,`&PTR("BYTE:[$dat+$YY]")`
187         movb    $TY#b,`&PTR("BYTE:[$dat+$XX]")`
188         add     $TX#b,$TY#b
189         movzb   `&PTR("BYTE:[$dat+$TY]")`,$TY#d
190         xorb    `&PTR("BYTE:[$inp]")`,$TY#b
191         movb    $TY#b,`&PTR("BYTE:[$out]")`
192         inc     $inp
193         inc     $out
194         dec     $len
195         jnz     .LRC4_CHAR
196         jmp     .Lexit
197 ___
198 $code.=<<___ if (defined($win64a));
199 RC4     ENDP
200 _TEXT   ENDS
201 END
202 ___
203 $code.=<<___ if (!defined($win64a));
204 .size   RC4,.-RC4
205 ___
206
207 $code =~ s/#([bwd])/$1/gm;
208 $code =~ s/\`([^\`]*)\`/eval $1/gem;
209
210 if (defined($win64a)) {
211     $code =~ s/\.align/ALIGN/gm;
212     $code =~ s/[\$%]//gm;
213     $code =~ s/\.L/\$L/gm;
214     $code =~ s/([\w]+)([\s]+)([\S]+),([\S]+)/$1$2$4,$3/gm;
215     $code =~ s/([QD]*WORD|BYTE):/$1 PTR/gm;
216     $code =~ s/mov[bwlq]/mov/gm;
217     $code =~ s/movzb/movzx/gm;
218     $code =~ s/repret/DB\t0F3h,0C3h/gm;
219     $code =~ s/cmpl/cmp/gm;
220     $code =~ s/xorb/xor/gm;
221 } else {
222     $code =~ s/([QD]*WORD|BYTE)://gm;
223     $code =~ s/repret/.byte\t0xF3,0xC3/gm;
224 }
225 print $code;