1e1051a39Sopenharmony_ci#! /usr/bin/env perl
2e1051a39Sopenharmony_ci# Copyright 2012-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci#
4e1051a39Sopenharmony_ci# Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci# this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci# in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci# https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci# ====================================================================
11e1051a39Sopenharmony_ci# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
12e1051a39Sopenharmony_ci# project. The module is, however, dual licensed under OpenSSL and
13e1051a39Sopenharmony_ci# CRYPTOGAMS licenses depending on where you obtain it. For further
14e1051a39Sopenharmony_ci# details see http://www.openssl.org/~appro/cryptogams/.
15e1051a39Sopenharmony_ci# ====================================================================
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ci# October 2012.
18e1051a39Sopenharmony_ci#
19e1051a39Sopenharmony_ci# SPARCv9 VIS3 Montgomery multiplication procedure suitable for T3 and
20e1051a39Sopenharmony_ci# onward. There are three new instructions used here: umulxhi,
21e1051a39Sopenharmony_ci# addxc[cc] and initializing store. On T3 RSA private key operations
22e1051a39Sopenharmony_ci# are 1.54/1.87/2.11/2.26 times faster for 512/1024/2048/4096-bit key
23e1051a39Sopenharmony_ci# lengths. This is without dedicated squaring procedure. On T4
24e1051a39Sopenharmony_ci# corresponding coefficients are 1.47/2.10/2.80/2.90x, which is mostly
25e1051a39Sopenharmony_ci# for reference purposes, because T4 has dedicated Montgomery
26e1051a39Sopenharmony_ci# multiplication and squaring *instructions* that deliver even more.
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ci$output = pop and open STDOUT,">$output";
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_ci$frame = "STACK_FRAME";
31e1051a39Sopenharmony_ci$bias = "STACK_BIAS";
32e1051a39Sopenharmony_ci
33e1051a39Sopenharmony_ci$code.=<<___;
34e1051a39Sopenharmony_ci#ifndef __ASSEMBLER__
35e1051a39Sopenharmony_ci# define __ASSEMBLER__ 1
36e1051a39Sopenharmony_ci#endif
37e1051a39Sopenharmony_ci#include "crypto/sparc_arch.h"
38e1051a39Sopenharmony_ci
39e1051a39Sopenharmony_ci#ifdef	__arch64__
40e1051a39Sopenharmony_ci.register	%g2,#scratch
41e1051a39Sopenharmony_ci.register	%g3,#scratch
42e1051a39Sopenharmony_ci#endif
43e1051a39Sopenharmony_ci
44e1051a39Sopenharmony_ci.section	".text",#alloc,#execinstr
45e1051a39Sopenharmony_ci___
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci($n0,$m0,$m1,$lo0,$hi0, $lo1,$hi1,$aj,$alo,$nj,$nlo,$tj)=
48e1051a39Sopenharmony_ci	(map("%g$_",(1..5)),map("%o$_",(0..5,7)));
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_ci# int bn_mul_mont(
51e1051a39Sopenharmony_ci$rp="%o0";	# BN_ULONG *rp,
52e1051a39Sopenharmony_ci$ap="%o1";	# const BN_ULONG *ap,
53e1051a39Sopenharmony_ci$bp="%o2";	# const BN_ULONG *bp,
54e1051a39Sopenharmony_ci$np="%o3";	# const BN_ULONG *np,
55e1051a39Sopenharmony_ci$n0p="%o4";	# const BN_ULONG *n0,
56e1051a39Sopenharmony_ci$num="%o5";	# int num);	# caller ensures that num is even
57e1051a39Sopenharmony_ci				# and >=6
58e1051a39Sopenharmony_ci$code.=<<___;
59e1051a39Sopenharmony_ci.globl	bn_mul_mont_vis3
60e1051a39Sopenharmony_ci.align	32
61e1051a39Sopenharmony_cibn_mul_mont_vis3:
62e1051a39Sopenharmony_ci	add	%sp,	$bias,	%g4	! real top of stack
63e1051a39Sopenharmony_ci	sll	$num,	2,	$num	! size in bytes
64e1051a39Sopenharmony_ci	add	$num,	63,	%g5
65e1051a39Sopenharmony_ci	andn	%g5,	63,	%g5	! buffer size rounded up to 64 bytes
66e1051a39Sopenharmony_ci	add	%g5,	%g5,	%g1
67e1051a39Sopenharmony_ci	add	%g5,	%g1,	%g1	! 3*buffer size
68e1051a39Sopenharmony_ci	sub	%g4,	%g1,	%g1
69e1051a39Sopenharmony_ci	andn	%g1,	63,	%g1	! align at 64 byte
70e1051a39Sopenharmony_ci	sub	%g1,	$frame,	%g1	! new top of stack
71e1051a39Sopenharmony_ci	sub	%g1,	%g4,	%g1
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_ci	save	%sp,	%g1,	%sp
74e1051a39Sopenharmony_ci___
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_ci#	+-------------------------------+<-----	%sp
77e1051a39Sopenharmony_ci#	.				.
78e1051a39Sopenharmony_ci#	+-------------------------------+<-----	aligned at 64 bytes
79e1051a39Sopenharmony_ci#	| __int64 tmp[0]		|
80e1051a39Sopenharmony_ci#	+-------------------------------+
81e1051a39Sopenharmony_ci#	.				.
82e1051a39Sopenharmony_ci#	.				.
83e1051a39Sopenharmony_ci#	+-------------------------------+<----- aligned at 64 bytes
84e1051a39Sopenharmony_ci#	| __int64 ap[1..0]		|	converted ap[]
85e1051a39Sopenharmony_ci#	+-------------------------------+
86e1051a39Sopenharmony_ci#	| __int64 np[1..0]		|	converted np[]
87e1051a39Sopenharmony_ci#	+-------------------------------+
88e1051a39Sopenharmony_ci#	| __int64 ap[3..2]		|
89e1051a39Sopenharmony_ci#	.				.
90e1051a39Sopenharmony_ci#	.				.
91e1051a39Sopenharmony_ci#	+-------------------------------+
92e1051a39Sopenharmony_ci($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
93e1051a39Sopenharmony_ci($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz,$anp)=map("%l$_",(0..7));
94e1051a39Sopenharmony_ci($ovf,$i)=($t0,$t1);
95e1051a39Sopenharmony_ci$code.=<<___;
96e1051a39Sopenharmony_ci	ld	[$n0p+0],	$t0	! pull n0[0..1] value
97e1051a39Sopenharmony_ci	add	%sp, $bias+$frame, $tp
98e1051a39Sopenharmony_ci	ld	[$n0p+4],	$t1
99e1051a39Sopenharmony_ci	add	$tp,	%g5,	$anp
100e1051a39Sopenharmony_ci	ld	[$bp+0],	$t2	! m0=bp[0]
101e1051a39Sopenharmony_ci	sllx	$t1,	32,	$n0
102e1051a39Sopenharmony_ci	ld	[$bp+4],	$t3
103e1051a39Sopenharmony_ci	or	$t0,	$n0,	$n0
104e1051a39Sopenharmony_ci	add	$bp,	8,	$bp
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_ci	ld	[$ap+0],	$t0	! ap[0]
107e1051a39Sopenharmony_ci	sllx	$t3,	32,	$m0
108e1051a39Sopenharmony_ci	ld	[$ap+4],	$t1
109e1051a39Sopenharmony_ci	or	$t2,	$m0,	$m0
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_ci	ld	[$ap+8],	$t2	! ap[1]
112e1051a39Sopenharmony_ci	sllx	$t1,	32,	$aj
113e1051a39Sopenharmony_ci	ld	[$ap+12],	$t3
114e1051a39Sopenharmony_ci	or	$t0,	$aj,	$aj
115e1051a39Sopenharmony_ci	add	$ap,	16,	$ap
116e1051a39Sopenharmony_ci	stx	$aj,	[$anp]		! converted ap[0]
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[0]
119e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$hi0
120e1051a39Sopenharmony_ci
121e1051a39Sopenharmony_ci	ld	[$np+0],	$t0	! np[0]
122e1051a39Sopenharmony_ci	sllx	$t3,	32,	$aj
123e1051a39Sopenharmony_ci	ld	[$np+4],	$t1
124e1051a39Sopenharmony_ci	or	$t2,	$aj,	$aj
125e1051a39Sopenharmony_ci
126e1051a39Sopenharmony_ci	ld	[$np+8],	$t2	! np[1]
127e1051a39Sopenharmony_ci	sllx	$t1,	32,	$nj
128e1051a39Sopenharmony_ci	ld	[$np+12],	$t3
129e1051a39Sopenharmony_ci	or	$t0, $nj,	$nj
130e1051a39Sopenharmony_ci	add	$np,	16,	$np
131e1051a39Sopenharmony_ci	stx	$nj,	[$anp+8]	! converted np[0]
132e1051a39Sopenharmony_ci
133e1051a39Sopenharmony_ci	mulx	$lo0,	$n0,	$m1	! "tp[0]"*n0
134e1051a39Sopenharmony_ci	stx	$aj,	[$anp+16]	! converted ap[1]
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$alo	! ap[1]*bp[0]
137e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$aj	! ahi=aj
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$lo1	! np[0]*m1
140e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$hi1
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci	sllx	$t3,	32,	$nj
143e1051a39Sopenharmony_ci	or	$t2,	$nj,	$nj
144e1051a39Sopenharmony_ci	stx	$nj,	[$anp+24]	! converted np[1]
145e1051a39Sopenharmony_ci	add	$anp,	32,	$anp
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci	addcc	$lo0,	$lo1,	$lo1
148e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$nlo	! np[1]*m1
151e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$nj	! nhi=nj
152e1051a39Sopenharmony_ci
153e1051a39Sopenharmony_ci	ba	.L1st
154e1051a39Sopenharmony_ci	sub	$num,	24,	$cnt	! cnt=num-3
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci.align	16
157e1051a39Sopenharmony_ci.L1st:
158e1051a39Sopenharmony_ci	ld	[$ap+0],	$t0	! ap[j]
159e1051a39Sopenharmony_ci	addcc	$alo,	$hi0,	$lo0
160e1051a39Sopenharmony_ci	ld	[$ap+4],	$t1
161e1051a39Sopenharmony_ci	addxc	$aj,	%g0,	$hi0
162e1051a39Sopenharmony_ci
163e1051a39Sopenharmony_ci	sllx	$t1,	32,	$aj
164e1051a39Sopenharmony_ci	add	$ap,	8,	$ap
165e1051a39Sopenharmony_ci	or	$t0,	$aj,	$aj
166e1051a39Sopenharmony_ci	stx	$aj,	[$anp]		! converted ap[j]
167e1051a39Sopenharmony_ci
168e1051a39Sopenharmony_ci	ld	[$np+0],	$t2	! np[j]
169e1051a39Sopenharmony_ci	addcc	$nlo,	$hi1,	$lo1
170e1051a39Sopenharmony_ci	ld	[$np+4],	$t3
171e1051a39Sopenharmony_ci	addxc	$nj,	%g0,	$hi1	! nhi=nj
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci	sllx	$t3,	32,	$nj
174e1051a39Sopenharmony_ci	add	$np,	8,	$np
175e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$alo	! ap[j]*bp[0]
176e1051a39Sopenharmony_ci	or	$t2,	$nj,	$nj
177e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$aj	! ahi=aj
178e1051a39Sopenharmony_ci	stx	$nj,	[$anp+8]	! converted np[j]
179e1051a39Sopenharmony_ci	add	$anp,	16,	$anp	! anp++
180e1051a39Sopenharmony_ci
181e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$nlo	! np[j]*m1
182e1051a39Sopenharmony_ci	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
183e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$nj	! nhi=nj
184e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
185e1051a39Sopenharmony_ci	stx	$lo1,	[$tp]		! tp[j-1]
186e1051a39Sopenharmony_ci	add	$tp,	8,	$tp	! tp++
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ci	brnz,pt	$cnt,	.L1st
189e1051a39Sopenharmony_ci	sub	$cnt,	8,	$cnt	! j--
190e1051a39Sopenharmony_ci!.L1st
191e1051a39Sopenharmony_ci	addcc	$alo,	$hi0,	$lo0
192e1051a39Sopenharmony_ci	addxc	$aj,	%g0,	$hi0	! ahi=aj
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ci	addcc	$nlo,	$hi1,	$lo1
195e1051a39Sopenharmony_ci	addxc	$nj,	%g0,	$hi1
196e1051a39Sopenharmony_ci	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
197e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
198e1051a39Sopenharmony_ci	stx	$lo1,	[$tp]		! tp[j-1]
199e1051a39Sopenharmony_ci	add	$tp,	8,	$tp
200e1051a39Sopenharmony_ci
201e1051a39Sopenharmony_ci	addcc	$hi0,	$hi1,	$hi1
202e1051a39Sopenharmony_ci	addxc	%g0,	%g0,	$ovf	! upmost overflow bit
203e1051a39Sopenharmony_ci	stx	$hi1,	[$tp]
204e1051a39Sopenharmony_ci	add	$tp,	8,	$tp
205e1051a39Sopenharmony_ci
206e1051a39Sopenharmony_ci	ba	.Louter
207e1051a39Sopenharmony_ci	sub	$num,	16,	$i	! i=num-2
208e1051a39Sopenharmony_ci
209e1051a39Sopenharmony_ci.align	16
210e1051a39Sopenharmony_ci.Louter:
211e1051a39Sopenharmony_ci	ld	[$bp+0],	$t2	! m0=bp[i]
212e1051a39Sopenharmony_ci	ld	[$bp+4],	$t3
213e1051a39Sopenharmony_ci
214e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp	! rewind
215e1051a39Sopenharmony_ci	sub	$tp,	$num,	$tp
216e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp
217e1051a39Sopenharmony_ci
218e1051a39Sopenharmony_ci	add	$bp,	8,	$bp
219e1051a39Sopenharmony_ci	sllx	$t3,	32,	$m0
220e1051a39Sopenharmony_ci	ldx	[$anp+0],	$aj	! ap[0]
221e1051a39Sopenharmony_ci	or	$t2,	$m0,	$m0
222e1051a39Sopenharmony_ci	ldx	[$anp+8],	$nj	! np[0]
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[i]
225e1051a39Sopenharmony_ci	ldx	[$tp],		$tj	! tp[0]
226e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$hi0
227e1051a39Sopenharmony_ci	ldx	[$anp+16],	$aj	! ap[1]
228e1051a39Sopenharmony_ci	addcc	$lo0,	$tj,	$lo0	! ap[0]*bp[i]+tp[0]
229e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$alo	! ap[1]*bp[i]
230e1051a39Sopenharmony_ci	addxc	%g0,	$hi0,	$hi0
231e1051a39Sopenharmony_ci	mulx	$lo0,	$n0,	$m1	! tp[0]*n0
232e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$aj	! ahi=aj
233e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$lo1	! np[0]*m1
234e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$hi1
235e1051a39Sopenharmony_ci	ldx	[$anp+24],	$nj	! np[1]
236e1051a39Sopenharmony_ci	add	$anp,	32,	$anp
237e1051a39Sopenharmony_ci	addcc	$lo1,	$lo0,	$lo1
238e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$nlo	! np[1]*m1
239e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
240e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$nj	! nhi=nj
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci	ba	.Linner
243e1051a39Sopenharmony_ci	sub	$num,	24,	$cnt	! cnt=num-3
244e1051a39Sopenharmony_ci.align	16
245e1051a39Sopenharmony_ci.Linner:
246e1051a39Sopenharmony_ci	addcc	$alo,	$hi0,	$lo0
247e1051a39Sopenharmony_ci	ldx	[$tp+8],	$tj	! tp[j]
248e1051a39Sopenharmony_ci	addxc	$aj,	%g0,	$hi0	! ahi=aj
249e1051a39Sopenharmony_ci	ldx	[$anp+0],	$aj	! ap[j]
250e1051a39Sopenharmony_ci	addcc	$nlo,	$hi1,	$lo1
251e1051a39Sopenharmony_ci	mulx	$aj,	$m0,	$alo	! ap[j]*bp[i]
252e1051a39Sopenharmony_ci	addxc	$nj,	%g0,	$hi1	! nhi=nj
253e1051a39Sopenharmony_ci	ldx	[$anp+8],	$nj	! np[j]
254e1051a39Sopenharmony_ci	add	$anp,	16,	$anp
255e1051a39Sopenharmony_ci	umulxhi	$aj,	$m0,	$aj	! ahi=aj
256e1051a39Sopenharmony_ci	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
257e1051a39Sopenharmony_ci	mulx	$nj,	$m1,	$nlo	! np[j]*m1
258e1051a39Sopenharmony_ci	addxc	%g0,	$hi0,	$hi0
259e1051a39Sopenharmony_ci	umulxhi	$nj,	$m1,	$nj	! nhi=nj
260e1051a39Sopenharmony_ci	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
261e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
262e1051a39Sopenharmony_ci	stx	$lo1,	[$tp]		! tp[j-1]
263e1051a39Sopenharmony_ci	add	$tp,	8,	$tp
264e1051a39Sopenharmony_ci	brnz,pt	$cnt,	.Linner
265e1051a39Sopenharmony_ci	sub	$cnt,	8,	$cnt
266e1051a39Sopenharmony_ci!.Linner
267e1051a39Sopenharmony_ci	ldx	[$tp+8],	$tj	! tp[j]
268e1051a39Sopenharmony_ci	addcc	$alo,	$hi0,	$lo0
269e1051a39Sopenharmony_ci	addxc	$aj,	%g0,	$hi0	! ahi=aj
270e1051a39Sopenharmony_ci	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
271e1051a39Sopenharmony_ci	addxc	%g0,	$hi0,	$hi0
272e1051a39Sopenharmony_ci
273e1051a39Sopenharmony_ci	addcc	$nlo,	$hi1,	$lo1
274e1051a39Sopenharmony_ci	addxc	$nj,	%g0,	$hi1	! nhi=nj
275e1051a39Sopenharmony_ci	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
276e1051a39Sopenharmony_ci	addxc	%g0,	$hi1,	$hi1
277e1051a39Sopenharmony_ci	stx	$lo1,	[$tp]		! tp[j-1]
278e1051a39Sopenharmony_ci
279e1051a39Sopenharmony_ci	subcc	%g0,	$ovf,	%g0	! move upmost overflow to CCR.xcc
280e1051a39Sopenharmony_ci	addxccc	$hi1,	$hi0,	$hi1
281e1051a39Sopenharmony_ci	addxc	%g0,	%g0,	$ovf
282e1051a39Sopenharmony_ci	stx	$hi1,	[$tp+8]
283e1051a39Sopenharmony_ci	add	$tp,	16,	$tp
284e1051a39Sopenharmony_ci
285e1051a39Sopenharmony_ci	brnz,pt	$i,	.Louter
286e1051a39Sopenharmony_ci	sub	$i,	8,	$i
287e1051a39Sopenharmony_ci
288e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp	! rewind
289e1051a39Sopenharmony_ci	sub	$tp,	$num,	$tp
290e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp
291e1051a39Sopenharmony_ci	ba	.Lsub
292e1051a39Sopenharmony_ci	subcc	$num,	8,	$cnt	! cnt=num-1 and clear CCR.xcc
293e1051a39Sopenharmony_ci
294e1051a39Sopenharmony_ci.align	16
295e1051a39Sopenharmony_ci.Lsub:
296e1051a39Sopenharmony_ci	ldx	[$tp],		$tj
297e1051a39Sopenharmony_ci	add	$tp,	8,	$tp
298e1051a39Sopenharmony_ci	ldx	[$anp+8],	$nj
299e1051a39Sopenharmony_ci	add	$anp,	16,	$anp
300e1051a39Sopenharmony_ci	subccc	$tj,	$nj,	$t2	! tp[j]-np[j]
301e1051a39Sopenharmony_ci	srlx	$tj,	32,	$tj
302e1051a39Sopenharmony_ci	srlx	$nj,	32,	$nj
303e1051a39Sopenharmony_ci	subccc	$tj,	$nj,	$t3
304e1051a39Sopenharmony_ci	add	$rp,	8,	$rp
305e1051a39Sopenharmony_ci	st	$t2,	[$rp-4]		! reverse order
306e1051a39Sopenharmony_ci	st	$t3,	[$rp-8]
307e1051a39Sopenharmony_ci	brnz,pt	$cnt,	.Lsub
308e1051a39Sopenharmony_ci	sub	$cnt,	8,	$cnt
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp	! rewind
311e1051a39Sopenharmony_ci	sub	$tp,	$num,	$tp
312e1051a39Sopenharmony_ci	sub	$anp,	$num,	$anp
313e1051a39Sopenharmony_ci	sub	$rp,	$num,	$rp
314e1051a39Sopenharmony_ci
315e1051a39Sopenharmony_ci	subccc	$ovf,	%g0,	$ovf	! handle upmost overflow bit
316e1051a39Sopenharmony_ci	ba	.Lcopy
317e1051a39Sopenharmony_ci	sub	$num,	8,	$cnt
318e1051a39Sopenharmony_ci
319e1051a39Sopenharmony_ci.align	16
320e1051a39Sopenharmony_ci.Lcopy:					! conditional copy
321e1051a39Sopenharmony_ci	ld	[$tp+0],	$t0
322e1051a39Sopenharmony_ci	ld	[$tp+4],	$t1
323e1051a39Sopenharmony_ci	ld	[$rp+0],	$t2
324e1051a39Sopenharmony_ci	ld	[$rp+4],	$t3
325e1051a39Sopenharmony_ci	stx	%g0,	[$tp]		! zap
326e1051a39Sopenharmony_ci	add	$tp,	8,	$tp
327e1051a39Sopenharmony_ci	stx	%g0,	[$anp]		! zap
328e1051a39Sopenharmony_ci	stx	%g0,	[$anp+8]
329e1051a39Sopenharmony_ci	add	$anp,	16,	$anp
330e1051a39Sopenharmony_ci	movcs	%icc,	$t0,	$t2
331e1051a39Sopenharmony_ci	movcs	%icc,	$t1,	$t3
332e1051a39Sopenharmony_ci	st	$t3,	[$rp+0]		! flip order
333e1051a39Sopenharmony_ci	st	$t2,	[$rp+4]
334e1051a39Sopenharmony_ci	add	$rp,	8,	$rp
335e1051a39Sopenharmony_ci	brnz	$cnt,	.Lcopy
336e1051a39Sopenharmony_ci	sub	$cnt,	8,	$cnt
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci	mov	1,	%o0
339e1051a39Sopenharmony_ci	ret
340e1051a39Sopenharmony_ci	restore
341e1051a39Sopenharmony_ci.type	bn_mul_mont_vis3, #function
342e1051a39Sopenharmony_ci.size	bn_mul_mont_vis3, .-bn_mul_mont_vis3
343e1051a39Sopenharmony_ci.asciz  "Montgomery Multiplication for SPARCv9 VIS3, CRYPTOGAMS by <appro\@openssl.org>"
344e1051a39Sopenharmony_ci.align	4
345e1051a39Sopenharmony_ci___
346e1051a39Sopenharmony_ci
347e1051a39Sopenharmony_ci# Purpose of these subroutines is to explicitly encode VIS instructions,
348e1051a39Sopenharmony_ci# so that one can compile the module without having to specify VIS
349e1051a39Sopenharmony_ci# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
350e1051a39Sopenharmony_ci# Idea is to reserve for option to produce "universal" binary and let
351e1051a39Sopenharmony_ci# programmer detect if current CPU is VIS capable at run-time.
352e1051a39Sopenharmony_cisub unvis3 {
353e1051a39Sopenharmony_cimy ($mnemonic,$rs1,$rs2,$rd)=@_;
354e1051a39Sopenharmony_cimy %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
355e1051a39Sopenharmony_cimy ($ref,$opf);
356e1051a39Sopenharmony_cimy %visopf = (	"addxc"		=> 0x011,
357e1051a39Sopenharmony_ci		"addxccc"	=> 0x013,
358e1051a39Sopenharmony_ci		"umulxhi"	=> 0x016	);
359e1051a39Sopenharmony_ci
360e1051a39Sopenharmony_ci    $ref = "$mnemonic\t$rs1,$rs2,$rd";
361e1051a39Sopenharmony_ci
362e1051a39Sopenharmony_ci    if ($opf=$visopf{$mnemonic}) {
363e1051a39Sopenharmony_ci	foreach ($rs1,$rs2,$rd) {
364e1051a39Sopenharmony_ci	    return $ref if (!/%([goli])([0-9])/);
365e1051a39Sopenharmony_ci	    $_=$bias{$1}+$2;
366e1051a39Sopenharmony_ci	}
367e1051a39Sopenharmony_ci
368e1051a39Sopenharmony_ci	return	sprintf ".word\t0x%08x !%s",
369e1051a39Sopenharmony_ci			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
370e1051a39Sopenharmony_ci			$ref;
371e1051a39Sopenharmony_ci    } else {
372e1051a39Sopenharmony_ci	return $ref;
373e1051a39Sopenharmony_ci    }
374e1051a39Sopenharmony_ci}
375e1051a39Sopenharmony_ci
376e1051a39Sopenharmony_ciforeach (split("\n",$code)) {
377e1051a39Sopenharmony_ci	s/\`([^\`]*)\`/eval $1/ge;
378e1051a39Sopenharmony_ci
379e1051a39Sopenharmony_ci	s/\b(umulxhi|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
380e1051a39Sopenharmony_ci		&unvis3($1,$2,$3,$4)
381e1051a39Sopenharmony_ci	 /ge;
382e1051a39Sopenharmony_ci
383e1051a39Sopenharmony_ci	print $_,"\n";
384e1051a39Sopenharmony_ci}
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_ciclose STDOUT or die "error closing STDOUT: $!";
387