1238384Sjkim#!/usr/bin/env perl
2238384Sjkim
3238384Sjkim# ====================================================================
4238384Sjkim# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5238384Sjkim# project. The module is, however, dual licensed under OpenSSL and
6238384Sjkim# CRYPTOGAMS licenses depending on where you obtain it. For further
7238384Sjkim# details see http://www.openssl.org/~appro/cryptogams/.
8238384Sjkim# ====================================================================
9238384Sjkim
10238384Sjkim# January 2009
11238384Sjkim#
12238384Sjkim# Provided that UltraSPARC VIS instructions are pipe-lined(*) and
13238384Sjkim# pairable(*) with IALU ones, offloading of Xupdate to the UltraSPARC
14238384Sjkim# Graphic Unit would make it possible to achieve higher instruction-
15238384Sjkim# level parallelism, ILP, and thus higher performance. It should be
16238384Sjkim# explicitly noted that ILP is the keyword, and it means that this
17238384Sjkim# code would be unsuitable for cores like UltraSPARC-Tx. The idea is
18238384Sjkim# not really novel, Sun had VIS-powered implementation for a while.
19238384Sjkim# Unlike Sun's implementation this one can process multiple unaligned
20238384Sjkim# input blocks, and as such works as drop-in replacement for OpenSSL
21238384Sjkim# sha1_block_data_order. Performance improvement was measured to be
22238384Sjkim# 40% over pure IALU sha1-sparcv9.pl on UltraSPARC-IIi, but 12% on
23238384Sjkim# UltraSPARC-III. See below for discussion...
24238384Sjkim#
25238384Sjkim# The module does not present direct interest for OpenSSL, because
26238384Sjkim# it doesn't provide better performance on contemporary SPARCv9 CPUs,
27238384Sjkim# UltraSPARC-Tx and SPARC64-V[II] to be specific. Those who feel they
28238384Sjkim# absolutely must score on UltraSPARC-I-IV can simply replace
29238384Sjkim# crypto/sha/asm/sha1-sparcv9.pl with this module.
30238384Sjkim#
31238384Sjkim# (*)	"Pipe-lined" means that even if it takes several cycles to
32238384Sjkim#	complete, next instruction using same functional unit [but not
33238384Sjkim#	depending on the result of the current instruction] can start
34238384Sjkim#	execution without having to wait for the unit. "Pairable"
35238384Sjkim#	means that two [or more] independent instructions can be
36238384Sjkim#	issued at the very same time.
37238384Sjkim
38238384Sjkim$bits=32;
39238384Sjkimfor (@ARGV)	{ $bits=64 if (/\-m64/ || /\-xarch\=v9/); }
40238384Sjkimif ($bits==64)	{ $bias=2047; $frame=192; }
41238384Sjkimelse		{ $bias=0;    $frame=112; }
42238384Sjkim
43238384Sjkim$output=shift;
44238384Sjkimopen STDOUT,">$output";
45238384Sjkim
46238384Sjkim$ctx="%i0";
47238384Sjkim$inp="%i1";
48238384Sjkim$len="%i2";
49238384Sjkim$tmp0="%i3";
50238384Sjkim$tmp1="%i4";
51238384Sjkim$tmp2="%i5";
52238384Sjkim$tmp3="%g5";
53238384Sjkim
54238384Sjkim$base="%g1";
55238384Sjkim$align="%g4";
56238384Sjkim$Xfer="%o5";
57238384Sjkim$nXfer=$tmp3;
58238384Sjkim$Xi="%o7";
59238384Sjkim
60238384Sjkim$A="%l0";
61238384Sjkim$B="%l1";
62238384Sjkim$C="%l2";
63238384Sjkim$D="%l3";
64238384Sjkim$E="%l4";
65238384Sjkim@V=($A,$B,$C,$D,$E);
66238384Sjkim
67238384Sjkim$Actx="%o0";
68238384Sjkim$Bctx="%o1";
69238384Sjkim$Cctx="%o2";
70238384Sjkim$Dctx="%o3";
71238384Sjkim$Ectx="%o4";
72238384Sjkim
73238384Sjkim$fmul="%f32";
74238384Sjkim$VK_00_19="%f34";
75238384Sjkim$VK_20_39="%f36";
76238384Sjkim$VK_40_59="%f38";
77238384Sjkim$VK_60_79="%f40";
78238384Sjkim@VK=($VK_00_19,$VK_20_39,$VK_40_59,$VK_60_79);
79238384Sjkim@X=("%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
80238384Sjkim    "%f8", "%f9","%f10","%f11","%f12","%f13","%f14","%f15","%f16");
81238384Sjkim
82238384Sjkim# This is reference 2x-parallelized VIS-powered Xupdate procedure. It
83238384Sjkim# covers even K_NN_MM addition...
84238384Sjkimsub Xupdate {
85238384Sjkimmy ($i)=@_;
86238384Sjkimmy $K=@VK[($i+16)/20];
87238384Sjkimmy $j=($i+16)%16;
88238384Sjkim
89238384Sjkim#	[ provided that GSR.alignaddr_offset is 5, $mul contains
90238384Sjkim#	  0x100ULL<<32|0x100 value and K_NN_MM are pre-loaded to
91238384Sjkim#	  chosen registers... ]
92238384Sjkim$code.=<<___;
93238384Sjkim	fxors		@X[($j+13)%16],@X[$j],@X[$j]	!-1/-1/-1:X[0]^=X[13]
94238384Sjkim	fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
95238384Sjkim	fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
96238384Sjkim	fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
97238384Sjkim	faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
98238384Sjkim	fpadd32		@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
99238384Sjkim	fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
100238384Sjkim	![fxors		%f15,%f2,%f2]
101238384Sjkim	for		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
102238384Sjkim	![fxors		%f0,%f3,%f3]			!10/17/12:X[0] dependency
103238384Sjkim	fpadd32		$K,@X[$j],%f20
104238384Sjkim	std		%f20,[$Xfer+`4*$j`]
105238384Sjkim___
106238384Sjkim# The numbers delimited with slash are the earliest possible dispatch
107238384Sjkim# cycles for given instruction assuming 1 cycle latency for simple VIS
108238384Sjkim# instructions, such as on UltraSPARC-I&II, 3 cycles latency, such as
109238384Sjkim# on UltraSPARC-III&IV, and 2 cycles latency(*), respectively. Being
110238384Sjkim# 2x-parallelized the procedure is "worth" 5, 8.5 or 6 ticks per SHA1
111238384Sjkim# round. As [long as] FPU/VIS instructions are perfectly pairable with
112238384Sjkim# IALU ones, the round timing is defined by the maximum between VIS
113238384Sjkim# and IALU timings. The latter varies from round to round and averages
114238384Sjkim# out at 6.25 ticks. This means that USI&II should operate at IALU
115238384Sjkim# rate, while USIII&IV - at VIS rate. This explains why performance
116238384Sjkim# improvement varies among processors. Well, given that pure IALU
117238384Sjkim# sha1-sparcv9.pl module exhibits virtually uniform performance of
118238384Sjkim# ~9.3 cycles per SHA1 round. Timings mentioned above are theoretical
119238384Sjkim# lower limits. Real-life performance was measured to be 6.6 cycles
120238384Sjkim# per SHA1 round on USIIi and 8.3 on USIII. The latter is lower than
121238384Sjkim# half-round VIS timing, because there are 16 Xupdate-free rounds,
122238384Sjkim# which "push down" average theoretical timing to 8 cycles...
123238384Sjkim
124238384Sjkim# (*)	SPARC64-V[II] was originally believed to have 2 cycles VIS
125238384Sjkim#	latency. Well, it might have, but it doesn't have dedicated
126238384Sjkim#	VIS-unit. Instead, VIS instructions are executed by other
127238384Sjkim#	functional units, ones used here - by IALU. This doesn't
128238384Sjkim#	improve effective ILP...
129238384Sjkim}
130238384Sjkim
131238384Sjkim# The reference Xupdate procedure is then "strained" over *pairs* of
132238384Sjkim# BODY_NN_MM and kind of modulo-scheduled in respect to X[n]^=X[n+13]
133238384Sjkim# and K_NN_MM addition. It's "running" 15 rounds ahead, which leaves
134238384Sjkim# plenty of room to amortize for read-after-write hazard, as well as
135238384Sjkim# to fetch and align input for the next spin. The VIS instructions are
136238384Sjkim# scheduled for latency of 2 cycles, because there are not enough IALU
137238384Sjkim# instructions to schedule for latency of 3, while scheduling for 1
138238384Sjkim# would give no gain on USI&II anyway.
139238384Sjkim
140238384Sjkimsub BODY_00_19 {
141238384Sjkimmy ($i,$a,$b,$c,$d,$e)=@_;
142238384Sjkimmy $j=$i&~1;
143238384Sjkimmy $k=($j+16+2)%16;	# ahead reference
144238384Sjkimmy $l=($j+16-2)%16;	# behind reference
145238384Sjkimmy $K=@VK[($j+16-2)/20];
146238384Sjkim
147238384Sjkim$j=($j+16)%16;
148238384Sjkim
149238384Sjkim$code.=<<___ if (!($i&1));
150238384Sjkim	sll		$a,5,$tmp0			!! $i
151238384Sjkim	and		$c,$b,$tmp3
152238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
153238384Sjkim	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
154238384Sjkim	srl		$a,27,$tmp1
155238384Sjkim	add		$tmp0,$e,$e
156238384Sjkim	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
157238384Sjkim	sll		$b,30,$tmp2
158238384Sjkim	add		$tmp1,$e,$e
159238384Sjkim	andn		$d,$b,$tmp1
160238384Sjkim	add		$Xi,$e,$e
161238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
162238384Sjkim	srl		$b,2,$b
163238384Sjkim	or		$tmp1,$tmp3,$tmp1
164238384Sjkim	or		$tmp2,$b,$b
165238384Sjkim	add		$tmp1,$e,$e
166238384Sjkim	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
167238384Sjkim___
168238384Sjkim$code.=<<___ if ($i&1);
169238384Sjkim	sll		$a,5,$tmp0			!! $i
170238384Sjkim	and		$c,$b,$tmp3
171238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
172238384Sjkim	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
173238384Sjkim	srl		$a,27,$tmp1
174238384Sjkim	add		$tmp0,$e,$e
175238384Sjkim	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
176238384Sjkim	sll		$b,30,$tmp2
177238384Sjkim	add		$tmp1,$e,$e
178238384Sjkim	 fpadd32	$K,@X[$l],%f20			!
179238384Sjkim	andn		$d,$b,$tmp1
180238384Sjkim	add		$Xi,$e,$e
181238384Sjkim	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
182238384Sjkim	srl		$b,2,$b
183238384Sjkim	or		$tmp1,$tmp3,$tmp1
184238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
185238384Sjkim	or		$tmp2,$b,$b
186238384Sjkim	add		$tmp1,$e,$e
187238384Sjkim___
188238384Sjkim$code.=<<___ if ($i&1 && $i>=2);
189238384Sjkim	 std		%f20,[$Xfer+`4*$l`]		!
190238384Sjkim___
191238384Sjkim}
192238384Sjkim
193238384Sjkimsub BODY_20_39 {
194238384Sjkimmy ($i,$a,$b,$c,$d,$e)=@_;
195238384Sjkimmy $j=$i&~1;
196238384Sjkimmy $k=($j+16+2)%16;	# ahead reference
197238384Sjkimmy $l=($j+16-2)%16;	# behind reference
198238384Sjkimmy $K=@VK[($j+16-2)/20];
199238384Sjkim
200238384Sjkim$j=($j+16)%16;
201238384Sjkim
202238384Sjkim$code.=<<___ if (!($i&1) && $i<64);
203238384Sjkim	sll		$a,5,$tmp0			!! $i
204238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
205238384Sjkim	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
206238384Sjkim	srl		$a,27,$tmp1
207238384Sjkim	add		$tmp0,$e,$e
208238384Sjkim	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
209238384Sjkim	xor		$c,$b,$tmp0
210238384Sjkim	add		$tmp1,$e,$e
211238384Sjkim	sll		$b,30,$tmp2
212238384Sjkim	xor		$d,$tmp0,$tmp1
213238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
214238384Sjkim	srl		$b,2,$b
215238384Sjkim	add		$tmp1,$e,$e
216238384Sjkim	or		$tmp2,$b,$b
217238384Sjkim	add		$Xi,$e,$e
218238384Sjkim	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
219238384Sjkim___
220238384Sjkim$code.=<<___ if ($i&1 && $i<64);
221238384Sjkim	sll		$a,5,$tmp0			!! $i
222238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
223238384Sjkim	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
224238384Sjkim	srl		$a,27,$tmp1
225238384Sjkim	add		$tmp0,$e,$e
226238384Sjkim	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
227238384Sjkim	xor		$c,$b,$tmp0
228238384Sjkim	add		$tmp1,$e,$e
229238384Sjkim	 fpadd32	$K,@X[$l],%f20			!
230238384Sjkim	sll		$b,30,$tmp2
231238384Sjkim	xor		$d,$tmp0,$tmp1
232238384Sjkim	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
233238384Sjkim	srl		$b,2,$b
234238384Sjkim	add		$tmp1,$e,$e
235238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
236238384Sjkim	or		$tmp2,$b,$b
237238384Sjkim	add		$Xi,$e,$e
238238384Sjkim	 std		%f20,[$Xfer+`4*$l`]		!
239238384Sjkim___
240238384Sjkim$code.=<<___ if ($i==64);
241238384Sjkim	sll		$a,5,$tmp0			!! $i
242238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
243238384Sjkim	 fpadd32	$K,@X[$l],%f20
244238384Sjkim	srl		$a,27,$tmp1
245238384Sjkim	add		$tmp0,$e,$e
246238384Sjkim	xor		$c,$b,$tmp0
247238384Sjkim	add		$tmp1,$e,$e
248238384Sjkim	sll		$b,30,$tmp2
249238384Sjkim	xor		$d,$tmp0,$tmp1
250238384Sjkim	 std		%f20,[$Xfer+`4*$l`]
251238384Sjkim	srl		$b,2,$b
252238384Sjkim	add		$tmp1,$e,$e
253238384Sjkim	or		$tmp2,$b,$b
254238384Sjkim	add		$Xi,$e,$e
255238384Sjkim___
256238384Sjkim$code.=<<___ if ($i>64);
257238384Sjkim	sll		$a,5,$tmp0			!! $i
258238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
259238384Sjkim	srl		$a,27,$tmp1
260238384Sjkim	add		$tmp0,$e,$e
261238384Sjkim	xor		$c,$b,$tmp0
262238384Sjkim	add		$tmp1,$e,$e
263238384Sjkim	sll		$b,30,$tmp2
264238384Sjkim	xor		$d,$tmp0,$tmp1
265238384Sjkim	srl		$b,2,$b
266238384Sjkim	add		$tmp1,$e,$e
267238384Sjkim	or		$tmp2,$b,$b
268238384Sjkim	add		$Xi,$e,$e
269238384Sjkim___
270238384Sjkim}
271238384Sjkim
272238384Sjkimsub BODY_40_59 {
273238384Sjkimmy ($i,$a,$b,$c,$d,$e)=@_;
274238384Sjkimmy $j=$i&~1;
275238384Sjkimmy $k=($j+16+2)%16;	# ahead reference
276238384Sjkimmy $l=($j+16-2)%16;	# behind reference
277238384Sjkimmy $K=@VK[($j+16-2)/20];
278238384Sjkim
279238384Sjkim$j=($j+16)%16;
280238384Sjkim
281238384Sjkim$code.=<<___ if (!($i&1));
282238384Sjkim	sll		$a,5,$tmp0			!! $i
283238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
284238384Sjkim	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
285238384Sjkim	srl		$a,27,$tmp1
286238384Sjkim	add		$tmp0,$e,$e
287238384Sjkim	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
288238384Sjkim	and		$c,$b,$tmp0
289238384Sjkim	add		$tmp1,$e,$e
290238384Sjkim	sll		$b,30,$tmp2
291238384Sjkim	or		$c,$b,$tmp1
292238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
293238384Sjkim	srl		$b,2,$b
294238384Sjkim	and		$d,$tmp1,$tmp1
295238384Sjkim	add		$Xi,$e,$e
296238384Sjkim	or		$tmp1,$tmp0,$tmp1
297238384Sjkim	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
298238384Sjkim	or		$tmp2,$b,$b
299238384Sjkim	add		$tmp1,$e,$e
300238384Sjkim	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
301238384Sjkim___
302238384Sjkim$code.=<<___ if ($i&1);
303238384Sjkim	sll		$a,5,$tmp0			!! $i
304238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
305238384Sjkim	srl		$a,27,$tmp1
306238384Sjkim	add		$tmp0,$e,$e
307238384Sjkim	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
308238384Sjkim	and		$c,$b,$tmp0
309238384Sjkim	add		$tmp1,$e,$e
310238384Sjkim	 fpadd32	$K,@X[$l],%f20			!
311238384Sjkim	sll		$b,30,$tmp2
312238384Sjkim	or		$c,$b,$tmp1
313238384Sjkim	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
314238384Sjkim	srl		$b,2,$b
315238384Sjkim	and		$d,$tmp1,$tmp1
316238384Sjkim	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
317238384Sjkim	add		$Xi,$e,$e
318238384Sjkim	or		$tmp1,$tmp0,$tmp1
319238384Sjkim	or		$tmp2,$b,$b
320238384Sjkim	add		$tmp1,$e,$e
321238384Sjkim	 std		%f20,[$Xfer+`4*$l`]		!
322238384Sjkim___
323238384Sjkim}
324238384Sjkim
325238384Sjkim# If there is more data to process, then we pre-fetch the data for
326238384Sjkim# next iteration in last ten rounds...
327238384Sjkimsub BODY_70_79 {
328238384Sjkimmy ($i,$a,$b,$c,$d,$e)=@_;
329238384Sjkimmy $j=$i&~1;
330238384Sjkimmy $m=($i%8)*2;
331238384Sjkim
332238384Sjkim$j=($j+16)%16;
333238384Sjkim
334238384Sjkim$code.=<<___ if ($i==70);
335238384Sjkim	sll		$a,5,$tmp0			!! $i
336238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
337238384Sjkim	srl		$a,27,$tmp1
338238384Sjkim	add		$tmp0,$e,$e
339238384Sjkim	 ldd		[$inp+64],@X[0]
340238384Sjkim	xor		$c,$b,$tmp0
341238384Sjkim	add		$tmp1,$e,$e
342238384Sjkim	sll		$b,30,$tmp2
343238384Sjkim	xor		$d,$tmp0,$tmp1
344238384Sjkim	srl		$b,2,$b
345238384Sjkim	add		$tmp1,$e,$e
346238384Sjkim	or		$tmp2,$b,$b
347238384Sjkim	add		$Xi,$e,$e
348238384Sjkim
349238384Sjkim	and		$inp,-64,$nXfer
350238384Sjkim	inc		64,$inp
351238384Sjkim	and		$nXfer,255,$nXfer
352238384Sjkim	alignaddr	%g0,$align,%g0
353238384Sjkim	add		$base,$nXfer,$nXfer
354238384Sjkim___
355238384Sjkim$code.=<<___ if ($i==71);
356238384Sjkim	sll		$a,5,$tmp0			!! $i
357238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
358238384Sjkim	srl		$a,27,$tmp1
359238384Sjkim	add		$tmp0,$e,$e
360238384Sjkim	xor		$c,$b,$tmp0
361238384Sjkim	add		$tmp1,$e,$e
362238384Sjkim	sll		$b,30,$tmp2
363238384Sjkim	xor		$d,$tmp0,$tmp1
364238384Sjkim	srl		$b,2,$b
365238384Sjkim	add		$tmp1,$e,$e
366238384Sjkim	or		$tmp2,$b,$b
367238384Sjkim	add		$Xi,$e,$e
368238384Sjkim___
369238384Sjkim$code.=<<___ if ($i>=72);
370238384Sjkim	 faligndata	@X[$m],@X[$m+2],@X[$m]
371238384Sjkim	sll		$a,5,$tmp0			!! $i
372238384Sjkim	ld		[$Xfer+`4*($i%16)`],$Xi
373238384Sjkim	srl		$a,27,$tmp1
374238384Sjkim	add		$tmp0,$e,$e
375238384Sjkim	xor		$c,$b,$tmp0
376238384Sjkim	add		$tmp1,$e,$e
377238384Sjkim	 fpadd32	$VK_00_19,@X[$m],%f20
378238384Sjkim	sll		$b,30,$tmp2
379238384Sjkim	xor		$d,$tmp0,$tmp1
380238384Sjkim	srl		$b,2,$b
381238384Sjkim	add		$tmp1,$e,$e
382238384Sjkim	or		$tmp2,$b,$b
383238384Sjkim	add		$Xi,$e,$e
384238384Sjkim___
385238384Sjkim$code.=<<___ if ($i<77);
386238384Sjkim	 ldd		[$inp+`8*($i+1-70)`],@X[2*($i+1-70)]
387238384Sjkim___
388238384Sjkim$code.=<<___ if ($i==77);	# redundant if $inp was aligned
389238384Sjkim	 add		$align,63,$tmp0
390238384Sjkim	 and		$tmp0,-8,$tmp0
391238384Sjkim	 ldd		[$inp+$tmp0],@X[16]
392238384Sjkim___
393238384Sjkim$code.=<<___ if ($i>=72);
394238384Sjkim	 std		%f20,[$nXfer+`4*$m`]
395238384Sjkim___
396238384Sjkim}
397238384Sjkim
398238384Sjkim$code.=<<___;
399238384Sjkim.section	".text",#alloc,#execinstr
400238384Sjkim
401238384Sjkim.align	64
402238384Sjkimvis_const:
403238384Sjkim.long	0x5a827999,0x5a827999	! K_00_19
404238384Sjkim.long	0x6ed9eba1,0x6ed9eba1	! K_20_39
405238384Sjkim.long	0x8f1bbcdc,0x8f1bbcdc	! K_40_59
406238384Sjkim.long	0xca62c1d6,0xca62c1d6	! K_60_79
407238384Sjkim.long	0x00000100,0x00000100
408238384Sjkim.align	64
409238384Sjkim.type	vis_const,#object
410238384Sjkim.size	vis_const,(.-vis_const)
411238384Sjkim
412238384Sjkim.globl	sha1_block_data_order
413238384Sjkimsha1_block_data_order:
414238384Sjkim	save	%sp,-$frame,%sp
415238384Sjkim	add	%fp,$bias-256,$base
416238384Sjkim
417238384Sjkim1:	call	.+8
418238384Sjkim	add	%o7,vis_const-1b,$tmp0
419238384Sjkim
420238384Sjkim	ldd	[$tmp0+0],$VK_00_19
421238384Sjkim	ldd	[$tmp0+8],$VK_20_39
422238384Sjkim	ldd	[$tmp0+16],$VK_40_59
423238384Sjkim	ldd	[$tmp0+24],$VK_60_79
424238384Sjkim	ldd	[$tmp0+32],$fmul
425238384Sjkim
426238384Sjkim	ld	[$ctx+0],$Actx
427238384Sjkim	and	$base,-256,$base
428238384Sjkim	ld	[$ctx+4],$Bctx
429238384Sjkim	sub	$base,$bias+$frame,%sp
430238384Sjkim	ld	[$ctx+8],$Cctx
431238384Sjkim	and	$inp,7,$align
432238384Sjkim	ld	[$ctx+12],$Dctx
433238384Sjkim	and	$inp,-8,$inp
434238384Sjkim	ld	[$ctx+16],$Ectx
435238384Sjkim
436238384Sjkim	! X[16] is maintained in FP register bank
437238384Sjkim	alignaddr	%g0,$align,%g0
438238384Sjkim	ldd		[$inp+0],@X[0]
439238384Sjkim	sub		$inp,-64,$Xfer
440238384Sjkim	ldd		[$inp+8],@X[2]
441238384Sjkim	and		$Xfer,-64,$Xfer
442238384Sjkim	ldd		[$inp+16],@X[4]
443238384Sjkim	and		$Xfer,255,$Xfer
444238384Sjkim	ldd		[$inp+24],@X[6]
445238384Sjkim	add		$base,$Xfer,$Xfer
446238384Sjkim	ldd		[$inp+32],@X[8]
447238384Sjkim	ldd		[$inp+40],@X[10]
448238384Sjkim	ldd		[$inp+48],@X[12]
449238384Sjkim	brz,pt		$align,.Laligned
450238384Sjkim	ldd		[$inp+56],@X[14]
451238384Sjkim
452238384Sjkim	ldd		[$inp+64],@X[16]
453238384Sjkim	faligndata	@X[0],@X[2],@X[0]
454238384Sjkim	faligndata	@X[2],@X[4],@X[2]
455238384Sjkim	faligndata	@X[4],@X[6],@X[4]
456238384Sjkim	faligndata	@X[6],@X[8],@X[6]
457238384Sjkim	faligndata	@X[8],@X[10],@X[8]
458238384Sjkim	faligndata	@X[10],@X[12],@X[10]
459238384Sjkim	faligndata	@X[12],@X[14],@X[12]
460238384Sjkim	faligndata	@X[14],@X[16],@X[14]
461238384Sjkim
462238384Sjkim.Laligned:
463238384Sjkim	mov		5,$tmp0
464238384Sjkim	dec		1,$len
465238384Sjkim	alignaddr	%g0,$tmp0,%g0
466238384Sjkim	fpadd32		$VK_00_19,@X[0],%f16
467238384Sjkim	fpadd32		$VK_00_19,@X[2],%f18
468238384Sjkim	fpadd32		$VK_00_19,@X[4],%f20
469238384Sjkim	fpadd32		$VK_00_19,@X[6],%f22
470238384Sjkim	fpadd32		$VK_00_19,@X[8],%f24
471238384Sjkim	fpadd32		$VK_00_19,@X[10],%f26
472238384Sjkim	fpadd32		$VK_00_19,@X[12],%f28
473238384Sjkim	fpadd32		$VK_00_19,@X[14],%f30
474238384Sjkim	std		%f16,[$Xfer+0]
475238384Sjkim	mov		$Actx,$A
476238384Sjkim	std		%f18,[$Xfer+8]
477238384Sjkim	mov		$Bctx,$B
478238384Sjkim	std		%f20,[$Xfer+16]
479238384Sjkim	mov		$Cctx,$C
480238384Sjkim	std		%f22,[$Xfer+24]
481238384Sjkim	mov		$Dctx,$D
482238384Sjkim	std		%f24,[$Xfer+32]
483238384Sjkim	mov		$Ectx,$E
484238384Sjkim	std		%f26,[$Xfer+40]
485238384Sjkim	fxors		@X[13],@X[0],@X[0]
486238384Sjkim	std		%f28,[$Xfer+48]
487238384Sjkim	ba		.Loop
488238384Sjkim	std		%f30,[$Xfer+56]
489238384Sjkim.align	32
490238384Sjkim.Loop:
491238384Sjkim___
492238384Sjkimfor ($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
493238384Sjkimfor (;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
494238384Sjkimfor (;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
495238384Sjkimfor (;$i<70;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
496238384Sjkim$code.=<<___;
497238384Sjkim	tst		$len
498238384Sjkim	bz,pn		`$bits==32?"%icc":"%xcc"`,.Ltail
499238384Sjkim	nop
500238384Sjkim___
501238384Sjkimfor (;$i<80;$i++)	{ &BODY_70_79($i,@V); unshift(@V,pop(@V)); }
502238384Sjkim$code.=<<___;
503238384Sjkim	add		$A,$Actx,$Actx
504238384Sjkim	add		$B,$Bctx,$Bctx
505238384Sjkim	add		$C,$Cctx,$Cctx
506238384Sjkim	add		$D,$Dctx,$Dctx
507238384Sjkim	add		$E,$Ectx,$Ectx
508238384Sjkim	mov		5,$tmp0
509238384Sjkim	fxors		@X[13],@X[0],@X[0]
510238384Sjkim	mov		$Actx,$A
511238384Sjkim	mov		$Bctx,$B
512238384Sjkim	mov		$Cctx,$C
513238384Sjkim	mov		$Dctx,$D
514238384Sjkim	mov		$Ectx,$E
515238384Sjkim	alignaddr	%g0,$tmp0,%g0
516238384Sjkim	dec		1,$len
517238384Sjkim	ba		.Loop
518238384Sjkim	mov		$nXfer,$Xfer
519238384Sjkim
520238384Sjkim.align	32
521238384Sjkim.Ltail:
522238384Sjkim___
523238384Sjkimfor($i=70;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
524238384Sjkim$code.=<<___;
525238384Sjkim	add	$A,$Actx,$Actx
526238384Sjkim	add	$B,$Bctx,$Bctx
527238384Sjkim	add	$C,$Cctx,$Cctx
528238384Sjkim	add	$D,$Dctx,$Dctx
529238384Sjkim	add	$E,$Ectx,$Ectx
530238384Sjkim
531238384Sjkim	st	$Actx,[$ctx+0]
532238384Sjkim	st	$Bctx,[$ctx+4]
533238384Sjkim	st	$Cctx,[$ctx+8]
534238384Sjkim	st	$Dctx,[$ctx+12]
535238384Sjkim	st	$Ectx,[$ctx+16]
536238384Sjkim
537238384Sjkim	ret
538238384Sjkim	restore
539238384Sjkim.type	sha1_block_data_order,#function
540238384Sjkim.size	sha1_block_data_order,(.-sha1_block_data_order)
541238384Sjkim.asciz	"SHA1 block transform for SPARCv9a, CRYPTOGAMS by <appro\@openssl.org>"
542238384Sjkim.align	4
543238384Sjkim___
544238384Sjkim
545238384Sjkim# Purpose of these subroutines is to explicitly encode VIS instructions,
546238384Sjkim# so that one can compile the module without having to specify VIS
547238384Sjkim# extentions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
548238384Sjkim# Idea is to reserve for option to produce "universal" binary and let
549238384Sjkim# programmer detect if current CPU is VIS capable at run-time.
550238384Sjkimsub unvis {
551238384Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
552246772Sjkimmy ($ref,$opf);
553238384Sjkimmy %visopf = (	"fmul8ulx16"	=> 0x037,
554238384Sjkim		"faligndata"	=> 0x048,
555238384Sjkim		"fpadd32"	=> 0x052,
556238384Sjkim		"fxor"		=> 0x06c,
557238384Sjkim		"fxors"		=> 0x06d	);
558238384Sjkim
559238384Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rd";
560238384Sjkim
561238384Sjkim    if ($opf=$visopf{$mnemonic}) {
562238384Sjkim	foreach ($rs1,$rs2,$rd) {
563238384Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
564238384Sjkim	    $_=$1;
565238384Sjkim	    if ($1>=32) {
566238384Sjkim		return $ref if ($1&1);
567238384Sjkim		# re-encode for upper double register addressing
568238384Sjkim		$_=($1|$1>>5)&31;
569238384Sjkim	    }
570238384Sjkim	}
571238384Sjkim
572238384Sjkim	return	sprintf ".word\t0x%08x !%s",
573238384Sjkim			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
574238384Sjkim			$ref;
575238384Sjkim    } else {
576238384Sjkim	return $ref;
577238384Sjkim    }
578238384Sjkim}
579238384Sjkimsub unalignaddr {
580238384Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
581238384Sjkimmy %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
582238384Sjkimmy $ref="$mnemonic\t$rs1,$rs2,$rd";
583238384Sjkim
584238384Sjkim    foreach ($rs1,$rs2,$rd) {
585238384Sjkim	if (/%([goli])([0-7])/)	{ $_=$bias{$1}+$2; }
586238384Sjkim	else			{ return $ref; }
587238384Sjkim    }
588238384Sjkim    return  sprintf ".word\t0x%08x !%s",
589238384Sjkim		    0x81b00300|$rd<<25|$rs1<<14|$rs2,
590238384Sjkim		    $ref;
591238384Sjkim}
592238384Sjkim
593238384Sjkim$code =~ s/\`([^\`]*)\`/eval $1/gem;
594238384Sjkim$code =~ s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),(%f[0-9]{1,2}),(%f[0-9]{1,2})/
595238384Sjkim		&unvis($1,$2,$3,$4)
596238384Sjkim	  /gem;
597238384Sjkim$code =~ s/\b(alignaddr)\s+(%[goli][0-7]),(%[goli][0-7]),(%[goli][0-7])/
598238384Sjkim		&unalignaddr($1,$2,$3,$4)
599238384Sjkim	  /gem;
600238384Sjkimprint $code;
601238384Sjkimclose STDOUT;
602