a00f7c679974972edd5b74226af02e35e3a98cbf
[openssl.git] / crypto / sha / asm / sha1-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # sha1_block procedure for x86_64.
11 #
12 # It was brought to my attention that on EM64T compiler-generated code
13 # was far behind 32-bit assembler implementation. This is unlike on
14 # Opteron where compiler-generated code was only 15% behind 32-bit
15 # assembler, which originally made it hard to motivate the effort.
16 # There was suggestion to mechanically translate 32-bit code, but I
17 # dismissed it, reasoning that x86_64 offers enough register bank
18 # capacity to fully utilize SHA-1 parallelism. Therefore this fresh
19 # implementation:-) However! While 64-bit code does perform better
20 # on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
21 # x86_64 does offer larger *addressable* bank, but out-of-order core
22 # reaches for even more registers through dynamic aliasing, and EM64T
23 # core must have managed to run-time optimize even 32-bit code just as
24 # good as 64-bit one. Performance improvement is summarized in the
25 # following table:
26 #
27 #               gcc 3.4         32-bit asm      cycles/byte
28 # Opteron       +45%            +20%            6.8
29 # Xeon P4       +65%            +0%             9.9
30 # Core2         +60%            +10%            7.0
31
32 # August 2009.
33 #
34 # The code was revised to minimize code size and to maximize
35 # "distance" between instructions producing input to 'lea'
36 # instruction and the 'lea' instruction itself, which is essential
37 # for Intel Atom core.
38
39 $flavour = shift;
40 $output  = shift;
41 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
42
43 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
44
45 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
46 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
47 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
48 die "can't locate x86_64-xlate.pl";
49
50 open STDOUT,"| $^X $xlate $flavour $output";
51
52 $ctx="%rdi";    # 1st arg
53 $inp="%rsi";    # 2nd arg
54 $num="%rdx";    # 3rd arg
55
56 # reassign arguments in order to produce more compact code
57 $ctx="%r8";
58 $inp="%r9";
59 $num="%r10";
60
61 $t0="%eax";
62 $t1="%ebx";
63 $t2="%ecx";
64 @xi=("%edx","%ebp");
65 $A="%esi";
66 $B="%edi";
67 $C="%r11d";
68 $D="%r12d";
69 $E="%r13d";
70
71 @V=($A,$B,$C,$D,$E);
72
73 sub BODY_00_19 {
74 my ($i,$a,$b,$c,$d,$e)=@_;
75 my $j=$i+1;
76 $code.=<<___ if ($i==0);
77         mov     `4*$i`($inp),$xi[0]
78         bswap   $xi[0]
79         mov     $xi[0],`4*$i`(%rsp)
80 ___
81 $code.=<<___ if ($i<15);
82         mov     $c,$t0
83         mov     `4*$j`($inp),$xi[1]
84         mov     $a,$t2
85         xor     $d,$t0
86         bswap   $xi[1]
87         rol     \$5,$t2
88         lea     0x5a827999($xi[0],$e),$e
89         and     $b,$t0
90         mov     $xi[1],`4*$j`(%rsp)
91         add     $t2,$e
92         xor     $d,$t0
93         rol     \$30,$b
94         add     $t0,$e
95 ___
96 $code.=<<___ if ($i>=15);
97         mov     `4*($j%16)`(%rsp),$xi[1]
98         mov     $c,$t0
99         mov     $a,$t2
100         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
101         xor     $d,$t0
102         rol     \$5,$t2
103         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
104         and     $b,$t0
105         lea     0x5a827999($xi[0],$e),$e
106         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
107         xor     $d,$t0
108         rol     \$1,$xi[1]
109         add     $t2,$e
110         rol     \$30,$b
111         mov     $xi[1],`4*($j%16)`(%rsp)
112         add     $t0,$e
113 ___
114 unshift(@xi,pop(@xi));
115 }
116
117 sub BODY_20_39 {
118 my ($i,$a,$b,$c,$d,$e)=@_;
119 my $j=$i+1;
120 my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
121 $code.=<<___ if ($i<79);
122         mov     `4*($j%16)`(%rsp),$xi[1]
123         mov     $c,$t0
124         mov     $a,$t2
125         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
126         xor     $b,$t0
127         rol     \$5,$t2
128         lea     $K($xi[0],$e),$e
129         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
130         xor     $d,$t0
131         add     $t2,$e
132         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
133         rol     \$30,$b
134         add     $t0,$e
135         rol     \$1,$xi[1]
136 ___
137 $code.=<<___ if ($i<76);
138         mov     $xi[1],`4*($j%16)`(%rsp)
139 ___
140 $code.=<<___ if ($i==79);
141         mov     $c,$t0
142         mov     $a,$t2
143         xor     $b,$t0
144         lea     $K($xi[0],$e),$e
145         rol     \$5,$t2
146         xor     $d,$t0
147         add     $t2,$e
148         rol     \$30,$b
149         add     $t0,$e
150 ___
151 unshift(@xi,pop(@xi));
152 }
153
154 sub BODY_40_59 {
155 my ($i,$a,$b,$c,$d,$e)=@_;
156 my $j=$i+1;
157 $code.=<<___;
158         mov     `4*($j%16)`(%rsp),$xi[1]
159         mov     $c,$t0
160         mov     $c,$t1
161         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
162         and     $d,$t0
163         mov     $a,$t2
164         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
165         xor     $d,$t1
166         lea     0x8f1bbcdc($xi[0],$e),$e
167         rol     \$5,$t2
168         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
169         add     $t0,$e
170         and     $b,$t1
171         rol     \$1,$xi[1]
172         add     $t1,$e
173         rol     \$30,$b
174         mov     $xi[1],`4*($j%16)`(%rsp)
175         add     $t2,$e
176 ___
177 unshift(@xi,pop(@xi));
178 }
179
180 $code.=<<___;
181 .section .note.GNU-stack,"",\@progbits
182 .text
183
184 .globl  sha1_block_data_order
185 .type   sha1_block_data_order,\@function,3
186 .align  16
187 sha1_block_data_order:
188         push    %rbx
189         push    %rbp
190         push    %r12
191         push    %r13
192         mov     %rsp,%r11
193         mov     %rdi,$ctx       # reassigned argument
194         sub     \$`8+16*4`,%rsp
195         mov     %rsi,$inp       # reassigned argument
196         and     \$-64,%rsp
197         mov     %rdx,$num       # reassigned argument
198         mov     %r11,`16*4`(%rsp)
199 .Lprologue:
200
201         mov     0($ctx),$A
202         mov     4($ctx),$B
203         mov     8($ctx),$C
204         mov     12($ctx),$D
205         mov     16($ctx),$E
206
207 .align  4
208 .Lloop:
209 ___
210 for($i=0;$i<20;$i++)    { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
211 for(;$i<40;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
212 for(;$i<60;$i++)        { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
213 for(;$i<80;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
214 $code.=<<___;
215         add     0($ctx),$A
216         add     4($ctx),$B
217         add     8($ctx),$C
218         add     12($ctx),$D
219         add     16($ctx),$E
220         mov     $A,0($ctx)
221         mov     $B,4($ctx)
222         mov     $C,8($ctx)
223         mov     $D,12($ctx)
224         mov     $E,16($ctx)
225
226         sub     \$1,$num
227         lea     `16*4`($inp),$inp
228         jnz     .Lloop
229
230         mov     `16*4`(%rsp),%rsi
231         mov     (%rsi),%r13
232         mov     8(%rsi),%r12
233         mov     16(%rsi),%rbp
234         mov     24(%rsi),%rbx
235         lea     32(%rsi),%rsp
236 .Lepilogue:
237         ret
238 .size   sha1_block_data_order,.-sha1_block_data_order
239
240 .asciz  "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
241 .align  16
242 ___
243
244 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
245 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
246 if ($win64) {
247 $rec="%rcx";
248 $frame="%rdx";
249 $context="%r8";
250 $disp="%r9";
251
252 $code.=<<___;
253 .extern __imp_RtlVirtualUnwind
254 .type   se_handler,\@abi-omnipotent
255 .align  16
256 se_handler:
257         push    %rsi
258         push    %rdi
259         push    %rbx
260         push    %rbp
261         push    %r12
262         push    %r13
263         push    %r14
264         push    %r15
265         pushfq
266         sub     \$64,%rsp
267
268         mov     120($context),%rax      # pull context->Rax
269         mov     248($context),%rbx      # pull context->Rip
270
271         lea     .Lprologue(%rip),%r10
272         cmp     %r10,%rbx               # context->Rip<.Lprologue
273         jb      .Lin_prologue
274
275         mov     152($context),%rax      # pull context->Rsp
276
277         lea     .Lepilogue(%rip),%r10
278         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
279         jae     .Lin_prologue
280
281         mov     `16*4`(%rax),%rax       # pull saved stack pointer
282         lea     32(%rax),%rax
283
284         mov     -8(%rax),%rbx
285         mov     -16(%rax),%rbp
286         mov     -24(%rax),%r12
287         mov     -32(%rax),%r13
288         mov     %rbx,144($context)      # restore context->Rbx
289         mov     %rbp,160($context)      # restore context->Rbp
290         mov     %r12,216($context)      # restore context->R12
291         mov     %r13,224($context)      # restore context->R13
292
293 .Lin_prologue:
294         mov     8(%rax),%rdi
295         mov     16(%rax),%rsi
296         mov     %rax,152($context)      # restore context->Rsp
297         mov     %rsi,168($context)      # restore context->Rsi
298         mov     %rdi,176($context)      # restore context->Rdi
299
300         mov     40($disp),%rdi          # disp->ContextRecord
301         mov     $context,%rsi           # context
302         mov     \$154,%ecx              # sizeof(CONTEXT)
303         .long   0xa548f3fc              # cld; rep movsq
304
305         mov     $disp,%rsi
306         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
307         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
308         mov     0(%rsi),%r8             # arg3, disp->ControlPc
309         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
310         mov     40(%rsi),%r10           # disp->ContextRecord
311         lea     56(%rsi),%r11           # &disp->HandlerData
312         lea     24(%rsi),%r12           # &disp->EstablisherFrame
313         mov     %r10,32(%rsp)           # arg5
314         mov     %r11,40(%rsp)           # arg6
315         mov     %r12,48(%rsp)           # arg7
316         mov     %rcx,56(%rsp)           # arg8, (NULL)
317         call    *__imp_RtlVirtualUnwind(%rip)
318
319         mov     \$1,%eax                # ExceptionContinueSearch
320         add     \$64,%rsp
321         popfq
322         pop     %r15
323         pop     %r14
324         pop     %r13
325         pop     %r12
326         pop     %rbp
327         pop     %rbx
328         pop     %rdi
329         pop     %rsi
330         ret
331 .size   se_handler,.-se_handler
332
333 .section        .pdata
334 .align  4
335         .rva    .LSEH_begin_sha1_block_data_order
336         .rva    .LSEH_end_sha1_block_data_order
337         .rva    .LSEH_info_sha1_block_data_order
338
339 .section        .xdata
340 .align  8
341 .LSEH_info_sha1_block_data_order:
342         .byte   9,0,0,0
343         .rva    se_handler
344 ___
345 }
346
347 ####################################################################
348
349 $code =~ s/\`([^\`]*)\`/eval $1/gem;
350 print $code;
351 close STDOUT;