1289848Sjkim#!/usr/bin/env perl
2289848Sjkim
3289848Sjkim##############################################################################
4289848Sjkim#                                                                            #
5289848Sjkim# Copyright 2014 Intel Corporation                                           #
6289848Sjkim#                                                                            #
7289848Sjkim# Licensed under the Apache License, Version 2.0 (the "License");            #
8289848Sjkim# you may not use this file except in compliance with the License.           #
9289848Sjkim# You may obtain a copy of the License at                                    #
10289848Sjkim#                                                                            #
11289848Sjkim#    http://www.apache.org/licenses/LICENSE-2.0                              #
12289848Sjkim#                                                                            #
13289848Sjkim# Unless required by applicable law or agreed to in writing, software        #
14289848Sjkim# distributed under the License is distributed on an "AS IS" BASIS,          #
15289848Sjkim# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
16289848Sjkim# See the License for the specific language governing permissions and        #
17289848Sjkim# limitations under the License.                                             #
18289848Sjkim#                                                                            #
19289848Sjkim##############################################################################
20289848Sjkim#                                                                            #
21289848Sjkim#  Developers and authors:                                                   #
22289848Sjkim#  Shay Gueron (1, 2), and Vlad Krasnov (1)                                  #
23289848Sjkim#  (1) Intel Corporation, Israel Development Center                          #
24289848Sjkim#  (2) University of Haifa                                                   #
25289848Sjkim#  Reference:                                                                #
26289848Sjkim#  S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with#
27289848Sjkim#                           256 Bit Primes"                                  #
28289848Sjkim#                                                                            #
29289848Sjkim##############################################################################
30289848Sjkim
31289848Sjkim# Further optimization by <appro@openssl.org>:
32289848Sjkim#
33289848Sjkim#		this/original	with/without -DECP_NISTZ256_ASM(*)
34289848Sjkim# Opteron	+12-49%		+110-150%
35289848Sjkim# Bulldozer	+14-45%		+175-210%
36289848Sjkim# P4		+18-46%		n/a :-(
37289848Sjkim# Westmere	+12-34%		+80-87%
38289848Sjkim# Sandy Bridge	+9-35%		+110-120%
39289848Sjkim# Ivy Bridge	+9-35%		+110-125%
40289848Sjkim# Haswell	+8-37%		+140-160%
41289848Sjkim# Broadwell	+18-58%		+145-210%
42289848Sjkim# Atom		+15-50%		+130-180%
43289848Sjkim# VIA Nano	+43-160%	+300-480%
44289848Sjkim#
45289848Sjkim# (*)	"without -DECP_NISTZ256_ASM" refers to build with
46289848Sjkim#	"enable-ec_nistp_64_gcc_128";
47289848Sjkim#
48289848Sjkim# Ranges denote minimum and maximum improvement coefficients depending
49289848Sjkim# on benchmark. Lower coefficients are for ECDSA sign, relatively fastest
50289848Sjkim# server-side operation. Keep in mind that +100% means 2x improvement.
51289848Sjkim
52289848Sjkim$flavour = shift;
53289848Sjkim$output  = shift;
54289848Sjkimif ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
55289848Sjkim
56289848Sjkim$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
57289848Sjkim
58289848Sjkim$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
59289848Sjkim( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
60289848Sjkim( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
61289848Sjkimdie "can't locate x86_64-xlate.pl";
62289848Sjkim
63289848Sjkimopen OUT,"| \"$^X\" $xlate $flavour $output";
64289848Sjkim*STDOUT=*OUT;
65289848Sjkim
66289848Sjkimif (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
67289848Sjkim		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
68289848Sjkim	$avx = ($1>=2.19) + ($1>=2.22);
69289848Sjkim	$addx = ($1>=2.23);
70289848Sjkim}
71289848Sjkim
72289848Sjkimif (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
73289848Sjkim	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
74289848Sjkim	$avx = ($1>=2.09) + ($1>=2.10);
75289848Sjkim	$addx = ($1>=2.10);
76289848Sjkim}
77289848Sjkim
78289848Sjkimif (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
79289848Sjkim	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
80289848Sjkim	$avx = ($1>=10) + ($1>=11);
81289848Sjkim	$addx = ($1>=12);
82289848Sjkim}
83289848Sjkim
84295009Sjkimif (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
85289848Sjkim	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
86289848Sjkim	$avx = ($ver>=3.0) + ($ver>=3.01);
87289848Sjkim	$addx = ($ver>=3.03);
88289848Sjkim}
89289848Sjkim
90289848Sjkim$code.=<<___;
91289848Sjkim.text
92289848Sjkim.extern	OPENSSL_ia32cap_P
93289848Sjkim
94289848Sjkim# The polynomial
95289848Sjkim.align 64
96289848Sjkim.Lpoly:
97289848Sjkim.quad 0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001
98289848Sjkim
99289848Sjkim# 2^512 mod P precomputed for NIST P256 polynomial
100289848Sjkim.LRR:
101289848Sjkim.quad 0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd
102289848Sjkim
103289848Sjkim.LOne:
104289848Sjkim.long 1,1,1,1,1,1,1,1
105289848Sjkim.LTwo:
106289848Sjkim.long 2,2,2,2,2,2,2,2
107289848Sjkim.LThree:
108289848Sjkim.long 3,3,3,3,3,3,3,3
109289848Sjkim.LONE_mont:
110289848Sjkim.quad 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
111289848Sjkim___
112289848Sjkim
113289848Sjkim{
114289848Sjkim################################################################################
115289848Sjkim# void ecp_nistz256_mul_by_2(uint64_t res[4], uint64_t a[4]);
116289848Sjkim
117289848Sjkimmy ($a0,$a1,$a2,$a3)=map("%r$_",(8..11));
118289848Sjkimmy ($t0,$t1,$t2,$t3,$t4)=("%rax","%rdx","%rcx","%r12","%r13");
119289848Sjkimmy ($r_ptr,$a_ptr,$b_ptr)=("%rdi","%rsi","%rdx");
120289848Sjkim
121289848Sjkim$code.=<<___;
122289848Sjkim
123289848Sjkim.globl	ecp_nistz256_mul_by_2
124289848Sjkim.type	ecp_nistz256_mul_by_2,\@function,2
125289848Sjkim.align	64
126289848Sjkimecp_nistz256_mul_by_2:
127289848Sjkim	push	%r12
128289848Sjkim	push	%r13
129289848Sjkim
130289848Sjkim	mov	8*0($a_ptr), $a0
131306195Sjkim	xor	$t4,$t4
132289848Sjkim	mov	8*1($a_ptr), $a1
133289848Sjkim	add	$a0, $a0		# a0:a3+a0:a3
134289848Sjkim	mov	8*2($a_ptr), $a2
135289848Sjkim	adc	$a1, $a1
136289848Sjkim	mov	8*3($a_ptr), $a3
137289848Sjkim	lea	.Lpoly(%rip), $a_ptr
138289848Sjkim	 mov	$a0, $t0
139289848Sjkim	adc	$a2, $a2
140289848Sjkim	adc	$a3, $a3
141289848Sjkim	 mov	$a1, $t1
142306195Sjkim	adc	\$0, $t4
143289848Sjkim
144289848Sjkim	sub	8*0($a_ptr), $a0
145289848Sjkim	 mov	$a2, $t2
146289848Sjkim	sbb	8*1($a_ptr), $a1
147289848Sjkim	sbb	8*2($a_ptr), $a2
148289848Sjkim	 mov	$a3, $t3
149289848Sjkim	sbb	8*3($a_ptr), $a3
150306195Sjkim	sbb	\$0, $t4
151289848Sjkim
152306195Sjkim	cmovc	$t0, $a0
153306195Sjkim	cmovc	$t1, $a1
154289848Sjkim	mov	$a0, 8*0($r_ptr)
155306195Sjkim	cmovc	$t2, $a2
156289848Sjkim	mov	$a1, 8*1($r_ptr)
157306195Sjkim	cmovc	$t3, $a3
158289848Sjkim	mov	$a2, 8*2($r_ptr)
159289848Sjkim	mov	$a3, 8*3($r_ptr)
160289848Sjkim
161289848Sjkim	pop	%r13
162289848Sjkim	pop	%r12
163289848Sjkim	ret
164289848Sjkim.size	ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
165289848Sjkim
166289848Sjkim################################################################################
167289848Sjkim# void ecp_nistz256_div_by_2(uint64_t res[4], uint64_t a[4]);
168289848Sjkim.globl	ecp_nistz256_div_by_2
169289848Sjkim.type	ecp_nistz256_div_by_2,\@function,2
170289848Sjkim.align	32
171289848Sjkimecp_nistz256_div_by_2:
172289848Sjkim	push	%r12
173289848Sjkim	push	%r13
174289848Sjkim
175289848Sjkim	mov	8*0($a_ptr), $a0
176289848Sjkim	mov	8*1($a_ptr), $a1
177289848Sjkim	mov	8*2($a_ptr), $a2
178289848Sjkim	 mov	$a0, $t0
179289848Sjkim	mov	8*3($a_ptr), $a3
180289848Sjkim	lea	.Lpoly(%rip), $a_ptr
181289848Sjkim
182289848Sjkim	 mov	$a1, $t1
183289848Sjkim	xor	$t4, $t4
184289848Sjkim	add	8*0($a_ptr), $a0
185289848Sjkim	 mov	$a2, $t2
186289848Sjkim	adc	8*1($a_ptr), $a1
187289848Sjkim	adc	8*2($a_ptr), $a2
188289848Sjkim	 mov	$a3, $t3
189289848Sjkim	adc	8*3($a_ptr), $a3
190289848Sjkim	adc	\$0, $t4
191289848Sjkim	xor	$a_ptr, $a_ptr		# borrow $a_ptr
192289848Sjkim	test	\$1, $t0
193289848Sjkim
194289848Sjkim	cmovz	$t0, $a0
195289848Sjkim	cmovz	$t1, $a1
196289848Sjkim	cmovz	$t2, $a2
197289848Sjkim	cmovz	$t3, $a3
198289848Sjkim	cmovz	$a_ptr, $t4
199289848Sjkim
200289848Sjkim	mov	$a1, $t0		# a0:a3>>1
201289848Sjkim	shr	\$1, $a0
202289848Sjkim	shl	\$63, $t0
203289848Sjkim	mov	$a2, $t1
204289848Sjkim	shr	\$1, $a1
205289848Sjkim	or	$t0, $a0
206289848Sjkim	shl	\$63, $t1
207289848Sjkim	mov	$a3, $t2
208289848Sjkim	shr	\$1, $a2
209289848Sjkim	or	$t1, $a1
210289848Sjkim	shl	\$63, $t2
211289848Sjkim	shr	\$1, $a3
212289848Sjkim	shl	\$63, $t4
213289848Sjkim	or	$t2, $a2
214289848Sjkim	or	$t4, $a3
215289848Sjkim
216289848Sjkim	mov	$a0, 8*0($r_ptr)
217289848Sjkim	mov	$a1, 8*1($r_ptr)
218289848Sjkim	mov	$a2, 8*2($r_ptr)
219289848Sjkim	mov	$a3, 8*3($r_ptr)
220289848Sjkim
221289848Sjkim	pop	%r13
222289848Sjkim	pop	%r12
223289848Sjkim	ret
224289848Sjkim.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
225289848Sjkim
226289848Sjkim################################################################################
227289848Sjkim# void ecp_nistz256_mul_by_3(uint64_t res[4], uint64_t a[4]);
228289848Sjkim.globl	ecp_nistz256_mul_by_3
229289848Sjkim.type	ecp_nistz256_mul_by_3,\@function,2
230289848Sjkim.align	32
231289848Sjkimecp_nistz256_mul_by_3:
232289848Sjkim	push	%r12
233289848Sjkim	push	%r13
234289848Sjkim
235289848Sjkim	mov	8*0($a_ptr), $a0
236289848Sjkim	xor	$t4, $t4
237289848Sjkim	mov	8*1($a_ptr), $a1
238289848Sjkim	add	$a0, $a0		# a0:a3+a0:a3
239289848Sjkim	mov	8*2($a_ptr), $a2
240289848Sjkim	adc	$a1, $a1
241289848Sjkim	mov	8*3($a_ptr), $a3
242289848Sjkim	 mov	$a0, $t0
243289848Sjkim	adc	$a2, $a2
244289848Sjkim	adc	$a3, $a3
245289848Sjkim	 mov	$a1, $t1
246289848Sjkim	adc	\$0, $t4
247289848Sjkim
248289848Sjkim	sub	\$-1, $a0
249289848Sjkim	 mov	$a2, $t2
250289848Sjkim	sbb	.Lpoly+8*1(%rip), $a1
251289848Sjkim	sbb	\$0, $a2
252289848Sjkim	 mov	$a3, $t3
253289848Sjkim	sbb	.Lpoly+8*3(%rip), $a3
254306195Sjkim	sbb	\$0, $t4
255289848Sjkim
256306195Sjkim	cmovc	$t0, $a0
257306195Sjkim	cmovc	$t1, $a1
258306195Sjkim	cmovc	$t2, $a2
259306195Sjkim	cmovc	$t3, $a3
260289848Sjkim
261289848Sjkim	xor	$t4, $t4
262289848Sjkim	add	8*0($a_ptr), $a0	# a0:a3+=a_ptr[0:3]
263289848Sjkim	adc	8*1($a_ptr), $a1
264289848Sjkim	 mov	$a0, $t0
265289848Sjkim	adc	8*2($a_ptr), $a2
266289848Sjkim	adc	8*3($a_ptr), $a3
267289848Sjkim	 mov	$a1, $t1
268289848Sjkim	adc	\$0, $t4
269289848Sjkim
270289848Sjkim	sub	\$-1, $a0
271289848Sjkim	 mov	$a2, $t2
272289848Sjkim	sbb	.Lpoly+8*1(%rip), $a1
273289848Sjkim	sbb	\$0, $a2
274289848Sjkim	 mov	$a3, $t3
275289848Sjkim	sbb	.Lpoly+8*3(%rip), $a3
276306195Sjkim	sbb	\$0, $t4
277289848Sjkim
278306195Sjkim	cmovc	$t0, $a0
279306195Sjkim	cmovc	$t1, $a1
280289848Sjkim	mov	$a0, 8*0($r_ptr)
281306195Sjkim	cmovc	$t2, $a2
282289848Sjkim	mov	$a1, 8*1($r_ptr)
283306195Sjkim	cmovc	$t3, $a3
284289848Sjkim	mov	$a2, 8*2($r_ptr)
285289848Sjkim	mov	$a3, 8*3($r_ptr)
286289848Sjkim
287289848Sjkim	pop %r13
288289848Sjkim	pop %r12
289289848Sjkim	ret
290289848Sjkim.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
291289848Sjkim
292289848Sjkim################################################################################
293289848Sjkim# void ecp_nistz256_add(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
294289848Sjkim.globl	ecp_nistz256_add
295289848Sjkim.type	ecp_nistz256_add,\@function,3
296289848Sjkim.align	32
297289848Sjkimecp_nistz256_add:
298289848Sjkim	push	%r12
299289848Sjkim	push	%r13
300289848Sjkim
301289848Sjkim	mov	8*0($a_ptr), $a0
302289848Sjkim	xor	$t4, $t4
303289848Sjkim	mov	8*1($a_ptr), $a1
304289848Sjkim	mov	8*2($a_ptr), $a2
305289848Sjkim	mov	8*3($a_ptr), $a3
306289848Sjkim	lea	.Lpoly(%rip), $a_ptr
307289848Sjkim
308289848Sjkim	add	8*0($b_ptr), $a0
309289848Sjkim	adc	8*1($b_ptr), $a1
310289848Sjkim	 mov	$a0, $t0
311289848Sjkim	adc	8*2($b_ptr), $a2
312289848Sjkim	adc	8*3($b_ptr), $a3
313289848Sjkim	 mov	$a1, $t1
314289848Sjkim	adc	\$0, $t4
315289848Sjkim
316289848Sjkim	sub	8*0($a_ptr), $a0
317289848Sjkim	 mov	$a2, $t2
318289848Sjkim	sbb	8*1($a_ptr), $a1
319289848Sjkim	sbb	8*2($a_ptr), $a2
320289848Sjkim	 mov	$a3, $t3
321289848Sjkim	sbb	8*3($a_ptr), $a3
322306195Sjkim	sbb	\$0, $t4
323289848Sjkim
324306195Sjkim	cmovc	$t0, $a0
325306195Sjkim	cmovc	$t1, $a1
326289848Sjkim	mov	$a0, 8*0($r_ptr)
327306195Sjkim	cmovc	$t2, $a2
328289848Sjkim	mov	$a1, 8*1($r_ptr)
329306195Sjkim	cmovc	$t3, $a3
330289848Sjkim	mov	$a2, 8*2($r_ptr)
331289848Sjkim	mov	$a3, 8*3($r_ptr)
332289848Sjkim
333289848Sjkim	pop %r13
334289848Sjkim	pop %r12
335289848Sjkim	ret
336289848Sjkim.size	ecp_nistz256_add,.-ecp_nistz256_add
337289848Sjkim
338289848Sjkim################################################################################
339289848Sjkim# void ecp_nistz256_sub(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
340289848Sjkim.globl	ecp_nistz256_sub
341289848Sjkim.type	ecp_nistz256_sub,\@function,3
342289848Sjkim.align	32
343289848Sjkimecp_nistz256_sub:
344289848Sjkim	push	%r12
345289848Sjkim	push	%r13
346289848Sjkim
347289848Sjkim	mov	8*0($a_ptr), $a0
348289848Sjkim	xor	$t4, $t4
349289848Sjkim	mov	8*1($a_ptr), $a1
350289848Sjkim	mov	8*2($a_ptr), $a2
351289848Sjkim	mov	8*3($a_ptr), $a3
352289848Sjkim	lea	.Lpoly(%rip), $a_ptr
353289848Sjkim
354289848Sjkim	sub	8*0($b_ptr), $a0
355289848Sjkim	sbb	8*1($b_ptr), $a1
356289848Sjkim	 mov	$a0, $t0
357289848Sjkim	sbb	8*2($b_ptr), $a2
358289848Sjkim	sbb	8*3($b_ptr), $a3
359289848Sjkim	 mov	$a1, $t1
360289848Sjkim	sbb	\$0, $t4
361289848Sjkim
362289848Sjkim	add	8*0($a_ptr), $a0
363289848Sjkim	 mov	$a2, $t2
364289848Sjkim	adc	8*1($a_ptr), $a1
365289848Sjkim	adc	8*2($a_ptr), $a2
366289848Sjkim	 mov	$a3, $t3
367289848Sjkim	adc	8*3($a_ptr), $a3
368289848Sjkim	test	$t4, $t4
369289848Sjkim
370289848Sjkim	cmovz	$t0, $a0
371289848Sjkim	cmovz	$t1, $a1
372289848Sjkim	mov	$a0, 8*0($r_ptr)
373289848Sjkim	cmovz	$t2, $a2
374289848Sjkim	mov	$a1, 8*1($r_ptr)
375289848Sjkim	cmovz	$t3, $a3
376289848Sjkim	mov	$a2, 8*2($r_ptr)
377289848Sjkim	mov	$a3, 8*3($r_ptr)
378289848Sjkim
379289848Sjkim	pop %r13
380289848Sjkim	pop %r12
381289848Sjkim	ret
382289848Sjkim.size	ecp_nistz256_sub,.-ecp_nistz256_sub
383289848Sjkim
384289848Sjkim################################################################################
385289848Sjkim# void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
386289848Sjkim.globl	ecp_nistz256_neg
387289848Sjkim.type	ecp_nistz256_neg,\@function,2
388289848Sjkim.align	32
389289848Sjkimecp_nistz256_neg:
390289848Sjkim	push	%r12
391289848Sjkim	push	%r13
392289848Sjkim
393289848Sjkim	xor	$a0, $a0
394289848Sjkim	xor	$a1, $a1
395289848Sjkim	xor	$a2, $a2
396289848Sjkim	xor	$a3, $a3
397289848Sjkim	xor	$t4, $t4
398289848Sjkim
399289848Sjkim	sub	8*0($a_ptr), $a0
400289848Sjkim	sbb	8*1($a_ptr), $a1
401289848Sjkim	sbb	8*2($a_ptr), $a2
402289848Sjkim	 mov	$a0, $t0
403289848Sjkim	sbb	8*3($a_ptr), $a3
404289848Sjkim	lea	.Lpoly(%rip), $a_ptr
405289848Sjkim	 mov	$a1, $t1
406289848Sjkim	sbb	\$0, $t4
407289848Sjkim
408289848Sjkim	add	8*0($a_ptr), $a0
409289848Sjkim	 mov	$a2, $t2
410289848Sjkim	adc	8*1($a_ptr), $a1
411289848Sjkim	adc	8*2($a_ptr), $a2
412289848Sjkim	 mov	$a3, $t3
413289848Sjkim	adc	8*3($a_ptr), $a3
414289848Sjkim	test	$t4, $t4
415289848Sjkim
416289848Sjkim	cmovz	$t0, $a0
417289848Sjkim	cmovz	$t1, $a1
418289848Sjkim	mov	$a0, 8*0($r_ptr)
419289848Sjkim	cmovz	$t2, $a2
420289848Sjkim	mov	$a1, 8*1($r_ptr)
421289848Sjkim	cmovz	$t3, $a3
422289848Sjkim	mov	$a2, 8*2($r_ptr)
423289848Sjkim	mov	$a3, 8*3($r_ptr)
424289848Sjkim
425289848Sjkim	pop %r13
426289848Sjkim	pop %r12
427289848Sjkim	ret
428289848Sjkim.size	ecp_nistz256_neg,.-ecp_nistz256_neg
429289848Sjkim___
430289848Sjkim}
431289848Sjkim{
432289848Sjkimmy ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
433289848Sjkimmy ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
434289848Sjkimmy ($t0,$t1,$t2,$t3,$t4)=("%rcx","%rbp","%rbx","%rdx","%rax");
435289848Sjkimmy ($poly1,$poly3)=($acc6,$acc7);
436289848Sjkim
437289848Sjkim$code.=<<___;
438289848Sjkim################################################################################
439289848Sjkim# void ecp_nistz256_to_mont(
440289848Sjkim#   uint64_t res[4],
441289848Sjkim#   uint64_t in[4]);
442289848Sjkim.globl	ecp_nistz256_to_mont
443289848Sjkim.type	ecp_nistz256_to_mont,\@function,2
444289848Sjkim.align	32
445289848Sjkimecp_nistz256_to_mont:
446289848Sjkim___
447289848Sjkim$code.=<<___	if ($addx);
448289848Sjkim	mov	\$0x80100, %ecx
449289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
450289848Sjkim___
451289848Sjkim$code.=<<___;
452289848Sjkim	lea	.LRR(%rip), $b_org
453289848Sjkim	jmp	.Lmul_mont
454289848Sjkim.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
455289848Sjkim
456289848Sjkim################################################################################
457289848Sjkim# void ecp_nistz256_mul_mont(
458289848Sjkim#   uint64_t res[4],
459289848Sjkim#   uint64_t a[4],
460289848Sjkim#   uint64_t b[4]);
461289848Sjkim
462289848Sjkim.globl	ecp_nistz256_mul_mont
463289848Sjkim.type	ecp_nistz256_mul_mont,\@function,3
464289848Sjkim.align	32
465289848Sjkimecp_nistz256_mul_mont:
466289848Sjkim___
467289848Sjkim$code.=<<___	if ($addx);
468289848Sjkim	mov	\$0x80100, %ecx
469289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
470289848Sjkim___
471289848Sjkim$code.=<<___;
472289848Sjkim.Lmul_mont:
473289848Sjkim	push	%rbp
474289848Sjkim	push	%rbx
475289848Sjkim	push	%r12
476289848Sjkim	push	%r13
477289848Sjkim	push	%r14
478289848Sjkim	push	%r15
479289848Sjkim___
480289848Sjkim$code.=<<___	if ($addx);
481289848Sjkim	cmp	\$0x80100, %ecx
482289848Sjkim	je	.Lmul_montx
483289848Sjkim___
484289848Sjkim$code.=<<___;
485289848Sjkim	mov	$b_org, $b_ptr
486289848Sjkim	mov	8*0($b_org), %rax
487289848Sjkim	mov	8*0($a_ptr), $acc1
488289848Sjkim	mov	8*1($a_ptr), $acc2
489289848Sjkim	mov	8*2($a_ptr), $acc3
490289848Sjkim	mov	8*3($a_ptr), $acc4
491289848Sjkim
492289848Sjkim	call	__ecp_nistz256_mul_montq
493289848Sjkim___
494289848Sjkim$code.=<<___	if ($addx);
495289848Sjkim	jmp	.Lmul_mont_done
496289848Sjkim
497289848Sjkim.align	32
498289848Sjkim.Lmul_montx:
499289848Sjkim	mov	$b_org, $b_ptr
500289848Sjkim	mov	8*0($b_org), %rdx
501289848Sjkim	mov	8*0($a_ptr), $acc1
502289848Sjkim	mov	8*1($a_ptr), $acc2
503289848Sjkim	mov	8*2($a_ptr), $acc3
504289848Sjkim	mov	8*3($a_ptr), $acc4
505289848Sjkim	lea	-128($a_ptr), $a_ptr	# control u-op density
506289848Sjkim
507289848Sjkim	call	__ecp_nistz256_mul_montx
508289848Sjkim___
509289848Sjkim$code.=<<___;
510289848Sjkim.Lmul_mont_done:
511289848Sjkim	pop	%r15
512289848Sjkim	pop	%r14
513289848Sjkim	pop	%r13
514289848Sjkim	pop	%r12
515289848Sjkim	pop	%rbx
516289848Sjkim	pop	%rbp
517289848Sjkim	ret
518289848Sjkim.size	ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
519289848Sjkim
520289848Sjkim.type	__ecp_nistz256_mul_montq,\@abi-omnipotent
521289848Sjkim.align	32
522289848Sjkim__ecp_nistz256_mul_montq:
523289848Sjkim	########################################################################
524289848Sjkim	# Multiply a by b[0]
525289848Sjkim	mov	%rax, $t1
526289848Sjkim	mulq	$acc1
527289848Sjkim	mov	.Lpoly+8*1(%rip),$poly1
528289848Sjkim	mov	%rax, $acc0
529289848Sjkim	mov	$t1, %rax
530289848Sjkim	mov	%rdx, $acc1
531289848Sjkim
532289848Sjkim	mulq	$acc2
533289848Sjkim	mov	.Lpoly+8*3(%rip),$poly3
534289848Sjkim	add	%rax, $acc1
535289848Sjkim	mov	$t1, %rax
536289848Sjkim	adc	\$0, %rdx
537289848Sjkim	mov	%rdx, $acc2
538289848Sjkim
539289848Sjkim	mulq	$acc3
540289848Sjkim	add	%rax, $acc2
541289848Sjkim	mov	$t1, %rax
542289848Sjkim	adc	\$0, %rdx
543289848Sjkim	mov	%rdx, $acc3
544289848Sjkim
545289848Sjkim	mulq	$acc4
546289848Sjkim	add	%rax, $acc3
547289848Sjkim	 mov	$acc0, %rax
548289848Sjkim	adc	\$0, %rdx
549289848Sjkim	xor	$acc5, $acc5
550289848Sjkim	mov	%rdx, $acc4
551289848Sjkim
552289848Sjkim	########################################################################
553289848Sjkim	# First reduction step
554289848Sjkim	# Basically now we want to multiply acc[0] by p256,
555289848Sjkim	# and add the result to the acc.
556289848Sjkim	# Due to the special form of p256 we do some optimizations
557289848Sjkim	#
558289848Sjkim	# acc[0] x p256[0..1] = acc[0] x 2^96 - acc[0]
559289848Sjkim	# then we add acc[0] and get acc[0] x 2^96
560289848Sjkim
561289848Sjkim	mov	$acc0, $t1
562289848Sjkim	shl	\$32, $acc0
563289848Sjkim	mulq	$poly3
564289848Sjkim	shr	\$32, $t1
565289848Sjkim	add	$acc0, $acc1		# +=acc[0]<<96
566289848Sjkim	adc	$t1, $acc2
567289848Sjkim	adc	%rax, $acc3
568289848Sjkim	 mov	8*1($b_ptr), %rax
569289848Sjkim	adc	%rdx, $acc4
570289848Sjkim	adc	\$0, $acc5
571289848Sjkim	xor	$acc0, $acc0
572289848Sjkim
573289848Sjkim	########################################################################
574289848Sjkim	# Multiply by b[1]
575289848Sjkim	mov	%rax, $t1
576289848Sjkim	mulq	8*0($a_ptr)
577289848Sjkim	add	%rax, $acc1
578289848Sjkim	mov	$t1, %rax
579289848Sjkim	adc	\$0, %rdx
580289848Sjkim	mov	%rdx, $t0
581289848Sjkim
582289848Sjkim	mulq	8*1($a_ptr)
583289848Sjkim	add	$t0, $acc2
584289848Sjkim	adc	\$0, %rdx
585289848Sjkim	add	%rax, $acc2
586289848Sjkim	mov	$t1, %rax
587289848Sjkim	adc	\$0, %rdx
588289848Sjkim	mov	%rdx, $t0
589289848Sjkim
590289848Sjkim	mulq	8*2($a_ptr)
591289848Sjkim	add	$t0, $acc3
592289848Sjkim	adc	\$0, %rdx
593289848Sjkim	add	%rax, $acc3
594289848Sjkim	mov	$t1, %rax
595289848Sjkim	adc	\$0, %rdx
596289848Sjkim	mov	%rdx, $t0
597289848Sjkim
598289848Sjkim	mulq	8*3($a_ptr)
599289848Sjkim	add	$t0, $acc4
600289848Sjkim	adc	\$0, %rdx
601289848Sjkim	add	%rax, $acc4
602289848Sjkim	 mov	$acc1, %rax
603289848Sjkim	adc	%rdx, $acc5
604289848Sjkim	adc	\$0, $acc0
605289848Sjkim
606289848Sjkim	########################################################################
607289848Sjkim	# Second reduction step
608289848Sjkim	mov	$acc1, $t1
609289848Sjkim	shl	\$32, $acc1
610289848Sjkim	mulq	$poly3
611289848Sjkim	shr	\$32, $t1
612289848Sjkim	add	$acc1, $acc2
613289848Sjkim	adc	$t1, $acc3
614289848Sjkim	adc	%rax, $acc4
615289848Sjkim	 mov	8*2($b_ptr), %rax
616289848Sjkim	adc	%rdx, $acc5
617289848Sjkim	adc	\$0, $acc0
618289848Sjkim	xor	$acc1, $acc1
619289848Sjkim
620289848Sjkim	########################################################################
621289848Sjkim	# Multiply by b[2]
622289848Sjkim	mov	%rax, $t1
623289848Sjkim	mulq	8*0($a_ptr)
624289848Sjkim	add	%rax, $acc2
625289848Sjkim	mov	$t1, %rax
626289848Sjkim	adc	\$0, %rdx
627289848Sjkim	mov	%rdx, $t0
628289848Sjkim
629289848Sjkim	mulq	8*1($a_ptr)
630289848Sjkim	add	$t0, $acc3
631289848Sjkim	adc	\$0, %rdx
632289848Sjkim	add	%rax, $acc3
633289848Sjkim	mov	$t1, %rax
634289848Sjkim	adc	\$0, %rdx
635289848Sjkim	mov	%rdx, $t0
636289848Sjkim
637289848Sjkim	mulq	8*2($a_ptr)
638289848Sjkim	add	$t0, $acc4
639289848Sjkim	adc	\$0, %rdx
640289848Sjkim	add	%rax, $acc4
641289848Sjkim	mov	$t1, %rax
642289848Sjkim	adc	\$0, %rdx
643289848Sjkim	mov	%rdx, $t0
644289848Sjkim
645289848Sjkim	mulq	8*3($a_ptr)
646289848Sjkim	add	$t0, $acc5
647289848Sjkim	adc	\$0, %rdx
648289848Sjkim	add	%rax, $acc5
649289848Sjkim	 mov	$acc2, %rax
650289848Sjkim	adc	%rdx, $acc0
651289848Sjkim	adc	\$0, $acc1
652289848Sjkim
653289848Sjkim	########################################################################
654289848Sjkim	# Third reduction step
655289848Sjkim	mov	$acc2, $t1
656289848Sjkim	shl	\$32, $acc2
657289848Sjkim	mulq	$poly3
658289848Sjkim	shr	\$32, $t1
659289848Sjkim	add	$acc2, $acc3
660289848Sjkim	adc	$t1, $acc4
661289848Sjkim	adc	%rax, $acc5
662289848Sjkim	 mov	8*3($b_ptr), %rax
663289848Sjkim	adc	%rdx, $acc0
664289848Sjkim	adc	\$0, $acc1
665289848Sjkim	xor	$acc2, $acc2
666289848Sjkim
667289848Sjkim	########################################################################
668289848Sjkim	# Multiply by b[3]
669289848Sjkim	mov	%rax, $t1
670289848Sjkim	mulq	8*0($a_ptr)
671289848Sjkim	add	%rax, $acc3
672289848Sjkim	mov	$t1, %rax
673289848Sjkim	adc	\$0, %rdx
674289848Sjkim	mov	%rdx, $t0
675289848Sjkim
676289848Sjkim	mulq	8*1($a_ptr)
677289848Sjkim	add	$t0, $acc4
678289848Sjkim	adc	\$0, %rdx
679289848Sjkim	add	%rax, $acc4
680289848Sjkim	mov	$t1, %rax
681289848Sjkim	adc	\$0, %rdx
682289848Sjkim	mov	%rdx, $t0
683289848Sjkim
684289848Sjkim	mulq	8*2($a_ptr)
685289848Sjkim	add	$t0, $acc5
686289848Sjkim	adc	\$0, %rdx
687289848Sjkim	add	%rax, $acc5
688289848Sjkim	mov	$t1, %rax
689289848Sjkim	adc	\$0, %rdx
690289848Sjkim	mov	%rdx, $t0
691289848Sjkim
692289848Sjkim	mulq	8*3($a_ptr)
693289848Sjkim	add	$t0, $acc0
694289848Sjkim	adc	\$0, %rdx
695289848Sjkim	add	%rax, $acc0
696289848Sjkim	 mov	$acc3, %rax
697289848Sjkim	adc	%rdx, $acc1
698289848Sjkim	adc	\$0, $acc2
699289848Sjkim
700289848Sjkim	########################################################################
701289848Sjkim	# Final reduction step
702289848Sjkim	mov	$acc3, $t1
703289848Sjkim	shl	\$32, $acc3
704289848Sjkim	mulq	$poly3
705289848Sjkim	shr	\$32, $t1
706289848Sjkim	add	$acc3, $acc4
707289848Sjkim	adc	$t1, $acc5
708289848Sjkim	 mov	$acc4, $t0
709289848Sjkim	adc	%rax, $acc0
710289848Sjkim	adc	%rdx, $acc1
711289848Sjkim	 mov	$acc5, $t1
712289848Sjkim	adc	\$0, $acc2
713289848Sjkim
714289848Sjkim	########################################################################
715289848Sjkim	# Branch-less conditional subtraction of P
716289848Sjkim	sub	\$-1, $acc4		# .Lpoly[0]
717289848Sjkim	 mov	$acc0, $t2
718289848Sjkim	sbb	$poly1, $acc5		# .Lpoly[1]
719289848Sjkim	sbb	\$0, $acc0		# .Lpoly[2]
720289848Sjkim	 mov	$acc1, $t3
721289848Sjkim	sbb	$poly3, $acc1		# .Lpoly[3]
722289848Sjkim	sbb	\$0, $acc2
723289848Sjkim
724289848Sjkim	cmovc	$t0, $acc4
725289848Sjkim	cmovc	$t1, $acc5
726289848Sjkim	mov	$acc4, 8*0($r_ptr)
727289848Sjkim	cmovc	$t2, $acc0
728289848Sjkim	mov	$acc5, 8*1($r_ptr)
729289848Sjkim	cmovc	$t3, $acc1
730289848Sjkim	mov	$acc0, 8*2($r_ptr)
731289848Sjkim	mov	$acc1, 8*3($r_ptr)
732289848Sjkim
733289848Sjkim	ret
734289848Sjkim.size	__ecp_nistz256_mul_montq,.-__ecp_nistz256_mul_montq
735289848Sjkim
736289848Sjkim################################################################################
737289848Sjkim# void ecp_nistz256_sqr_mont(
738289848Sjkim#   uint64_t res[4],
739289848Sjkim#   uint64_t a[4]);
740289848Sjkim
741289848Sjkim# we optimize the square according to S.Gueron and V.Krasnov,
742289848Sjkim# "Speeding up Big-Number Squaring"
743289848Sjkim.globl	ecp_nistz256_sqr_mont
744289848Sjkim.type	ecp_nistz256_sqr_mont,\@function,2
745289848Sjkim.align	32
746289848Sjkimecp_nistz256_sqr_mont:
747289848Sjkim___
748289848Sjkim$code.=<<___	if ($addx);
749289848Sjkim	mov	\$0x80100, %ecx
750289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
751289848Sjkim___
752289848Sjkim$code.=<<___;
753289848Sjkim	push	%rbp
754289848Sjkim	push	%rbx
755289848Sjkim	push	%r12
756289848Sjkim	push	%r13
757289848Sjkim	push	%r14
758289848Sjkim	push	%r15
759289848Sjkim___
760289848Sjkim$code.=<<___	if ($addx);
761289848Sjkim	cmp	\$0x80100, %ecx
762289848Sjkim	je	.Lsqr_montx
763289848Sjkim___
764289848Sjkim$code.=<<___;
765289848Sjkim	mov	8*0($a_ptr), %rax
766289848Sjkim	mov	8*1($a_ptr), $acc6
767289848Sjkim	mov	8*2($a_ptr), $acc7
768289848Sjkim	mov	8*3($a_ptr), $acc0
769289848Sjkim
770289848Sjkim	call	__ecp_nistz256_sqr_montq
771289848Sjkim___
772289848Sjkim$code.=<<___	if ($addx);
773289848Sjkim	jmp	.Lsqr_mont_done
774289848Sjkim
775289848Sjkim.align	32
776289848Sjkim.Lsqr_montx:
777289848Sjkim	mov	8*0($a_ptr), %rdx
778289848Sjkim	mov	8*1($a_ptr), $acc6
779289848Sjkim	mov	8*2($a_ptr), $acc7
780289848Sjkim	mov	8*3($a_ptr), $acc0
781289848Sjkim	lea	-128($a_ptr), $a_ptr	# control u-op density
782289848Sjkim
783289848Sjkim	call	__ecp_nistz256_sqr_montx
784289848Sjkim___
785289848Sjkim$code.=<<___;
786289848Sjkim.Lsqr_mont_done:
787289848Sjkim	pop	%r15
788289848Sjkim	pop	%r14
789289848Sjkim	pop	%r13
790289848Sjkim	pop	%r12
791289848Sjkim	pop	%rbx
792289848Sjkim	pop	%rbp
793289848Sjkim	ret
794289848Sjkim.size	ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
795289848Sjkim
796289848Sjkim.type	__ecp_nistz256_sqr_montq,\@abi-omnipotent
797289848Sjkim.align	32
798289848Sjkim__ecp_nistz256_sqr_montq:
799289848Sjkim	mov	%rax, $acc5
800289848Sjkim	mulq	$acc6			# a[1]*a[0]
801289848Sjkim	mov	%rax, $acc1
802289848Sjkim	mov	$acc7, %rax
803289848Sjkim	mov	%rdx, $acc2
804289848Sjkim
805289848Sjkim	mulq	$acc5			# a[0]*a[2]
806289848Sjkim	add	%rax, $acc2
807289848Sjkim	mov	$acc0, %rax
808289848Sjkim	adc	\$0, %rdx
809289848Sjkim	mov	%rdx, $acc3
810289848Sjkim
811289848Sjkim	mulq	$acc5			# a[0]*a[3]
812289848Sjkim	add	%rax, $acc3
813289848Sjkim	 mov	$acc7, %rax
814289848Sjkim	adc	\$0, %rdx
815289848Sjkim	mov	%rdx, $acc4
816289848Sjkim
817289848Sjkim	#################################
818289848Sjkim	mulq	$acc6			# a[1]*a[2]
819289848Sjkim	add	%rax, $acc3
820289848Sjkim	mov	$acc0, %rax
821289848Sjkim	adc	\$0, %rdx
822289848Sjkim	mov	%rdx, $t1
823289848Sjkim
824289848Sjkim	mulq	$acc6			# a[1]*a[3]
825289848Sjkim	add	%rax, $acc4
826289848Sjkim	 mov	$acc0, %rax
827289848Sjkim	adc	\$0, %rdx
828289848Sjkim	add	$t1, $acc4
829289848Sjkim	mov	%rdx, $acc5
830289848Sjkim	adc	\$0, $acc5
831289848Sjkim
832289848Sjkim	#################################
833289848Sjkim	mulq	$acc7			# a[2]*a[3]
834289848Sjkim	xor	$acc7, $acc7
835289848Sjkim	add	%rax, $acc5
836289848Sjkim	 mov	8*0($a_ptr), %rax
837289848Sjkim	mov	%rdx, $acc6
838289848Sjkim	adc	\$0, $acc6
839289848Sjkim
840289848Sjkim	add	$acc1, $acc1		# acc1:6<<1
841289848Sjkim	adc	$acc2, $acc2
842289848Sjkim	adc	$acc3, $acc3
843289848Sjkim	adc	$acc4, $acc4
844289848Sjkim	adc	$acc5, $acc5
845289848Sjkim	adc	$acc6, $acc6
846289848Sjkim	adc	\$0, $acc7
847289848Sjkim
848289848Sjkim	mulq	%rax
849289848Sjkim	mov	%rax, $acc0
850289848Sjkim	mov	8*1($a_ptr), %rax
851289848Sjkim	mov	%rdx, $t0
852289848Sjkim
853289848Sjkim	mulq	%rax
854289848Sjkim	add	$t0, $acc1
855289848Sjkim	adc	%rax, $acc2
856289848Sjkim	mov	8*2($a_ptr), %rax
857289848Sjkim	adc	\$0, %rdx
858289848Sjkim	mov	%rdx, $t0
859289848Sjkim
860289848Sjkim	mulq	%rax
861289848Sjkim	add	$t0, $acc3
862289848Sjkim	adc	%rax, $acc4
863289848Sjkim	mov	8*3($a_ptr), %rax
864289848Sjkim	adc	\$0, %rdx
865289848Sjkim	mov	%rdx, $t0
866289848Sjkim
867289848Sjkim	mulq	%rax
868289848Sjkim	add	$t0, $acc5
869289848Sjkim	adc	%rax, $acc6
870289848Sjkim	 mov	$acc0, %rax
871289848Sjkim	adc	%rdx, $acc7
872289848Sjkim
873289848Sjkim	mov	.Lpoly+8*1(%rip), $a_ptr
874289848Sjkim	mov	.Lpoly+8*3(%rip), $t1
875289848Sjkim
876289848Sjkim	##########################################
877289848Sjkim	# Now the reduction
878289848Sjkim	# First iteration
879289848Sjkim	mov	$acc0, $t0
880289848Sjkim	shl	\$32, $acc0
881289848Sjkim	mulq	$t1
882289848Sjkim	shr	\$32, $t0
883289848Sjkim	add	$acc0, $acc1		# +=acc[0]<<96
884289848Sjkim	adc	$t0, $acc2
885289848Sjkim	adc	%rax, $acc3
886289848Sjkim	 mov	$acc1, %rax
887289848Sjkim	adc	\$0, %rdx
888289848Sjkim
889289848Sjkim	##########################################
890289848Sjkim	# Second iteration
891289848Sjkim	mov	$acc1, $t0
892289848Sjkim	shl	\$32, $acc1
893289848Sjkim	mov	%rdx, $acc0
894289848Sjkim	mulq	$t1
895289848Sjkim	shr	\$32, $t0
896289848Sjkim	add	$acc1, $acc2
897289848Sjkim	adc	$t0, $acc3
898289848Sjkim	adc	%rax, $acc0
899289848Sjkim	 mov	$acc2, %rax
900289848Sjkim	adc	\$0, %rdx
901289848Sjkim
902289848Sjkim	##########################################
903289848Sjkim	# Third iteration
904289848Sjkim	mov	$acc2, $t0
905289848Sjkim	shl	\$32, $acc2
906289848Sjkim	mov	%rdx, $acc1
907289848Sjkim	mulq	$t1
908289848Sjkim	shr	\$32, $t0
909289848Sjkim	add	$acc2, $acc3
910289848Sjkim	adc	$t0, $acc0
911289848Sjkim	adc	%rax, $acc1
912289848Sjkim	 mov	$acc3, %rax
913289848Sjkim	adc	\$0, %rdx
914289848Sjkim
915289848Sjkim	###########################################
916289848Sjkim	# Last iteration
917289848Sjkim	mov	$acc3, $t0
918289848Sjkim	shl	\$32, $acc3
919289848Sjkim	mov	%rdx, $acc2
920289848Sjkim	mulq	$t1
921289848Sjkim	shr	\$32, $t0
922289848Sjkim	add	$acc3, $acc0
923289848Sjkim	adc	$t0, $acc1
924289848Sjkim	adc	%rax, $acc2
925289848Sjkim	adc	\$0, %rdx
926289848Sjkim	xor	$acc3, $acc3
927289848Sjkim
928289848Sjkim	############################################
929289848Sjkim	# Add the rest of the acc
930289848Sjkim	add	$acc0, $acc4
931289848Sjkim	adc	$acc1, $acc5
932289848Sjkim	 mov	$acc4, $acc0
933289848Sjkim	adc	$acc2, $acc6
934289848Sjkim	adc	%rdx, $acc7
935289848Sjkim	 mov	$acc5, $acc1
936289848Sjkim	adc	\$0, $acc3
937289848Sjkim
938289848Sjkim	sub	\$-1, $acc4		# .Lpoly[0]
939289848Sjkim	 mov	$acc6, $acc2
940289848Sjkim	sbb	$a_ptr, $acc5		# .Lpoly[1]
941289848Sjkim	sbb	\$0, $acc6		# .Lpoly[2]
942289848Sjkim	 mov	$acc7, $t0
943289848Sjkim	sbb	$t1, $acc7		# .Lpoly[3]
944289848Sjkim	sbb	\$0, $acc3
945289848Sjkim
946289848Sjkim	cmovc	$acc0, $acc4
947289848Sjkim	cmovc	$acc1, $acc5
948289848Sjkim	mov	$acc4, 8*0($r_ptr)
949289848Sjkim	cmovc	$acc2, $acc6
950289848Sjkim	mov	$acc5, 8*1($r_ptr)
951289848Sjkim	cmovc	$t0, $acc7
952289848Sjkim	mov	$acc6, 8*2($r_ptr)
953289848Sjkim	mov	$acc7, 8*3($r_ptr)
954289848Sjkim
955289848Sjkim	ret
956289848Sjkim.size	__ecp_nistz256_sqr_montq,.-__ecp_nistz256_sqr_montq
957289848Sjkim___
958289848Sjkim
959289848Sjkimif ($addx) {
960289848Sjkim$code.=<<___;
961289848Sjkim.type	__ecp_nistz256_mul_montx,\@abi-omnipotent
962289848Sjkim.align	32
963289848Sjkim__ecp_nistz256_mul_montx:
964289848Sjkim	########################################################################
965289848Sjkim	# Multiply by b[0]
966289848Sjkim	mulx	$acc1, $acc0, $acc1
967289848Sjkim	mulx	$acc2, $t0, $acc2
968289848Sjkim	mov	\$32, $poly1
969289848Sjkim	xor	$acc5, $acc5		# cf=0
970289848Sjkim	mulx	$acc3, $t1, $acc3
971289848Sjkim	mov	.Lpoly+8*3(%rip), $poly3
972289848Sjkim	adc	$t0, $acc1
973289848Sjkim	mulx	$acc4, $t0, $acc4
974289848Sjkim	 mov	$acc0, %rdx
975289848Sjkim	adc	$t1, $acc2
976289848Sjkim	 shlx	$poly1,$acc0,$t1
977289848Sjkim	adc	$t0, $acc3
978289848Sjkim	 shrx	$poly1,$acc0,$t0
979289848Sjkim	adc	\$0, $acc4
980289848Sjkim
981289848Sjkim	########################################################################
982289848Sjkim	# First reduction step
983289848Sjkim	add	$t1, $acc1
984289848Sjkim	adc	$t0, $acc2
985289848Sjkim
986289848Sjkim	mulx	$poly3, $t0, $t1
987289848Sjkim	 mov	8*1($b_ptr), %rdx
988289848Sjkim	adc	$t0, $acc3
989289848Sjkim	adc	$t1, $acc4
990289848Sjkim	adc	\$0, $acc5
991289848Sjkim	xor	$acc0, $acc0		# $acc0=0,cf=0,of=0
992289848Sjkim
993289848Sjkim	########################################################################
994289848Sjkim	# Multiply by b[1]
995289848Sjkim	mulx	8*0+128($a_ptr), $t0, $t1
996289848Sjkim	adcx	$t0, $acc1
997289848Sjkim	adox	$t1, $acc2
998289848Sjkim
999289848Sjkim	mulx	8*1+128($a_ptr), $t0, $t1
1000289848Sjkim	adcx	$t0, $acc2
1001289848Sjkim	adox	$t1, $acc3
1002289848Sjkim
1003289848Sjkim	mulx	8*2+128($a_ptr), $t0, $t1
1004289848Sjkim	adcx	$t0, $acc3
1005289848Sjkim	adox	$t1, $acc4
1006289848Sjkim
1007289848Sjkim	mulx	8*3+128($a_ptr), $t0, $t1
1008289848Sjkim	 mov	$acc1, %rdx
1009289848Sjkim	adcx	$t0, $acc4
1010289848Sjkim	 shlx	$poly1, $acc1, $t0
1011289848Sjkim	adox	$t1, $acc5
1012289848Sjkim	 shrx	$poly1, $acc1, $t1
1013289848Sjkim
1014289848Sjkim	adcx	$acc0, $acc5
1015289848Sjkim	adox	$acc0, $acc0
1016289848Sjkim	adc	\$0, $acc0
1017289848Sjkim
1018289848Sjkim	########################################################################
1019289848Sjkim	# Second reduction step
1020289848Sjkim	add	$t0, $acc2
1021289848Sjkim	adc	$t1, $acc3
1022289848Sjkim
1023289848Sjkim	mulx	$poly3, $t0, $t1
1024289848Sjkim	 mov	8*2($b_ptr), %rdx
1025289848Sjkim	adc	$t0, $acc4
1026289848Sjkim	adc	$t1, $acc5
1027289848Sjkim	adc	\$0, $acc0
1028289848Sjkim	xor	$acc1 ,$acc1		# $acc1=0,cf=0,of=0
1029289848Sjkim
1030289848Sjkim	########################################################################
1031289848Sjkim	# Multiply by b[2]
1032289848Sjkim	mulx	8*0+128($a_ptr), $t0, $t1
1033289848Sjkim	adcx	$t0, $acc2
1034289848Sjkim	adox	$t1, $acc3
1035289848Sjkim
1036289848Sjkim	mulx	8*1+128($a_ptr), $t0, $t1
1037289848Sjkim	adcx	$t0, $acc3
1038289848Sjkim	adox	$t1, $acc4
1039289848Sjkim
1040289848Sjkim	mulx	8*2+128($a_ptr), $t0, $t1
1041289848Sjkim	adcx	$t0, $acc4
1042289848Sjkim	adox	$t1, $acc5
1043289848Sjkim
1044289848Sjkim	mulx	8*3+128($a_ptr), $t0, $t1
1045289848Sjkim	 mov	$acc2, %rdx
1046289848Sjkim	adcx	$t0, $acc5
1047289848Sjkim	 shlx	$poly1, $acc2, $t0
1048289848Sjkim	adox	$t1, $acc0
1049289848Sjkim	 shrx	$poly1, $acc2, $t1
1050289848Sjkim
1051289848Sjkim	adcx	$acc1, $acc0
1052289848Sjkim	adox	$acc1, $acc1
1053289848Sjkim	adc	\$0, $acc1
1054289848Sjkim
1055289848Sjkim	########################################################################
1056289848Sjkim	# Third reduction step
1057289848Sjkim	add	$t0, $acc3
1058289848Sjkim	adc	$t1, $acc4
1059289848Sjkim
1060289848Sjkim	mulx	$poly3, $t0, $t1
1061289848Sjkim	 mov	8*3($b_ptr), %rdx
1062289848Sjkim	adc	$t0, $acc5
1063289848Sjkim	adc	$t1, $acc0
1064289848Sjkim	adc	\$0, $acc1
1065289848Sjkim	xor	$acc2, $acc2		# $acc2=0,cf=0,of=0
1066289848Sjkim
1067289848Sjkim	########################################################################
1068289848Sjkim	# Multiply by b[3]
1069289848Sjkim	mulx	8*0+128($a_ptr), $t0, $t1
1070289848Sjkim	adcx	$t0, $acc3
1071289848Sjkim	adox	$t1, $acc4
1072289848Sjkim
1073289848Sjkim	mulx	8*1+128($a_ptr), $t0, $t1
1074289848Sjkim	adcx	$t0, $acc4
1075289848Sjkim	adox	$t1, $acc5
1076289848Sjkim
1077289848Sjkim	mulx	8*2+128($a_ptr), $t0, $t1
1078289848Sjkim	adcx	$t0, $acc5
1079289848Sjkim	adox	$t1, $acc0
1080289848Sjkim
1081289848Sjkim	mulx	8*3+128($a_ptr), $t0, $t1
1082289848Sjkim	 mov	$acc3, %rdx
1083289848Sjkim	adcx	$t0, $acc0
1084289848Sjkim	 shlx	$poly1, $acc3, $t0
1085289848Sjkim	adox	$t1, $acc1
1086289848Sjkim	 shrx	$poly1, $acc3, $t1
1087289848Sjkim
1088289848Sjkim	adcx	$acc2, $acc1
1089289848Sjkim	adox	$acc2, $acc2
1090289848Sjkim	adc	\$0, $acc2
1091289848Sjkim
1092289848Sjkim	########################################################################
1093289848Sjkim	# Fourth reduction step
1094289848Sjkim	add	$t0, $acc4
1095289848Sjkim	adc	$t1, $acc5
1096289848Sjkim
1097289848Sjkim	mulx	$poly3, $t0, $t1
1098289848Sjkim	 mov	$acc4, $t2
1099289848Sjkim	mov	.Lpoly+8*1(%rip), $poly1
1100289848Sjkim	adc	$t0, $acc0
1101289848Sjkim	 mov	$acc5, $t3
1102289848Sjkim	adc	$t1, $acc1
1103289848Sjkim	adc	\$0, $acc2
1104289848Sjkim
1105289848Sjkim	########################################################################
1106289848Sjkim	# Branch-less conditional subtraction of P
1107289848Sjkim	xor	%eax, %eax
1108289848Sjkim	 mov	$acc0, $t0
1109289848Sjkim	sbb	\$-1, $acc4		# .Lpoly[0]
1110289848Sjkim	sbb	$poly1, $acc5		# .Lpoly[1]
1111289848Sjkim	sbb	\$0, $acc0		# .Lpoly[2]
1112289848Sjkim	 mov	$acc1, $t1
1113289848Sjkim	sbb	$poly3, $acc1		# .Lpoly[3]
1114289848Sjkim	sbb	\$0, $acc2
1115289848Sjkim
1116289848Sjkim	cmovc	$t2, $acc4
1117289848Sjkim	cmovc	$t3, $acc5
1118289848Sjkim	mov	$acc4, 8*0($r_ptr)
1119289848Sjkim	cmovc	$t0, $acc0
1120289848Sjkim	mov	$acc5, 8*1($r_ptr)
1121289848Sjkim	cmovc	$t1, $acc1
1122289848Sjkim	mov	$acc0, 8*2($r_ptr)
1123289848Sjkim	mov	$acc1, 8*3($r_ptr)
1124289848Sjkim
1125289848Sjkim	ret
1126289848Sjkim.size	__ecp_nistz256_mul_montx,.-__ecp_nistz256_mul_montx
1127289848Sjkim
1128289848Sjkim.type	__ecp_nistz256_sqr_montx,\@abi-omnipotent
1129289848Sjkim.align	32
1130289848Sjkim__ecp_nistz256_sqr_montx:
1131289848Sjkim	mulx	$acc6, $acc1, $acc2	# a[0]*a[1]
1132289848Sjkim	mulx	$acc7, $t0, $acc3	# a[0]*a[2]
1133289848Sjkim	xor	%eax, %eax
1134289848Sjkim	adc	$t0, $acc2
1135289848Sjkim	mulx	$acc0, $t1, $acc4	# a[0]*a[3]
1136289848Sjkim	 mov	$acc6, %rdx
1137289848Sjkim	adc	$t1, $acc3
1138289848Sjkim	adc	\$0, $acc4
1139289848Sjkim	xor	$acc5, $acc5		# $acc5=0,cf=0,of=0
1140289848Sjkim
1141289848Sjkim	#################################
1142289848Sjkim	mulx	$acc7, $t0, $t1		# a[1]*a[2]
1143289848Sjkim	adcx	$t0, $acc3
1144289848Sjkim	adox	$t1, $acc4
1145289848Sjkim
1146289848Sjkim	mulx	$acc0, $t0, $t1		# a[1]*a[3]
1147289848Sjkim	 mov	$acc7, %rdx
1148289848Sjkim	adcx	$t0, $acc4
1149289848Sjkim	adox	$t1, $acc5
1150289848Sjkim	adc	\$0, $acc5
1151289848Sjkim
1152289848Sjkim	#################################
1153289848Sjkim	mulx	$acc0, $t0, $acc6	# a[2]*a[3]
1154289848Sjkim	 mov	8*0+128($a_ptr), %rdx
1155289848Sjkim	xor	$acc7, $acc7		# $acc7=0,cf=0,of=0
1156289848Sjkim	 adcx	$acc1, $acc1		# acc1:6<<1
1157289848Sjkim	adox	$t0, $acc5
1158289848Sjkim	 adcx	$acc2, $acc2
1159289848Sjkim	adox	$acc7, $acc6		# of=0
1160289848Sjkim
1161289848Sjkim	mulx	%rdx, $acc0, $t1
1162289848Sjkim	mov	8*1+128($a_ptr), %rdx
1163289848Sjkim	 adcx	$acc3, $acc3
1164289848Sjkim	adox	$t1, $acc1
1165289848Sjkim	 adcx	$acc4, $acc4
1166289848Sjkim	mulx	%rdx, $t0, $t4
1167289848Sjkim	mov	8*2+128($a_ptr), %rdx
1168289848Sjkim	 adcx	$acc5, $acc5
1169289848Sjkim	adox	$t0, $acc2
1170289848Sjkim	 adcx	$acc6, $acc6
1171289848Sjkim	.byte	0x67
1172289848Sjkim	mulx	%rdx, $t0, $t1
1173289848Sjkim	mov	8*3+128($a_ptr), %rdx
1174289848Sjkim	adox	$t4, $acc3
1175289848Sjkim	 adcx	$acc7, $acc7
1176289848Sjkim	adox	$t0, $acc4
1177289848Sjkim	 mov	\$32, $a_ptr
1178289848Sjkim	adox	$t1, $acc5
1179289848Sjkim	.byte	0x67,0x67
1180289848Sjkim	mulx	%rdx, $t0, $t4
1181325337Sjkim	 mov	.Lpoly+8*3(%rip), %rdx
1182289848Sjkim	adox	$t0, $acc6
1183289848Sjkim	 shlx	$a_ptr, $acc0, $t0
1184289848Sjkim	adox	$t4, $acc7
1185289848Sjkim	 shrx	$a_ptr, $acc0, $t4
1186325337Sjkim	mov	%rdx,$t1
1187289848Sjkim
1188289848Sjkim	# reduction step 1
1189289848Sjkim	add	$t0, $acc1
1190289848Sjkim	adc	$t4, $acc2
1191289848Sjkim
1192325337Sjkim	mulx	$acc0, $t0, $acc0
1193289848Sjkim	adc	$t0, $acc3
1194289848Sjkim	 shlx	$a_ptr, $acc1, $t0
1195289848Sjkim	adc	\$0, $acc0
1196289848Sjkim	 shrx	$a_ptr, $acc1, $t4
1197289848Sjkim
1198289848Sjkim	# reduction step 2
1199289848Sjkim	add	$t0, $acc2
1200289848Sjkim	adc	$t4, $acc3
1201289848Sjkim
1202325337Sjkim	mulx	$acc1, $t0, $acc1
1203289848Sjkim	adc	$t0, $acc0
1204289848Sjkim	 shlx	$a_ptr, $acc2, $t0
1205289848Sjkim	adc	\$0, $acc1
1206289848Sjkim	 shrx	$a_ptr, $acc2, $t4
1207289848Sjkim
1208289848Sjkim	# reduction step 3
1209289848Sjkim	add	$t0, $acc3
1210289848Sjkim	adc	$t4, $acc0
1211289848Sjkim
1212325337Sjkim	mulx	$acc2, $t0, $acc2
1213289848Sjkim	adc	$t0, $acc1
1214289848Sjkim	 shlx	$a_ptr, $acc3, $t0
1215289848Sjkim	adc	\$0, $acc2
1216289848Sjkim	 shrx	$a_ptr, $acc3, $t4
1217289848Sjkim
1218289848Sjkim	# reduction step 4
1219289848Sjkim	add	$t0, $acc0
1220289848Sjkim	adc	$t4, $acc1
1221289848Sjkim
1222325337Sjkim	mulx	$acc3, $t0, $acc3
1223289848Sjkim	adc	$t0, $acc2
1224289848Sjkim	adc	\$0, $acc3
1225289848Sjkim
1226325337Sjkim	xor	$t3, $t3
1227325337Sjkim	add	$acc0, $acc4		# accumulate upper half
1228289848Sjkim	 mov	.Lpoly+8*1(%rip), $a_ptr
1229289848Sjkim	adc	$acc1, $acc5
1230289848Sjkim	 mov	$acc4, $acc0
1231289848Sjkim	adc	$acc2, $acc6
1232289848Sjkim	adc	$acc3, $acc7
1233289848Sjkim	 mov	$acc5, $acc1
1234289848Sjkim	adc	\$0, $t3
1235289848Sjkim
1236325337Sjkim	sub	\$-1, $acc4		# .Lpoly[0]
1237289848Sjkim	 mov	$acc6, $acc2
1238289848Sjkim	sbb	$a_ptr, $acc5		# .Lpoly[1]
1239289848Sjkim	sbb	\$0, $acc6		# .Lpoly[2]
1240289848Sjkim	 mov	$acc7, $acc3
1241289848Sjkim	sbb	$t1, $acc7		# .Lpoly[3]
1242289848Sjkim	sbb	\$0, $t3
1243289848Sjkim
1244289848Sjkim	cmovc	$acc0, $acc4
1245289848Sjkim	cmovc	$acc1, $acc5
1246289848Sjkim	mov	$acc4, 8*0($r_ptr)
1247289848Sjkim	cmovc	$acc2, $acc6
1248289848Sjkim	mov	$acc5, 8*1($r_ptr)
1249289848Sjkim	cmovc	$acc3, $acc7
1250289848Sjkim	mov	$acc6, 8*2($r_ptr)
1251289848Sjkim	mov	$acc7, 8*3($r_ptr)
1252289848Sjkim
1253289848Sjkim	ret
1254289848Sjkim.size	__ecp_nistz256_sqr_montx,.-__ecp_nistz256_sqr_montx
1255289848Sjkim___
1256289848Sjkim}
1257289848Sjkim}
1258289848Sjkim{
1259289848Sjkimmy ($r_ptr,$in_ptr)=("%rdi","%rsi");
1260289848Sjkimmy ($acc0,$acc1,$acc2,$acc3)=map("%r$_",(8..11));
1261289848Sjkimmy ($t0,$t1,$t2)=("%rcx","%r12","%r13");
1262289848Sjkim
1263289848Sjkim$code.=<<___;
1264289848Sjkim################################################################################
1265289848Sjkim# void ecp_nistz256_from_mont(
1266289848Sjkim#   uint64_t res[4],
1267289848Sjkim#   uint64_t in[4]);
1268289848Sjkim# This one performs Montgomery multiplication by 1, so we only need the reduction
1269289848Sjkim
1270289848Sjkim.globl	ecp_nistz256_from_mont
1271289848Sjkim.type	ecp_nistz256_from_mont,\@function,2
1272289848Sjkim.align	32
1273289848Sjkimecp_nistz256_from_mont:
1274289848Sjkim	push	%r12
1275289848Sjkim	push	%r13
1276289848Sjkim
1277289848Sjkim	mov	8*0($in_ptr), %rax
1278289848Sjkim	mov	.Lpoly+8*3(%rip), $t2
1279289848Sjkim	mov	8*1($in_ptr), $acc1
1280289848Sjkim	mov	8*2($in_ptr), $acc2
1281289848Sjkim	mov	8*3($in_ptr), $acc3
1282289848Sjkim	mov	%rax, $acc0
1283289848Sjkim	mov	.Lpoly+8*1(%rip), $t1
1284289848Sjkim
1285289848Sjkim	#########################################
1286289848Sjkim	# First iteration
1287289848Sjkim	mov	%rax, $t0
1288289848Sjkim	shl	\$32, $acc0
1289289848Sjkim	mulq	$t2
1290289848Sjkim	shr	\$32, $t0
1291289848Sjkim	add	$acc0, $acc1
1292289848Sjkim	adc	$t0, $acc2
1293289848Sjkim	adc	%rax, $acc3
1294289848Sjkim	 mov	$acc1, %rax
1295289848Sjkim	adc	\$0, %rdx
1296289848Sjkim
1297289848Sjkim	#########################################
1298289848Sjkim	# Second iteration
1299289848Sjkim	mov	$acc1, $t0
1300289848Sjkim	shl	\$32, $acc1
1301289848Sjkim	mov	%rdx, $acc0
1302289848Sjkim	mulq	$t2
1303289848Sjkim	shr	\$32, $t0
1304289848Sjkim	add	$acc1, $acc2
1305289848Sjkim	adc	$t0, $acc3
1306289848Sjkim	adc	%rax, $acc0
1307289848Sjkim	 mov	$acc2, %rax
1308289848Sjkim	adc	\$0, %rdx
1309289848Sjkim
1310289848Sjkim	##########################################
1311289848Sjkim	# Third iteration
1312289848Sjkim	mov	$acc2, $t0
1313289848Sjkim	shl	\$32, $acc2
1314289848Sjkim	mov	%rdx, $acc1
1315289848Sjkim	mulq	$t2
1316289848Sjkim	shr	\$32, $t0
1317289848Sjkim	add	$acc2, $acc3
1318289848Sjkim	adc	$t0, $acc0
1319289848Sjkim	adc	%rax, $acc1
1320289848Sjkim	 mov	$acc3, %rax
1321289848Sjkim	adc	\$0, %rdx
1322289848Sjkim
1323289848Sjkim	###########################################
1324289848Sjkim	# Last iteration
1325289848Sjkim	mov	$acc3, $t0
1326289848Sjkim	shl	\$32, $acc3
1327289848Sjkim	mov	%rdx, $acc2
1328289848Sjkim	mulq	$t2
1329289848Sjkim	shr	\$32, $t0
1330289848Sjkim	add	$acc3, $acc0
1331289848Sjkim	adc	$t0, $acc1
1332289848Sjkim	 mov	$acc0, $t0
1333289848Sjkim	adc	%rax, $acc2
1334289848Sjkim	 mov	$acc1, $in_ptr
1335289848Sjkim	adc	\$0, %rdx
1336289848Sjkim
1337289848Sjkim	###########################################
1338289848Sjkim	# Branch-less conditional subtraction
1339289848Sjkim	sub	\$-1, $acc0
1340289848Sjkim	 mov	$acc2, %rax
1341289848Sjkim	sbb	$t1, $acc1
1342289848Sjkim	sbb	\$0, $acc2
1343289848Sjkim	 mov	%rdx, $acc3
1344289848Sjkim	sbb	$t2, %rdx
1345289848Sjkim	sbb	$t2, $t2
1346289848Sjkim
1347289848Sjkim	cmovnz	$t0, $acc0
1348289848Sjkim	cmovnz	$in_ptr, $acc1
1349289848Sjkim	mov	$acc0, 8*0($r_ptr)
1350289848Sjkim	cmovnz	%rax, $acc2
1351289848Sjkim	mov	$acc1, 8*1($r_ptr)
1352289848Sjkim	cmovz	%rdx, $acc3
1353289848Sjkim	mov	$acc2, 8*2($r_ptr)
1354289848Sjkim	mov	$acc3, 8*3($r_ptr)
1355289848Sjkim
1356289848Sjkim	pop	%r13
1357289848Sjkim	pop	%r12
1358289848Sjkim	ret
1359289848Sjkim.size	ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
1360289848Sjkim___
1361289848Sjkim}
1362289848Sjkim{
1363289848Sjkimmy ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1364289848Sjkimmy ($ONE,$INDEX,$Ra,$Rb,$Rc,$Rd,$Re,$Rf)=map("%xmm$_",(0..7));
1365289848Sjkimmy ($M0,$T0a,$T0b,$T0c,$T0d,$T0e,$T0f,$TMP0)=map("%xmm$_",(8..15));
1366289848Sjkimmy ($M1,$T2a,$T2b,$TMP2,$M2,$T2a,$T2b,$TMP2)=map("%xmm$_",(8..15));
1367289848Sjkim
1368289848Sjkim$code.=<<___;
1369289848Sjkim################################################################################
1370289848Sjkim# void ecp_nistz256_select_w5(uint64_t *val, uint64_t *in_t, int index);
1371289848Sjkim.globl	ecp_nistz256_select_w5
1372289848Sjkim.type	ecp_nistz256_select_w5,\@abi-omnipotent
1373289848Sjkim.align	32
1374289848Sjkimecp_nistz256_select_w5:
1375289848Sjkim___
1376289848Sjkim$code.=<<___	if ($avx>1);
1377289848Sjkim	mov	OPENSSL_ia32cap_P+8(%rip), %eax
1378289848Sjkim	test	\$`1<<5`, %eax
1379289848Sjkim	jnz	.Lavx2_select_w5
1380289848Sjkim___
1381289848Sjkim$code.=<<___	if ($win64);
1382289848Sjkim	lea	-0x88(%rsp), %rax
1383289848Sjkim.LSEH_begin_ecp_nistz256_select_w5:
1384289848Sjkim	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
1385289848Sjkim	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6, -0x20(%rax)
1386289848Sjkim	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7, -0x10(%rax)
1387289848Sjkim	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8, 0(%rax)
1388289848Sjkim	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9, 0x10(%rax)
1389289848Sjkim	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10, 0x20(%rax)
1390289848Sjkim	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11, 0x30(%rax)
1391289848Sjkim	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12, 0x40(%rax)
1392289848Sjkim	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13, 0x50(%rax)
1393289848Sjkim	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14, 0x60(%rax)
1394289848Sjkim	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15, 0x70(%rax)
1395289848Sjkim___
1396289848Sjkim$code.=<<___;
1397289848Sjkim	movdqa	.LOne(%rip), $ONE
1398289848Sjkim	movd	$index, $INDEX
1399289848Sjkim
1400289848Sjkim	pxor	$Ra, $Ra
1401289848Sjkim	pxor	$Rb, $Rb
1402289848Sjkim	pxor	$Rc, $Rc
1403289848Sjkim	pxor	$Rd, $Rd
1404289848Sjkim	pxor	$Re, $Re
1405289848Sjkim	pxor	$Rf, $Rf
1406289848Sjkim
1407289848Sjkim	movdqa	$ONE, $M0
1408289848Sjkim	pshufd	\$0, $INDEX, $INDEX
1409289848Sjkim
1410289848Sjkim	mov	\$16, %rax
1411289848Sjkim.Lselect_loop_sse_w5:
1412289848Sjkim
1413289848Sjkim	movdqa	$M0, $TMP0
1414289848Sjkim	paddd	$ONE, $M0
1415289848Sjkim	pcmpeqd $INDEX, $TMP0
1416289848Sjkim
1417289848Sjkim	movdqa	16*0($in_t), $T0a
1418289848Sjkim	movdqa	16*1($in_t), $T0b
1419289848Sjkim	movdqa	16*2($in_t), $T0c
1420289848Sjkim	movdqa	16*3($in_t), $T0d
1421289848Sjkim	movdqa	16*4($in_t), $T0e
1422289848Sjkim	movdqa	16*5($in_t), $T0f
1423289848Sjkim	lea 16*6($in_t), $in_t
1424289848Sjkim
1425289848Sjkim	pand	$TMP0, $T0a
1426289848Sjkim	pand	$TMP0, $T0b
1427289848Sjkim	por	$T0a, $Ra
1428289848Sjkim	pand	$TMP0, $T0c
1429289848Sjkim	por	$T0b, $Rb
1430289848Sjkim	pand	$TMP0, $T0d
1431289848Sjkim	por	$T0c, $Rc
1432289848Sjkim	pand	$TMP0, $T0e
1433289848Sjkim	por	$T0d, $Rd
1434289848Sjkim	pand	$TMP0, $T0f
1435289848Sjkim	por	$T0e, $Re
1436289848Sjkim	por	$T0f, $Rf
1437289848Sjkim
1438289848Sjkim	dec	%rax
1439289848Sjkim	jnz	.Lselect_loop_sse_w5
1440289848Sjkim
1441289848Sjkim	movdqu	$Ra, 16*0($val)
1442289848Sjkim	movdqu	$Rb, 16*1($val)
1443289848Sjkim	movdqu	$Rc, 16*2($val)
1444289848Sjkim	movdqu	$Rd, 16*3($val)
1445289848Sjkim	movdqu	$Re, 16*4($val)
1446289848Sjkim	movdqu	$Rf, 16*5($val)
1447289848Sjkim___
1448289848Sjkim$code.=<<___	if ($win64);
1449289848Sjkim	movaps	(%rsp), %xmm6
1450289848Sjkim	movaps	0x10(%rsp), %xmm7
1451289848Sjkim	movaps	0x20(%rsp), %xmm8
1452289848Sjkim	movaps	0x30(%rsp), %xmm9
1453289848Sjkim	movaps	0x40(%rsp), %xmm10
1454289848Sjkim	movaps	0x50(%rsp), %xmm11
1455289848Sjkim	movaps	0x60(%rsp), %xmm12
1456289848Sjkim	movaps	0x70(%rsp), %xmm13
1457289848Sjkim	movaps	0x80(%rsp), %xmm14
1458289848Sjkim	movaps	0x90(%rsp), %xmm15
1459289848Sjkim	lea	0xa8(%rsp), %rsp
1460289848Sjkim.LSEH_end_ecp_nistz256_select_w5:
1461289848Sjkim___
1462289848Sjkim$code.=<<___;
1463289848Sjkim	ret
1464289848Sjkim.size	ecp_nistz256_select_w5,.-ecp_nistz256_select_w5
1465289848Sjkim
1466289848Sjkim################################################################################
1467289848Sjkim# void ecp_nistz256_select_w7(uint64_t *val, uint64_t *in_t, int index);
1468289848Sjkim.globl	ecp_nistz256_select_w7
1469289848Sjkim.type	ecp_nistz256_select_w7,\@abi-omnipotent
1470289848Sjkim.align	32
1471289848Sjkimecp_nistz256_select_w7:
1472289848Sjkim___
1473289848Sjkim$code.=<<___	if ($avx>1);
1474289848Sjkim	mov	OPENSSL_ia32cap_P+8(%rip), %eax
1475289848Sjkim	test	\$`1<<5`, %eax
1476289848Sjkim	jnz	.Lavx2_select_w7
1477289848Sjkim___
1478289848Sjkim$code.=<<___	if ($win64);
1479289848Sjkim	lea	-0x88(%rsp), %rax
1480289848Sjkim.LSEH_begin_ecp_nistz256_select_w7:
1481289848Sjkim	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
1482289848Sjkim	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6, -0x20(%rax)
1483289848Sjkim	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7, -0x10(%rax)
1484289848Sjkim	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8, 0(%rax)
1485289848Sjkim	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9, 0x10(%rax)
1486289848Sjkim	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10, 0x20(%rax)
1487289848Sjkim	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11, 0x30(%rax)
1488289848Sjkim	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12, 0x40(%rax)
1489289848Sjkim	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13, 0x50(%rax)
1490289848Sjkim	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14, 0x60(%rax)
1491289848Sjkim	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15, 0x70(%rax)
1492289848Sjkim___
1493289848Sjkim$code.=<<___;
1494289848Sjkim	movdqa	.LOne(%rip), $M0
1495289848Sjkim	movd	$index, $INDEX
1496289848Sjkim
1497289848Sjkim	pxor	$Ra, $Ra
1498289848Sjkim	pxor	$Rb, $Rb
1499289848Sjkim	pxor	$Rc, $Rc
1500289848Sjkim	pxor	$Rd, $Rd
1501289848Sjkim
1502289848Sjkim	movdqa	$M0, $ONE
1503289848Sjkim	pshufd	\$0, $INDEX, $INDEX
1504289848Sjkim	mov	\$64, %rax
1505289848Sjkim
1506289848Sjkim.Lselect_loop_sse_w7:
1507289848Sjkim	movdqa	$M0, $TMP0
1508289848Sjkim	paddd	$ONE, $M0
1509289848Sjkim	movdqa	16*0($in_t), $T0a
1510289848Sjkim	movdqa	16*1($in_t), $T0b
1511289848Sjkim	pcmpeqd	$INDEX, $TMP0
1512289848Sjkim	movdqa	16*2($in_t), $T0c
1513289848Sjkim	movdqa	16*3($in_t), $T0d
1514289848Sjkim	lea	16*4($in_t), $in_t
1515289848Sjkim
1516289848Sjkim	pand	$TMP0, $T0a
1517289848Sjkim	pand	$TMP0, $T0b
1518289848Sjkim	por	$T0a, $Ra
1519289848Sjkim	pand	$TMP0, $T0c
1520289848Sjkim	por	$T0b, $Rb
1521289848Sjkim	pand	$TMP0, $T0d
1522289848Sjkim	por	$T0c, $Rc
1523289848Sjkim	prefetcht0	255($in_t)
1524289848Sjkim	por	$T0d, $Rd
1525289848Sjkim
1526289848Sjkim	dec	%rax
1527289848Sjkim	jnz	.Lselect_loop_sse_w7
1528289848Sjkim
1529289848Sjkim	movdqu	$Ra, 16*0($val)
1530289848Sjkim	movdqu	$Rb, 16*1($val)
1531289848Sjkim	movdqu	$Rc, 16*2($val)
1532289848Sjkim	movdqu	$Rd, 16*3($val)
1533289848Sjkim___
1534289848Sjkim$code.=<<___	if ($win64);
1535289848Sjkim	movaps	(%rsp), %xmm6
1536289848Sjkim	movaps	0x10(%rsp), %xmm7
1537289848Sjkim	movaps	0x20(%rsp), %xmm8
1538289848Sjkim	movaps	0x30(%rsp), %xmm9
1539289848Sjkim	movaps	0x40(%rsp), %xmm10
1540289848Sjkim	movaps	0x50(%rsp), %xmm11
1541289848Sjkim	movaps	0x60(%rsp), %xmm12
1542289848Sjkim	movaps	0x70(%rsp), %xmm13
1543289848Sjkim	movaps	0x80(%rsp), %xmm14
1544289848Sjkim	movaps	0x90(%rsp), %xmm15
1545289848Sjkim	lea	0xa8(%rsp), %rsp
1546289848Sjkim.LSEH_end_ecp_nistz256_select_w7:
1547289848Sjkim___
1548289848Sjkim$code.=<<___;
1549289848Sjkim	ret
1550289848Sjkim.size	ecp_nistz256_select_w7,.-ecp_nistz256_select_w7
1551289848Sjkim___
1552289848Sjkim}
1553289848Sjkimif ($avx>1) {
1554289848Sjkimmy ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1555289848Sjkimmy ($TWO,$INDEX,$Ra,$Rb,$Rc)=map("%ymm$_",(0..4));
1556289848Sjkimmy ($M0,$T0a,$T0b,$T0c,$TMP0)=map("%ymm$_",(5..9));
1557289848Sjkimmy ($M1,$T1a,$T1b,$T1c,$TMP1)=map("%ymm$_",(10..14));
1558289848Sjkim
1559289848Sjkim$code.=<<___;
1560289848Sjkim################################################################################
1561289848Sjkim# void ecp_nistz256_avx2_select_w5(uint64_t *val, uint64_t *in_t, int index);
1562289848Sjkim.type	ecp_nistz256_avx2_select_w5,\@abi-omnipotent
1563289848Sjkim.align	32
1564289848Sjkimecp_nistz256_avx2_select_w5:
1565289848Sjkim.Lavx2_select_w5:
1566289848Sjkim	vzeroupper
1567289848Sjkim___
1568289848Sjkim$code.=<<___	if ($win64);
1569289848Sjkim	lea	-0x88(%rsp), %rax
1570289848Sjkim.LSEH_begin_ecp_nistz256_avx2_select_w5:
1571289848Sjkim	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
1572289848Sjkim	.byte	0xc5,0xf8,0x29,0x70,0xe0	#vmovaps %xmm6, -0x20(%rax)
1573289848Sjkim	.byte	0xc5,0xf8,0x29,0x78,0xf0	#vmovaps %xmm7, -0x10(%rax)
1574289848Sjkim	.byte	0xc5,0x78,0x29,0x40,0x00	#vmovaps %xmm8, 8(%rax)
1575289848Sjkim	.byte	0xc5,0x78,0x29,0x48,0x10	#vmovaps %xmm9, 0x10(%rax)
1576289848Sjkim	.byte	0xc5,0x78,0x29,0x50,0x20	#vmovaps %xmm10, 0x20(%rax)
1577289848Sjkim	.byte	0xc5,0x78,0x29,0x58,0x30	#vmovaps %xmm11, 0x30(%rax)
1578289848Sjkim	.byte	0xc5,0x78,0x29,0x60,0x40	#vmovaps %xmm12, 0x40(%rax)
1579289848Sjkim	.byte	0xc5,0x78,0x29,0x68,0x50	#vmovaps %xmm13, 0x50(%rax)
1580289848Sjkim	.byte	0xc5,0x78,0x29,0x70,0x60	#vmovaps %xmm14, 0x60(%rax)
1581289848Sjkim	.byte	0xc5,0x78,0x29,0x78,0x70	#vmovaps %xmm15, 0x70(%rax)
1582289848Sjkim___
1583289848Sjkim$code.=<<___;
1584289848Sjkim	vmovdqa	.LTwo(%rip), $TWO
1585289848Sjkim
1586289848Sjkim	vpxor	$Ra, $Ra, $Ra
1587289848Sjkim	vpxor	$Rb, $Rb, $Rb
1588289848Sjkim	vpxor	$Rc, $Rc, $Rc
1589289848Sjkim
1590289848Sjkim	vmovdqa .LOne(%rip), $M0
1591289848Sjkim	vmovdqa .LTwo(%rip), $M1
1592289848Sjkim
1593289848Sjkim	vmovd	$index, %xmm1
1594289848Sjkim	vpermd	$INDEX, $Ra, $INDEX
1595289848Sjkim
1596289848Sjkim	mov	\$8, %rax
1597289848Sjkim.Lselect_loop_avx2_w5:
1598289848Sjkim
1599289848Sjkim	vmovdqa	32*0($in_t), $T0a
1600289848Sjkim	vmovdqa	32*1($in_t), $T0b
1601289848Sjkim	vmovdqa	32*2($in_t), $T0c
1602289848Sjkim
1603289848Sjkim	vmovdqa	32*3($in_t), $T1a
1604289848Sjkim	vmovdqa	32*4($in_t), $T1b
1605289848Sjkim	vmovdqa	32*5($in_t), $T1c
1606289848Sjkim
1607289848Sjkim	vpcmpeqd	$INDEX, $M0, $TMP0
1608289848Sjkim	vpcmpeqd	$INDEX, $M1, $TMP1
1609289848Sjkim
1610289848Sjkim	vpaddd	$TWO, $M0, $M0
1611289848Sjkim	vpaddd	$TWO, $M1, $M1
1612289848Sjkim	lea	32*6($in_t), $in_t
1613289848Sjkim
1614289848Sjkim	vpand	$TMP0, $T0a, $T0a
1615289848Sjkim	vpand	$TMP0, $T0b, $T0b
1616289848Sjkim	vpand	$TMP0, $T0c, $T0c
1617289848Sjkim	vpand	$TMP1, $T1a, $T1a
1618289848Sjkim	vpand	$TMP1, $T1b, $T1b
1619289848Sjkim	vpand	$TMP1, $T1c, $T1c
1620289848Sjkim
1621289848Sjkim	vpxor	$T0a, $Ra, $Ra
1622289848Sjkim	vpxor	$T0b, $Rb, $Rb
1623289848Sjkim	vpxor	$T0c, $Rc, $Rc
1624289848Sjkim	vpxor	$T1a, $Ra, $Ra
1625289848Sjkim	vpxor	$T1b, $Rb, $Rb
1626289848Sjkim	vpxor	$T1c, $Rc, $Rc
1627289848Sjkim
1628289848Sjkim	dec %rax
1629289848Sjkim	jnz .Lselect_loop_avx2_w5
1630289848Sjkim
1631289848Sjkim	vmovdqu $Ra, 32*0($val)
1632289848Sjkim	vmovdqu $Rb, 32*1($val)
1633289848Sjkim	vmovdqu $Rc, 32*2($val)
1634289848Sjkim	vzeroupper
1635289848Sjkim___
1636289848Sjkim$code.=<<___	if ($win64);
1637289848Sjkim	movaps	(%rsp), %xmm6
1638289848Sjkim	movaps	0x10(%rsp), %xmm7
1639289848Sjkim	movaps	0x20(%rsp), %xmm8
1640289848Sjkim	movaps	0x30(%rsp), %xmm9
1641289848Sjkim	movaps	0x40(%rsp), %xmm10
1642289848Sjkim	movaps	0x50(%rsp), %xmm11
1643289848Sjkim	movaps	0x60(%rsp), %xmm12
1644289848Sjkim	movaps	0x70(%rsp), %xmm13
1645289848Sjkim	movaps	0x80(%rsp), %xmm14
1646289848Sjkim	movaps	0x90(%rsp), %xmm15
1647289848Sjkim	lea	0xa8(%rsp), %rsp
1648289848Sjkim.LSEH_end_ecp_nistz256_avx2_select_w5:
1649289848Sjkim___
1650289848Sjkim$code.=<<___;
1651289848Sjkim	ret
1652289848Sjkim.size	ecp_nistz256_avx2_select_w5,.-ecp_nistz256_avx2_select_w5
1653289848Sjkim___
1654289848Sjkim}
1655289848Sjkimif ($avx>1) {
1656289848Sjkimmy ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1657289848Sjkimmy ($THREE,$INDEX,$Ra,$Rb)=map("%ymm$_",(0..3));
1658289848Sjkimmy ($M0,$T0a,$T0b,$TMP0)=map("%ymm$_",(4..7));
1659289848Sjkimmy ($M1,$T1a,$T1b,$TMP1)=map("%ymm$_",(8..11));
1660289848Sjkimmy ($M2,$T2a,$T2b,$TMP2)=map("%ymm$_",(12..15));
1661289848Sjkim
1662289848Sjkim$code.=<<___;
1663289848Sjkim
1664289848Sjkim################################################################################
1665289848Sjkim# void ecp_nistz256_avx2_select_w7(uint64_t *val, uint64_t *in_t, int index);
1666289848Sjkim.globl	ecp_nistz256_avx2_select_w7
1667289848Sjkim.type	ecp_nistz256_avx2_select_w7,\@abi-omnipotent
1668289848Sjkim.align	32
1669289848Sjkimecp_nistz256_avx2_select_w7:
1670289848Sjkim.Lavx2_select_w7:
1671289848Sjkim	vzeroupper
1672289848Sjkim___
1673289848Sjkim$code.=<<___	if ($win64);
1674289848Sjkim	lea	-0x88(%rsp), %rax
1675289848Sjkim.LSEH_begin_ecp_nistz256_avx2_select_w7:
1676289848Sjkim	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
1677289848Sjkim	.byte	0xc5,0xf8,0x29,0x70,0xe0	#vmovaps %xmm6, -0x20(%rax)
1678289848Sjkim	.byte	0xc5,0xf8,0x29,0x78,0xf0	#vmovaps %xmm7, -0x10(%rax)
1679289848Sjkim	.byte	0xc5,0x78,0x29,0x40,0x00	#vmovaps %xmm8, 8(%rax)
1680289848Sjkim	.byte	0xc5,0x78,0x29,0x48,0x10	#vmovaps %xmm9, 0x10(%rax)
1681289848Sjkim	.byte	0xc5,0x78,0x29,0x50,0x20	#vmovaps %xmm10, 0x20(%rax)
1682289848Sjkim	.byte	0xc5,0x78,0x29,0x58,0x30	#vmovaps %xmm11, 0x30(%rax)
1683289848Sjkim	.byte	0xc5,0x78,0x29,0x60,0x40	#vmovaps %xmm12, 0x40(%rax)
1684289848Sjkim	.byte	0xc5,0x78,0x29,0x68,0x50	#vmovaps %xmm13, 0x50(%rax)
1685289848Sjkim	.byte	0xc5,0x78,0x29,0x70,0x60	#vmovaps %xmm14, 0x60(%rax)
1686289848Sjkim	.byte	0xc5,0x78,0x29,0x78,0x70	#vmovaps %xmm15, 0x70(%rax)
1687289848Sjkim___
1688289848Sjkim$code.=<<___;
1689289848Sjkim	vmovdqa	.LThree(%rip), $THREE
1690289848Sjkim
1691289848Sjkim	vpxor	$Ra, $Ra, $Ra
1692289848Sjkim	vpxor	$Rb, $Rb, $Rb
1693289848Sjkim
1694289848Sjkim	vmovdqa .LOne(%rip), $M0
1695289848Sjkim	vmovdqa .LTwo(%rip), $M1
1696289848Sjkim	vmovdqa .LThree(%rip), $M2
1697289848Sjkim
1698289848Sjkim	vmovd	$index, %xmm1
1699289848Sjkim	vpermd	$INDEX, $Ra, $INDEX
1700289848Sjkim	# Skip index = 0, because it is implicitly the point at infinity
1701289848Sjkim
1702289848Sjkim	mov	\$21, %rax
1703289848Sjkim.Lselect_loop_avx2_w7:
1704289848Sjkim
1705289848Sjkim	vmovdqa	32*0($in_t), $T0a
1706289848Sjkim	vmovdqa	32*1($in_t), $T0b
1707289848Sjkim
1708289848Sjkim	vmovdqa	32*2($in_t), $T1a
1709289848Sjkim	vmovdqa	32*3($in_t), $T1b
1710289848Sjkim
1711289848Sjkim	vmovdqa	32*4($in_t), $T2a
1712289848Sjkim	vmovdqa	32*5($in_t), $T2b
1713289848Sjkim
1714289848Sjkim	vpcmpeqd	$INDEX, $M0, $TMP0
1715289848Sjkim	vpcmpeqd	$INDEX, $M1, $TMP1
1716289848Sjkim	vpcmpeqd	$INDEX, $M2, $TMP2
1717289848Sjkim
1718289848Sjkim	vpaddd	$THREE, $M0, $M0
1719289848Sjkim	vpaddd	$THREE, $M1, $M1
1720289848Sjkim	vpaddd	$THREE, $M2, $M2
1721289848Sjkim	lea	32*6($in_t), $in_t
1722289848Sjkim
1723289848Sjkim	vpand	$TMP0, $T0a, $T0a
1724289848Sjkim	vpand	$TMP0, $T0b, $T0b
1725289848Sjkim	vpand	$TMP1, $T1a, $T1a
1726289848Sjkim	vpand	$TMP1, $T1b, $T1b
1727289848Sjkim	vpand	$TMP2, $T2a, $T2a
1728289848Sjkim	vpand	$TMP2, $T2b, $T2b
1729289848Sjkim
1730289848Sjkim	vpxor	$T0a, $Ra, $Ra
1731289848Sjkim	vpxor	$T0b, $Rb, $Rb
1732289848Sjkim	vpxor	$T1a, $Ra, $Ra
1733289848Sjkim	vpxor	$T1b, $Rb, $Rb
1734289848Sjkim	vpxor	$T2a, $Ra, $Ra
1735289848Sjkim	vpxor	$T2b, $Rb, $Rb
1736289848Sjkim
1737289848Sjkim	dec %rax
1738289848Sjkim	jnz .Lselect_loop_avx2_w7
1739289848Sjkim
1740289848Sjkim
1741289848Sjkim	vmovdqa	32*0($in_t), $T0a
1742289848Sjkim	vmovdqa	32*1($in_t), $T0b
1743289848Sjkim
1744289848Sjkim	vpcmpeqd	$INDEX, $M0, $TMP0
1745289848Sjkim
1746289848Sjkim	vpand	$TMP0, $T0a, $T0a
1747289848Sjkim	vpand	$TMP0, $T0b, $T0b
1748289848Sjkim
1749289848Sjkim	vpxor	$T0a, $Ra, $Ra
1750289848Sjkim	vpxor	$T0b, $Rb, $Rb
1751289848Sjkim
1752289848Sjkim	vmovdqu $Ra, 32*0($val)
1753289848Sjkim	vmovdqu $Rb, 32*1($val)
1754289848Sjkim	vzeroupper
1755289848Sjkim___
1756289848Sjkim$code.=<<___	if ($win64);
1757289848Sjkim	movaps	(%rsp), %xmm6
1758289848Sjkim	movaps	0x10(%rsp), %xmm7
1759289848Sjkim	movaps	0x20(%rsp), %xmm8
1760289848Sjkim	movaps	0x30(%rsp), %xmm9
1761289848Sjkim	movaps	0x40(%rsp), %xmm10
1762289848Sjkim	movaps	0x50(%rsp), %xmm11
1763289848Sjkim	movaps	0x60(%rsp), %xmm12
1764289848Sjkim	movaps	0x70(%rsp), %xmm13
1765289848Sjkim	movaps	0x80(%rsp), %xmm14
1766289848Sjkim	movaps	0x90(%rsp), %xmm15
1767289848Sjkim	lea	0xa8(%rsp), %rsp
1768289848Sjkim.LSEH_end_ecp_nistz256_avx2_select_w7:
1769289848Sjkim___
1770289848Sjkim$code.=<<___;
1771289848Sjkim	ret
1772289848Sjkim.size	ecp_nistz256_avx2_select_w7,.-ecp_nistz256_avx2_select_w7
1773289848Sjkim___
1774289848Sjkim} else {
1775289848Sjkim$code.=<<___;
1776289848Sjkim.globl	ecp_nistz256_avx2_select_w7
1777289848Sjkim.type	ecp_nistz256_avx2_select_w7,\@function,3
1778289848Sjkim.align	32
1779289848Sjkimecp_nistz256_avx2_select_w7:
1780289848Sjkim	.byte	0x0f,0x0b	# ud2
1781289848Sjkim	ret
1782289848Sjkim.size	ecp_nistz256_avx2_select_w7,.-ecp_nistz256_avx2_select_w7
1783289848Sjkim___
1784289848Sjkim}
1785289848Sjkim{{{
1786289848Sjkim########################################################################
1787289848Sjkim# This block implements higher level point_double, point_add and
1788289848Sjkim# point_add_affine. The key to performance in this case is to allow
1789289848Sjkim# out-of-order execution logic to overlap computations from next step
1790289848Sjkim# with tail processing from current step. By using tailored calling
1791289848Sjkim# sequence we minimize inter-step overhead to give processor better
1792289848Sjkim# shot at overlapping operations...
1793289848Sjkim#
1794289848Sjkim# You will notice that input data is copied to stack. Trouble is that
1795289848Sjkim# there are no registers to spare for holding original pointers and
1796289848Sjkim# reloading them, pointers, would create undesired dependencies on
1797289848Sjkim# effective addresses calculation paths. In other words it's too done
1798289848Sjkim# to favour out-of-order execution logic.
1799289848Sjkim#						<appro@openssl.org>
1800289848Sjkim
1801289848Sjkimmy ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
1802289848Sjkimmy ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
1803289848Sjkimmy ($t0,$t1,$t2,$t3,$t4)=("%rax","%rbp","%rcx",$acc4,$acc4);
1804289848Sjkimmy ($poly1,$poly3)=($acc6,$acc7);
1805289848Sjkim
1806289848Sjkimsub load_for_mul () {
1807289848Sjkimmy ($a,$b,$src0) = @_;
1808289848Sjkimmy $bias = $src0 eq "%rax" ? 0 : -128;
1809289848Sjkim
1810289848Sjkim"	mov	$b, $src0
1811289848Sjkim	lea	$b, $b_ptr
1812289848Sjkim	mov	8*0+$a, $acc1
1813289848Sjkim	mov	8*1+$a, $acc2
1814289848Sjkim	lea	$bias+$a, $a_ptr
1815289848Sjkim	mov	8*2+$a, $acc3
1816289848Sjkim	mov	8*3+$a, $acc4"
1817289848Sjkim}
1818289848Sjkim
1819289848Sjkimsub load_for_sqr () {
1820289848Sjkimmy ($a,$src0) = @_;
1821289848Sjkimmy $bias = $src0 eq "%rax" ? 0 : -128;
1822289848Sjkim
1823289848Sjkim"	mov	8*0+$a, $src0
1824289848Sjkim	mov	8*1+$a, $acc6
1825289848Sjkim	lea	$bias+$a, $a_ptr
1826289848Sjkim	mov	8*2+$a, $acc7
1827289848Sjkim	mov	8*3+$a, $acc0"
1828289848Sjkim}
1829289848Sjkim
1830289848Sjkim									{
1831289848Sjkim########################################################################
1832289848Sjkim# operate in 4-5-0-1 "name space" that matches multiplication output
1833289848Sjkim#
1834289848Sjkimmy ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
1835289848Sjkim
1836289848Sjkim$code.=<<___;
1837289848Sjkim.type	__ecp_nistz256_add_toq,\@abi-omnipotent
1838289848Sjkim.align	32
1839289848Sjkim__ecp_nistz256_add_toq:
1840306195Sjkim	xor	$t4,$t4
1841289848Sjkim	add	8*0($b_ptr), $a0
1842289848Sjkim	adc	8*1($b_ptr), $a1
1843289848Sjkim	 mov	$a0, $t0
1844289848Sjkim	adc	8*2($b_ptr), $a2
1845289848Sjkim	adc	8*3($b_ptr), $a3
1846289848Sjkim	 mov	$a1, $t1
1847306195Sjkim	adc	\$0, $t4
1848289848Sjkim
1849289848Sjkim	sub	\$-1, $a0
1850289848Sjkim	 mov	$a2, $t2
1851289848Sjkim	sbb	$poly1, $a1
1852289848Sjkim	sbb	\$0, $a2
1853289848Sjkim	 mov	$a3, $t3
1854289848Sjkim	sbb	$poly3, $a3
1855306195Sjkim	sbb	\$0, $t4
1856289848Sjkim
1857306195Sjkim	cmovc	$t0, $a0
1858306195Sjkim	cmovc	$t1, $a1
1859289848Sjkim	mov	$a0, 8*0($r_ptr)
1860306195Sjkim	cmovc	$t2, $a2
1861289848Sjkim	mov	$a1, 8*1($r_ptr)
1862306195Sjkim	cmovc	$t3, $a3
1863289848Sjkim	mov	$a2, 8*2($r_ptr)
1864289848Sjkim	mov	$a3, 8*3($r_ptr)
1865289848Sjkim
1866289848Sjkim	ret
1867289848Sjkim.size	__ecp_nistz256_add_toq,.-__ecp_nistz256_add_toq
1868289848Sjkim
1869289848Sjkim.type	__ecp_nistz256_sub_fromq,\@abi-omnipotent
1870289848Sjkim.align	32
1871289848Sjkim__ecp_nistz256_sub_fromq:
1872289848Sjkim	sub	8*0($b_ptr), $a0
1873289848Sjkim	sbb	8*1($b_ptr), $a1
1874289848Sjkim	 mov	$a0, $t0
1875289848Sjkim	sbb	8*2($b_ptr), $a2
1876289848Sjkim	sbb	8*3($b_ptr), $a3
1877289848Sjkim	 mov	$a1, $t1
1878289848Sjkim	sbb	$t4, $t4
1879289848Sjkim
1880289848Sjkim	add	\$-1, $a0
1881289848Sjkim	 mov	$a2, $t2
1882289848Sjkim	adc	$poly1, $a1
1883289848Sjkim	adc	\$0, $a2
1884289848Sjkim	 mov	$a3, $t3
1885289848Sjkim	adc	$poly3, $a3
1886289848Sjkim	test	$t4, $t4
1887289848Sjkim
1888289848Sjkim	cmovz	$t0, $a0
1889289848Sjkim	cmovz	$t1, $a1
1890289848Sjkim	mov	$a0, 8*0($r_ptr)
1891289848Sjkim	cmovz	$t2, $a2
1892289848Sjkim	mov	$a1, 8*1($r_ptr)
1893289848Sjkim	cmovz	$t3, $a3
1894289848Sjkim	mov	$a2, 8*2($r_ptr)
1895289848Sjkim	mov	$a3, 8*3($r_ptr)
1896289848Sjkim
1897289848Sjkim	ret
1898289848Sjkim.size	__ecp_nistz256_sub_fromq,.-__ecp_nistz256_sub_fromq
1899289848Sjkim
1900289848Sjkim.type	__ecp_nistz256_subq,\@abi-omnipotent
1901289848Sjkim.align	32
1902289848Sjkim__ecp_nistz256_subq:
1903289848Sjkim	sub	$a0, $t0
1904289848Sjkim	sbb	$a1, $t1
1905289848Sjkim	 mov	$t0, $a0
1906289848Sjkim	sbb	$a2, $t2
1907289848Sjkim	sbb	$a3, $t3
1908289848Sjkim	 mov	$t1, $a1
1909289848Sjkim	sbb	$t4, $t4
1910289848Sjkim
1911289848Sjkim	add	\$-1, $t0
1912289848Sjkim	 mov	$t2, $a2
1913289848Sjkim	adc	$poly1, $t1
1914289848Sjkim	adc	\$0, $t2
1915289848Sjkim	 mov	$t3, $a3
1916289848Sjkim	adc	$poly3, $t3
1917289848Sjkim	test	$t4, $t4
1918289848Sjkim
1919289848Sjkim	cmovnz	$t0, $a0
1920289848Sjkim	cmovnz	$t1, $a1
1921289848Sjkim	cmovnz	$t2, $a2
1922289848Sjkim	cmovnz	$t3, $a3
1923289848Sjkim
1924289848Sjkim	ret
1925289848Sjkim.size	__ecp_nistz256_subq,.-__ecp_nistz256_subq
1926289848Sjkim
1927289848Sjkim.type	__ecp_nistz256_mul_by_2q,\@abi-omnipotent
1928289848Sjkim.align	32
1929289848Sjkim__ecp_nistz256_mul_by_2q:
1930306195Sjkim	xor	$t4, $t4
1931289848Sjkim	add	$a0, $a0		# a0:a3+a0:a3
1932289848Sjkim	adc	$a1, $a1
1933289848Sjkim	 mov	$a0, $t0
1934289848Sjkim	adc	$a2, $a2
1935289848Sjkim	adc	$a3, $a3
1936289848Sjkim	 mov	$a1, $t1
1937306195Sjkim	adc	\$0, $t4
1938289848Sjkim
1939289848Sjkim	sub	\$-1, $a0
1940289848Sjkim	 mov	$a2, $t2
1941289848Sjkim	sbb	$poly1, $a1
1942289848Sjkim	sbb	\$0, $a2
1943289848Sjkim	 mov	$a3, $t3
1944289848Sjkim	sbb	$poly3, $a3
1945306195Sjkim	sbb	\$0, $t4
1946289848Sjkim
1947306195Sjkim	cmovc	$t0, $a0
1948306195Sjkim	cmovc	$t1, $a1
1949289848Sjkim	mov	$a0, 8*0($r_ptr)
1950306195Sjkim	cmovc	$t2, $a2
1951289848Sjkim	mov	$a1, 8*1($r_ptr)
1952306195Sjkim	cmovc	$t3, $a3
1953289848Sjkim	mov	$a2, 8*2($r_ptr)
1954289848Sjkim	mov	$a3, 8*3($r_ptr)
1955289848Sjkim
1956289848Sjkim	ret
1957289848Sjkim.size	__ecp_nistz256_mul_by_2q,.-__ecp_nistz256_mul_by_2q
1958289848Sjkim___
1959289848Sjkim									}
1960289848Sjkimsub gen_double () {
1961289848Sjkim    my $x = shift;
1962289848Sjkim    my ($src0,$sfx,$bias);
1963289848Sjkim    my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
1964289848Sjkim
1965289848Sjkim    if ($x ne "x") {
1966289848Sjkim	$src0 = "%rax";
1967289848Sjkim	$sfx  = "";
1968289848Sjkim	$bias = 0;
1969289848Sjkim
1970289848Sjkim$code.=<<___;
1971289848Sjkim.globl	ecp_nistz256_point_double
1972289848Sjkim.type	ecp_nistz256_point_double,\@function,2
1973289848Sjkim.align	32
1974289848Sjkimecp_nistz256_point_double:
1975289848Sjkim___
1976289848Sjkim$code.=<<___	if ($addx);
1977289848Sjkim	mov	\$0x80100, %ecx
1978289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
1979289848Sjkim	cmp	\$0x80100, %ecx
1980289848Sjkim	je	.Lpoint_doublex
1981289848Sjkim___
1982289848Sjkim    } else {
1983289848Sjkim	$src0 = "%rdx";
1984289848Sjkim	$sfx  = "x";
1985289848Sjkim	$bias = 128;
1986289848Sjkim
1987289848Sjkim$code.=<<___;
1988289848Sjkim.type	ecp_nistz256_point_doublex,\@function,2
1989289848Sjkim.align	32
1990289848Sjkimecp_nistz256_point_doublex:
1991289848Sjkim.Lpoint_doublex:
1992289848Sjkim___
1993289848Sjkim    }
1994289848Sjkim$code.=<<___;
1995289848Sjkim	push	%rbp
1996289848Sjkim	push	%rbx
1997289848Sjkim	push	%r12
1998289848Sjkim	push	%r13
1999289848Sjkim	push	%r14
2000289848Sjkim	push	%r15
2001289848Sjkim	sub	\$32*5+8, %rsp
2002289848Sjkim
2003296279Sjkim.Lpoint_double_shortcut$x:
2004289848Sjkim	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$a_ptr.x
2005289848Sjkim	mov	$a_ptr, $b_ptr			# backup copy
2006289848Sjkim	movdqu	0x10($a_ptr), %xmm1
2007289848Sjkim	 mov	0x20+8*0($a_ptr), $acc4		# load in_y in "5-4-0-1" order
2008289848Sjkim	 mov	0x20+8*1($a_ptr), $acc5
2009289848Sjkim	 mov	0x20+8*2($a_ptr), $acc0
2010289848Sjkim	 mov	0x20+8*3($a_ptr), $acc1
2011289848Sjkim	 mov	.Lpoly+8*1(%rip), $poly1
2012289848Sjkim	 mov	.Lpoly+8*3(%rip), $poly3
2013289848Sjkim	movdqa	%xmm0, $in_x(%rsp)
2014289848Sjkim	movdqa	%xmm1, $in_x+0x10(%rsp)
2015289848Sjkim	lea	0x20($r_ptr), $acc2
2016289848Sjkim	lea	0x40($r_ptr), $acc3
2017289848Sjkim	movq	$r_ptr, %xmm0
2018289848Sjkim	movq	$acc2, %xmm1
2019289848Sjkim	movq	$acc3, %xmm2
2020289848Sjkim
2021289848Sjkim	lea	$S(%rsp), $r_ptr
2022289848Sjkim	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(S, in_y);
2023289848Sjkim
2024289848Sjkim	mov	0x40+8*0($a_ptr), $src0
2025289848Sjkim	mov	0x40+8*1($a_ptr), $acc6
2026289848Sjkim	mov	0x40+8*2($a_ptr), $acc7
2027289848Sjkim	mov	0x40+8*3($a_ptr), $acc0
2028289848Sjkim	lea	0x40-$bias($a_ptr), $a_ptr
2029289848Sjkim	lea	$Zsqr(%rsp), $r_ptr
2030289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Zsqr, in_z);
2031289848Sjkim
2032289848Sjkim	`&load_for_sqr("$S(%rsp)", "$src0")`
2033289848Sjkim	lea	$S(%rsp), $r_ptr
2034289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(S, S);
2035289848Sjkim
2036289848Sjkim	mov	0x20($b_ptr), $src0		# $b_ptr is still valid
2037289848Sjkim	mov	0x40+8*0($b_ptr), $acc1
2038289848Sjkim	mov	0x40+8*1($b_ptr), $acc2
2039289848Sjkim	mov	0x40+8*2($b_ptr), $acc3
2040289848Sjkim	mov	0x40+8*3($b_ptr), $acc4
2041289848Sjkim	lea	0x40-$bias($b_ptr), $a_ptr
2042289848Sjkim	lea	0x20($b_ptr), $b_ptr
2043289848Sjkim	movq	%xmm2, $r_ptr
2044289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, in_z, in_y);
2045289848Sjkim	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(res_z, res_z);
2046289848Sjkim
2047289848Sjkim	mov	$in_x+8*0(%rsp), $acc4		# "5-4-0-1" order
2048289848Sjkim	mov	$in_x+8*1(%rsp), $acc5
2049289848Sjkim	lea	$Zsqr(%rsp), $b_ptr
2050289848Sjkim	mov	$in_x+8*2(%rsp), $acc0
2051289848Sjkim	mov	$in_x+8*3(%rsp), $acc1
2052289848Sjkim	lea	$M(%rsp), $r_ptr
2053289848Sjkim	call	__ecp_nistz256_add_to$x		# p256_add(M, in_x, Zsqr);
2054289848Sjkim
2055289848Sjkim	mov	$in_x+8*0(%rsp), $acc4		# "5-4-0-1" order
2056289848Sjkim	mov	$in_x+8*1(%rsp), $acc5
2057289848Sjkim	lea	$Zsqr(%rsp), $b_ptr
2058289848Sjkim	mov	$in_x+8*2(%rsp), $acc0
2059289848Sjkim	mov	$in_x+8*3(%rsp), $acc1
2060289848Sjkim	lea	$Zsqr(%rsp), $r_ptr
2061289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(Zsqr, in_x, Zsqr);
2062289848Sjkim
2063289848Sjkim	`&load_for_sqr("$S(%rsp)", "$src0")`
2064289848Sjkim	movq	%xmm1, $r_ptr
2065289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(res_y, S);
2066289848Sjkim___
2067289848Sjkim{
2068289848Sjkim######## ecp_nistz256_div_by_2(res_y, res_y); ##########################
2069289848Sjkim# operate in 4-5-6-7 "name space" that matches squaring output
2070289848Sjkim#
2071289848Sjkimmy ($poly1,$poly3)=($a_ptr,$t1);
2072289848Sjkimmy ($a0,$a1,$a2,$a3,$t3,$t4,$t1)=($acc4,$acc5,$acc6,$acc7,$acc0,$acc1,$acc2);
2073289848Sjkim
2074289848Sjkim$code.=<<___;
2075289848Sjkim	xor	$t4, $t4
2076289848Sjkim	mov	$a0, $t0
2077289848Sjkim	add	\$-1, $a0
2078289848Sjkim	mov	$a1, $t1
2079289848Sjkim	adc	$poly1, $a1
2080289848Sjkim	mov	$a2, $t2
2081289848Sjkim	adc	\$0, $a2
2082289848Sjkim	mov	$a3, $t3
2083289848Sjkim	adc	$poly3, $a3
2084289848Sjkim	adc	\$0, $t4
2085289848Sjkim	xor	$a_ptr, $a_ptr		# borrow $a_ptr
2086289848Sjkim	test	\$1, $t0
2087289848Sjkim
2088289848Sjkim	cmovz	$t0, $a0
2089289848Sjkim	cmovz	$t1, $a1
2090289848Sjkim	cmovz	$t2, $a2
2091289848Sjkim	cmovz	$t3, $a3
2092289848Sjkim	cmovz	$a_ptr, $t4
2093289848Sjkim
2094289848Sjkim	mov	$a1, $t0		# a0:a3>>1
2095289848Sjkim	shr	\$1, $a0
2096289848Sjkim	shl	\$63, $t0
2097289848Sjkim	mov	$a2, $t1
2098289848Sjkim	shr	\$1, $a1
2099289848Sjkim	or	$t0, $a0
2100289848Sjkim	shl	\$63, $t1
2101289848Sjkim	mov	$a3, $t2
2102289848Sjkim	shr	\$1, $a2
2103289848Sjkim	or	$t1, $a1
2104289848Sjkim	shl	\$63, $t2
2105289848Sjkim	mov	$a0, 8*0($r_ptr)
2106289848Sjkim	shr	\$1, $a3
2107289848Sjkim	mov	$a1, 8*1($r_ptr)
2108289848Sjkim	shl	\$63, $t4
2109289848Sjkim	or	$t2, $a2
2110289848Sjkim	or	$t4, $a3
2111289848Sjkim	mov	$a2, 8*2($r_ptr)
2112289848Sjkim	mov	$a3, 8*3($r_ptr)
2113289848Sjkim___
2114289848Sjkim}
2115289848Sjkim$code.=<<___;
2116289848Sjkim	`&load_for_mul("$M(%rsp)", "$Zsqr(%rsp)", "$src0")`
2117289848Sjkim	lea	$M(%rsp), $r_ptr
2118289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(M, M, Zsqr);
2119289848Sjkim
2120289848Sjkim	lea	$tmp0(%rsp), $r_ptr
2121289848Sjkim	call	__ecp_nistz256_mul_by_2$x
2122289848Sjkim
2123289848Sjkim	lea	$M(%rsp), $b_ptr
2124289848Sjkim	lea	$M(%rsp), $r_ptr
2125289848Sjkim	call	__ecp_nistz256_add_to$x		# p256_mul_by_3(M, M);
2126289848Sjkim
2127289848Sjkim	`&load_for_mul("$S(%rsp)", "$in_x(%rsp)", "$src0")`
2128289848Sjkim	lea	$S(%rsp), $r_ptr
2129289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S, S, in_x);
2130289848Sjkim
2131289848Sjkim	lea	$tmp0(%rsp), $r_ptr
2132289848Sjkim	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(tmp0, S);
2133289848Sjkim
2134289848Sjkim	`&load_for_sqr("$M(%rsp)", "$src0")`
2135289848Sjkim	movq	%xmm0, $r_ptr
2136289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(res_x, M);
2137289848Sjkim
2138289848Sjkim	lea	$tmp0(%rsp), $b_ptr
2139289848Sjkim	mov	$acc6, $acc0			# harmonize sqr output and sub input
2140289848Sjkim	mov	$acc7, $acc1
2141289848Sjkim	mov	$a_ptr, $poly1
2142289848Sjkim	mov	$t1, $poly3
2143289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, tmp0);
2144289848Sjkim
2145289848Sjkim	mov	$S+8*0(%rsp), $t0
2146289848Sjkim	mov	$S+8*1(%rsp), $t1
2147289848Sjkim	mov	$S+8*2(%rsp), $t2
2148289848Sjkim	mov	$S+8*3(%rsp), $acc2		# "4-5-0-1" order
2149289848Sjkim	lea	$S(%rsp), $r_ptr
2150289848Sjkim	call	__ecp_nistz256_sub$x		# p256_sub(S, S, res_x);
2151289848Sjkim
2152289848Sjkim	mov	$M(%rsp), $src0
2153289848Sjkim	lea	$M(%rsp), $b_ptr
2154289848Sjkim	mov	$acc4, $acc6			# harmonize sub output and mul input
2155289848Sjkim	xor	%ecx, %ecx
2156289848Sjkim	mov	$acc4, $S+8*0(%rsp)		# have to save:-(
2157289848Sjkim	mov	$acc5, $acc2
2158289848Sjkim	mov	$acc5, $S+8*1(%rsp)
2159289848Sjkim	cmovz	$acc0, $acc3
2160289848Sjkim	mov	$acc0, $S+8*2(%rsp)
2161289848Sjkim	lea	$S-$bias(%rsp), $a_ptr
2162289848Sjkim	cmovz	$acc1, $acc4
2163289848Sjkim	mov	$acc1, $S+8*3(%rsp)
2164289848Sjkim	mov	$acc6, $acc1
2165289848Sjkim	lea	$S(%rsp), $r_ptr
2166289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S, S, M);
2167289848Sjkim
2168289848Sjkim	movq	%xmm1, $b_ptr
2169289848Sjkim	movq	%xmm1, $r_ptr
2170289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, S, res_y);
2171289848Sjkim
2172289848Sjkim	add	\$32*5+8, %rsp
2173289848Sjkim	pop	%r15
2174289848Sjkim	pop	%r14
2175289848Sjkim	pop	%r13
2176289848Sjkim	pop	%r12
2177289848Sjkim	pop	%rbx
2178289848Sjkim	pop	%rbp
2179289848Sjkim	ret
2180289848Sjkim.size	ecp_nistz256_point_double$sfx,.-ecp_nistz256_point_double$sfx
2181289848Sjkim___
2182289848Sjkim}
2183289848Sjkim&gen_double("q");
2184289848Sjkim
2185289848Sjkimsub gen_add () {
2186289848Sjkim    my $x = shift;
2187289848Sjkim    my ($src0,$sfx,$bias);
2188289848Sjkim    my ($H,$Hsqr,$R,$Rsqr,$Hcub,
2189289848Sjkim	$U1,$U2,$S1,$S2,
2190289848Sjkim	$res_x,$res_y,$res_z,
2191289848Sjkim	$in1_x,$in1_y,$in1_z,
2192289848Sjkim	$in2_x,$in2_y,$in2_z)=map(32*$_,(0..17));
2193289848Sjkim    my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
2194289848Sjkim
2195289848Sjkim    if ($x ne "x") {
2196289848Sjkim	$src0 = "%rax";
2197289848Sjkim	$sfx  = "";
2198289848Sjkim	$bias = 0;
2199289848Sjkim
2200289848Sjkim$code.=<<___;
2201289848Sjkim.globl	ecp_nistz256_point_add
2202289848Sjkim.type	ecp_nistz256_point_add,\@function,3
2203289848Sjkim.align	32
2204289848Sjkimecp_nistz256_point_add:
2205289848Sjkim___
2206289848Sjkim$code.=<<___	if ($addx);
2207289848Sjkim	mov	\$0x80100, %ecx
2208289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
2209289848Sjkim	cmp	\$0x80100, %ecx
2210289848Sjkim	je	.Lpoint_addx
2211289848Sjkim___
2212289848Sjkim    } else {
2213289848Sjkim	$src0 = "%rdx";
2214289848Sjkim	$sfx  = "x";
2215289848Sjkim	$bias = 128;
2216289848Sjkim
2217289848Sjkim$code.=<<___;
2218289848Sjkim.type	ecp_nistz256_point_addx,\@function,3
2219289848Sjkim.align	32
2220289848Sjkimecp_nistz256_point_addx:
2221289848Sjkim.Lpoint_addx:
2222289848Sjkim___
2223289848Sjkim    }
2224289848Sjkim$code.=<<___;
2225289848Sjkim	push	%rbp
2226289848Sjkim	push	%rbx
2227289848Sjkim	push	%r12
2228289848Sjkim	push	%r13
2229289848Sjkim	push	%r14
2230289848Sjkim	push	%r15
2231289848Sjkim	sub	\$32*18+8, %rsp
2232289848Sjkim
2233289848Sjkim	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$a_ptr
2234289848Sjkim	movdqu	0x10($a_ptr), %xmm1
2235289848Sjkim	movdqu	0x20($a_ptr), %xmm2
2236289848Sjkim	movdqu	0x30($a_ptr), %xmm3
2237289848Sjkim	movdqu	0x40($a_ptr), %xmm4
2238289848Sjkim	movdqu	0x50($a_ptr), %xmm5
2239289848Sjkim	mov	$a_ptr, $b_ptr			# reassign
2240289848Sjkim	mov	$b_org, $a_ptr			# reassign
2241289848Sjkim	movdqa	%xmm0, $in1_x(%rsp)
2242289848Sjkim	movdqa	%xmm1, $in1_x+0x10(%rsp)
2243289848Sjkim	movdqa	%xmm2, $in1_y(%rsp)
2244289848Sjkim	movdqa	%xmm3, $in1_y+0x10(%rsp)
2245289848Sjkim	movdqa	%xmm4, $in1_z(%rsp)
2246289848Sjkim	movdqa	%xmm5, $in1_z+0x10(%rsp)
2247306195Sjkim	por	%xmm4, %xmm5
2248289848Sjkim
2249289848Sjkim	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$b_ptr
2250306195Sjkim	 pshufd	\$0xb1, %xmm5, %xmm3
2251289848Sjkim	movdqu	0x10($a_ptr), %xmm1
2252289848Sjkim	movdqu	0x20($a_ptr), %xmm2
2253289848Sjkim	 por	%xmm3, %xmm5
2254289848Sjkim	movdqu	0x30($a_ptr), %xmm3
2255289848Sjkim	 mov	0x40+8*0($a_ptr), $src0		# load original in2_z
2256289848Sjkim	 mov	0x40+8*1($a_ptr), $acc6
2257289848Sjkim	 mov	0x40+8*2($a_ptr), $acc7
2258289848Sjkim	 mov	0x40+8*3($a_ptr), $acc0
2259289848Sjkim	movdqa	%xmm0, $in2_x(%rsp)
2260289848Sjkim	 pshufd	\$0x1e, %xmm5, %xmm4
2261289848Sjkim	movdqa	%xmm1, $in2_x+0x10(%rsp)
2262306195Sjkim	movdqu	0x40($a_ptr),%xmm0		# in2_z again
2263306195Sjkim	movdqu	0x50($a_ptr),%xmm1
2264289848Sjkim	movdqa	%xmm2, $in2_y(%rsp)
2265289848Sjkim	movdqa	%xmm3, $in2_y+0x10(%rsp)
2266289848Sjkim	 por	%xmm4, %xmm5
2267289848Sjkim	 pxor	%xmm4, %xmm4
2268306195Sjkim	por	%xmm0, %xmm1
2269306195Sjkim	 movq	$r_ptr, %xmm0			# save $r_ptr
2270289848Sjkim
2271289848Sjkim	lea	0x40-$bias($a_ptr), $a_ptr	# $a_ptr is still valid
2272289848Sjkim	 mov	$src0, $in2_z+8*0(%rsp)		# make in2_z copy
2273289848Sjkim	 mov	$acc6, $in2_z+8*1(%rsp)
2274289848Sjkim	 mov	$acc7, $in2_z+8*2(%rsp)
2275289848Sjkim	 mov	$acc0, $in2_z+8*3(%rsp)
2276289848Sjkim	lea	$Z2sqr(%rsp), $r_ptr		# Z2^2
2277289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z2sqr, in2_z);
2278289848Sjkim
2279289848Sjkim	pcmpeqd	%xmm4, %xmm5
2280306195Sjkim	pshufd	\$0xb1, %xmm1, %xmm4
2281306195Sjkim	por	%xmm1, %xmm4
2282289848Sjkim	pshufd	\$0, %xmm5, %xmm5		# in1infty
2283289848Sjkim	pshufd	\$0x1e, %xmm4, %xmm3
2284289848Sjkim	por	%xmm3, %xmm4
2285289848Sjkim	pxor	%xmm3, %xmm3
2286289848Sjkim	pcmpeqd	%xmm3, %xmm4
2287289848Sjkim	pshufd	\$0, %xmm4, %xmm4		# in2infty
2288289848Sjkim	 mov	0x40+8*0($b_ptr), $src0		# load original in1_z
2289289848Sjkim	 mov	0x40+8*1($b_ptr), $acc6
2290289848Sjkim	 mov	0x40+8*2($b_ptr), $acc7
2291289848Sjkim	 mov	0x40+8*3($b_ptr), $acc0
2292296279Sjkim	movq	$b_ptr, %xmm1
2293289848Sjkim
2294289848Sjkim	lea	0x40-$bias($b_ptr), $a_ptr
2295289848Sjkim	lea	$Z1sqr(%rsp), $r_ptr		# Z1^2
2296289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z1sqr, in1_z);
2297289848Sjkim
2298289848Sjkim	`&load_for_mul("$Z2sqr(%rsp)", "$in2_z(%rsp)", "$src0")`
2299289848Sjkim	lea	$S1(%rsp), $r_ptr		# S1 = Z2^3
2300289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S1, Z2sqr, in2_z);
2301289848Sjkim
2302289848Sjkim	`&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2303289848Sjkim	lea	$S2(%rsp), $r_ptr		# S2 = Z1^3
2304289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Z1sqr, in1_z);
2305289848Sjkim
2306289848Sjkim	`&load_for_mul("$S1(%rsp)", "$in1_y(%rsp)", "$src0")`
2307289848Sjkim	lea	$S1(%rsp), $r_ptr		# S1 = Y1*Z2^3
2308289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S1, S1, in1_y);
2309289848Sjkim
2310289848Sjkim	`&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2311289848Sjkim	lea	$S2(%rsp), $r_ptr		# S2 = Y2*Z1^3
2312289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S2, in2_y);
2313289848Sjkim
2314289848Sjkim	lea	$S1(%rsp), $b_ptr
2315289848Sjkim	lea	$R(%rsp), $r_ptr		# R = S2 - S1
2316289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(R, S2, S1);
2317289848Sjkim
2318289848Sjkim	or	$acc5, $acc4			# see if result is zero
2319289848Sjkim	movdqa	%xmm4, %xmm2
2320289848Sjkim	or	$acc0, $acc4
2321289848Sjkim	or	$acc1, $acc4
2322289848Sjkim	por	%xmm5, %xmm2			# in1infty || in2infty
2323289848Sjkim	movq	$acc4, %xmm3
2324289848Sjkim
2325289848Sjkim	`&load_for_mul("$Z2sqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2326289848Sjkim	lea	$U1(%rsp), $r_ptr		# U1 = X1*Z2^2
2327289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U1, in1_x, Z2sqr);
2328289848Sjkim
2329289848Sjkim	`&load_for_mul("$Z1sqr(%rsp)", "$in2_x(%rsp)", "$src0")`
2330289848Sjkim	lea	$U2(%rsp), $r_ptr		# U2 = X2*Z1^2
2331289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, in2_x, Z1sqr);
2332289848Sjkim
2333289848Sjkim	lea	$U1(%rsp), $b_ptr
2334289848Sjkim	lea	$H(%rsp), $r_ptr		# H = U2 - U1
2335289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(H, U2, U1);
2336289848Sjkim
2337289848Sjkim	or	$acc5, $acc4			# see if result is zero
2338289848Sjkim	or	$acc0, $acc4
2339289848Sjkim	or	$acc1, $acc4
2340289848Sjkim
2341289848Sjkim	.byte	0x3e				# predict taken
2342289848Sjkim	jnz	.Ladd_proceed$x			# is_equal(U1,U2)?
2343289848Sjkim	movq	%xmm2, $acc0
2344289848Sjkim	movq	%xmm3, $acc1
2345289848Sjkim	test	$acc0, $acc0
2346289848Sjkim	jnz	.Ladd_proceed$x			# (in1infty || in2infty)?
2347289848Sjkim	test	$acc1, $acc1
2348296279Sjkim	jz	.Ladd_double$x			# is_equal(S1,S2)?
2349289848Sjkim
2350289848Sjkim	movq	%xmm0, $r_ptr			# restore $r_ptr
2351289848Sjkim	pxor	%xmm0, %xmm0
2352289848Sjkim	movdqu	%xmm0, 0x00($r_ptr)
2353289848Sjkim	movdqu	%xmm0, 0x10($r_ptr)
2354289848Sjkim	movdqu	%xmm0, 0x20($r_ptr)
2355289848Sjkim	movdqu	%xmm0, 0x30($r_ptr)
2356289848Sjkim	movdqu	%xmm0, 0x40($r_ptr)
2357289848Sjkim	movdqu	%xmm0, 0x50($r_ptr)
2358289848Sjkim	jmp	.Ladd_done$x
2359289848Sjkim
2360289848Sjkim.align	32
2361296279Sjkim.Ladd_double$x:
2362296279Sjkim	movq	%xmm1, $a_ptr			# restore $a_ptr
2363296279Sjkim	movq	%xmm0, $r_ptr			# restore $r_ptr
2364296279Sjkim	add	\$`32*(18-5)`, %rsp		# difference in frame sizes
2365296279Sjkim	jmp	.Lpoint_double_shortcut$x
2366296279Sjkim
2367296279Sjkim.align	32
2368289848Sjkim.Ladd_proceed$x:
2369289848Sjkim	`&load_for_sqr("$R(%rsp)", "$src0")`
2370289848Sjkim	lea	$Rsqr(%rsp), $r_ptr		# R^2
2371289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Rsqr, R);
2372289848Sjkim
2373289848Sjkim	`&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2374289848Sjkim	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
2375289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, H, in1_z);
2376289848Sjkim
2377289848Sjkim	`&load_for_sqr("$H(%rsp)", "$src0")`
2378289848Sjkim	lea	$Hsqr(%rsp), $r_ptr		# H^2
2379289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Hsqr, H);
2380289848Sjkim
2381289848Sjkim	`&load_for_mul("$res_z(%rsp)", "$in2_z(%rsp)", "$src0")`
2382289848Sjkim	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
2383289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, res_z, in2_z);
2384289848Sjkim
2385289848Sjkim	`&load_for_mul("$Hsqr(%rsp)", "$H(%rsp)", "$src0")`
2386289848Sjkim	lea	$Hcub(%rsp), $r_ptr		# H^3
2387289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(Hcub, Hsqr, H);
2388289848Sjkim
2389289848Sjkim	`&load_for_mul("$Hsqr(%rsp)", "$U1(%rsp)", "$src0")`
2390289848Sjkim	lea	$U2(%rsp), $r_ptr		# U1*H^2
2391289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, U1, Hsqr);
2392289848Sjkim___
2393289848Sjkim{
2394289848Sjkim#######################################################################
2395289848Sjkim# operate in 4-5-0-1 "name space" that matches multiplication output
2396289848Sjkim#
2397289848Sjkimmy ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2398289848Sjkimmy ($poly1, $poly3)=($acc6,$acc7);
2399289848Sjkim
2400289848Sjkim$code.=<<___;
2401289848Sjkim	#lea	$U2(%rsp), $a_ptr
2402289848Sjkim	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
2403289848Sjkim	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
2404289848Sjkim
2405306195Sjkim	xor	$t4, $t4
2406289848Sjkim	add	$acc0, $acc0		# a0:a3+a0:a3
2407289848Sjkim	lea	$Rsqr(%rsp), $a_ptr
2408289848Sjkim	adc	$acc1, $acc1
2409289848Sjkim	 mov	$acc0, $t0
2410289848Sjkim	adc	$acc2, $acc2
2411289848Sjkim	adc	$acc3, $acc3
2412289848Sjkim	 mov	$acc1, $t1
2413306195Sjkim	adc	\$0, $t4
2414289848Sjkim
2415289848Sjkim	sub	\$-1, $acc0
2416289848Sjkim	 mov	$acc2, $t2
2417289848Sjkim	sbb	$poly1, $acc1
2418289848Sjkim	sbb	\$0, $acc2
2419289848Sjkim	 mov	$acc3, $t3
2420289848Sjkim	sbb	$poly3, $acc3
2421306195Sjkim	sbb	\$0, $t4
2422289848Sjkim
2423306195Sjkim	cmovc	$t0, $acc0
2424289848Sjkim	mov	8*0($a_ptr), $t0
2425306195Sjkim	cmovc	$t1, $acc1
2426289848Sjkim	mov	8*1($a_ptr), $t1
2427306195Sjkim	cmovc	$t2, $acc2
2428289848Sjkim	mov	8*2($a_ptr), $t2
2429306195Sjkim	cmovc	$t3, $acc3
2430289848Sjkim	mov	8*3($a_ptr), $t3
2431289848Sjkim
2432289848Sjkim	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
2433289848Sjkim
2434289848Sjkim	lea	$Hcub(%rsp), $b_ptr
2435289848Sjkim	lea	$res_x(%rsp), $r_ptr
2436289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, Hcub);
2437289848Sjkim
2438289848Sjkim	mov	$U2+8*0(%rsp), $t0
2439289848Sjkim	mov	$U2+8*1(%rsp), $t1
2440289848Sjkim	mov	$U2+8*2(%rsp), $t2
2441289848Sjkim	mov	$U2+8*3(%rsp), $t3
2442289848Sjkim	lea	$res_y(%rsp), $r_ptr
2443289848Sjkim
2444289848Sjkim	call	__ecp_nistz256_sub$x		# p256_sub(res_y, U2, res_x);
2445289848Sjkim
2446289848Sjkim	mov	$acc0, 8*0($r_ptr)		# save the result, as
2447289848Sjkim	mov	$acc1, 8*1($r_ptr)		# __ecp_nistz256_sub doesn't
2448289848Sjkim	mov	$acc2, 8*2($r_ptr)
2449289848Sjkim	mov	$acc3, 8*3($r_ptr)
2450289848Sjkim___
2451289848Sjkim}
2452289848Sjkim$code.=<<___;
2453289848Sjkim	`&load_for_mul("$S1(%rsp)", "$Hcub(%rsp)", "$src0")`
2454289848Sjkim	lea	$S2(%rsp), $r_ptr
2455289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S1, Hcub);
2456289848Sjkim
2457289848Sjkim	`&load_for_mul("$R(%rsp)", "$res_y(%rsp)", "$src0")`
2458289848Sjkim	lea	$res_y(%rsp), $r_ptr
2459289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_y, R, res_y);
2460289848Sjkim
2461289848Sjkim	lea	$S2(%rsp), $b_ptr
2462289848Sjkim	lea	$res_y(%rsp), $r_ptr
2463289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, res_y, S2);
2464289848Sjkim
2465289848Sjkim	movq	%xmm0, $r_ptr		# restore $r_ptr
2466289848Sjkim
2467289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_z, in2_z, in1infty);
2468289848Sjkim	movdqa	%xmm5, %xmm1
2469289848Sjkim	pandn	$res_z(%rsp), %xmm0
2470289848Sjkim	movdqa	%xmm5, %xmm2
2471289848Sjkim	pandn	$res_z+0x10(%rsp), %xmm1
2472289848Sjkim	movdqa	%xmm5, %xmm3
2473289848Sjkim	pand	$in2_z(%rsp), %xmm2
2474289848Sjkim	pand	$in2_z+0x10(%rsp), %xmm3
2475289848Sjkim	por	%xmm0, %xmm2
2476289848Sjkim	por	%xmm1, %xmm3
2477289848Sjkim
2478289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_z, in1_z, in2infty);
2479289848Sjkim	movdqa	%xmm4, %xmm1
2480289848Sjkim	pandn	%xmm2, %xmm0
2481289848Sjkim	movdqa	%xmm4, %xmm2
2482289848Sjkim	pandn	%xmm3, %xmm1
2483289848Sjkim	movdqa	%xmm4, %xmm3
2484289848Sjkim	pand	$in1_z(%rsp), %xmm2
2485289848Sjkim	pand	$in1_z+0x10(%rsp), %xmm3
2486289848Sjkim	por	%xmm0, %xmm2
2487289848Sjkim	por	%xmm1, %xmm3
2488289848Sjkim	movdqu	%xmm2, 0x40($r_ptr)
2489289848Sjkim	movdqu	%xmm3, 0x50($r_ptr)
2490289848Sjkim
2491289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_x, in2_x, in1infty);
2492289848Sjkim	movdqa	%xmm5, %xmm1
2493289848Sjkim	pandn	$res_x(%rsp), %xmm0
2494289848Sjkim	movdqa	%xmm5, %xmm2
2495289848Sjkim	pandn	$res_x+0x10(%rsp), %xmm1
2496289848Sjkim	movdqa	%xmm5, %xmm3
2497289848Sjkim	pand	$in2_x(%rsp), %xmm2
2498289848Sjkim	pand	$in2_x+0x10(%rsp), %xmm3
2499289848Sjkim	por	%xmm0, %xmm2
2500289848Sjkim	por	%xmm1, %xmm3
2501289848Sjkim
2502289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_x, in1_x, in2infty);
2503289848Sjkim	movdqa	%xmm4, %xmm1
2504289848Sjkim	pandn	%xmm2, %xmm0
2505289848Sjkim	movdqa	%xmm4, %xmm2
2506289848Sjkim	pandn	%xmm3, %xmm1
2507289848Sjkim	movdqa	%xmm4, %xmm3
2508289848Sjkim	pand	$in1_x(%rsp), %xmm2
2509289848Sjkim	pand	$in1_x+0x10(%rsp), %xmm3
2510289848Sjkim	por	%xmm0, %xmm2
2511289848Sjkim	por	%xmm1, %xmm3
2512289848Sjkim	movdqu	%xmm2, 0x00($r_ptr)
2513289848Sjkim	movdqu	%xmm3, 0x10($r_ptr)
2514289848Sjkim
2515289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_y, in2_y, in1infty);
2516289848Sjkim	movdqa	%xmm5, %xmm1
2517289848Sjkim	pandn	$res_y(%rsp), %xmm0
2518289848Sjkim	movdqa	%xmm5, %xmm2
2519289848Sjkim	pandn	$res_y+0x10(%rsp), %xmm1
2520289848Sjkim	movdqa	%xmm5, %xmm3
2521289848Sjkim	pand	$in2_y(%rsp), %xmm2
2522289848Sjkim	pand	$in2_y+0x10(%rsp), %xmm3
2523289848Sjkim	por	%xmm0, %xmm2
2524289848Sjkim	por	%xmm1, %xmm3
2525289848Sjkim
2526289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_y, in1_y, in2infty);
2527289848Sjkim	movdqa	%xmm4, %xmm1
2528289848Sjkim	pandn	%xmm2, %xmm0
2529289848Sjkim	movdqa	%xmm4, %xmm2
2530289848Sjkim	pandn	%xmm3, %xmm1
2531289848Sjkim	movdqa	%xmm4, %xmm3
2532289848Sjkim	pand	$in1_y(%rsp), %xmm2
2533289848Sjkim	pand	$in1_y+0x10(%rsp), %xmm3
2534289848Sjkim	por	%xmm0, %xmm2
2535289848Sjkim	por	%xmm1, %xmm3
2536289848Sjkim	movdqu	%xmm2, 0x20($r_ptr)
2537289848Sjkim	movdqu	%xmm3, 0x30($r_ptr)
2538289848Sjkim
2539289848Sjkim.Ladd_done$x:
2540289848Sjkim	add	\$32*18+8, %rsp
2541289848Sjkim	pop	%r15
2542289848Sjkim	pop	%r14
2543289848Sjkim	pop	%r13
2544289848Sjkim	pop	%r12
2545289848Sjkim	pop	%rbx
2546289848Sjkim	pop	%rbp
2547289848Sjkim	ret
2548289848Sjkim.size	ecp_nistz256_point_add$sfx,.-ecp_nistz256_point_add$sfx
2549289848Sjkim___
2550289848Sjkim}
2551289848Sjkim&gen_add("q");
2552289848Sjkim
2553289848Sjkimsub gen_add_affine () {
2554289848Sjkim    my $x = shift;
2555289848Sjkim    my ($src0,$sfx,$bias);
2556289848Sjkim    my ($U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr,
2557289848Sjkim	$res_x,$res_y,$res_z,
2558289848Sjkim	$in1_x,$in1_y,$in1_z,
2559289848Sjkim	$in2_x,$in2_y)=map(32*$_,(0..14));
2560289848Sjkim    my $Z1sqr = $S2;
2561289848Sjkim
2562289848Sjkim    if ($x ne "x") {
2563289848Sjkim	$src0 = "%rax";
2564289848Sjkim	$sfx  = "";
2565289848Sjkim	$bias = 0;
2566289848Sjkim
2567289848Sjkim$code.=<<___;
2568289848Sjkim.globl	ecp_nistz256_point_add_affine
2569289848Sjkim.type	ecp_nistz256_point_add_affine,\@function,3
2570289848Sjkim.align	32
2571289848Sjkimecp_nistz256_point_add_affine:
2572289848Sjkim___
2573289848Sjkim$code.=<<___	if ($addx);
2574289848Sjkim	mov	\$0x80100, %ecx
2575289848Sjkim	and	OPENSSL_ia32cap_P+8(%rip), %ecx
2576289848Sjkim	cmp	\$0x80100, %ecx
2577289848Sjkim	je	.Lpoint_add_affinex
2578289848Sjkim___
2579289848Sjkim    } else {
2580289848Sjkim	$src0 = "%rdx";
2581289848Sjkim	$sfx  = "x";
2582289848Sjkim	$bias = 128;
2583289848Sjkim
2584289848Sjkim$code.=<<___;
2585289848Sjkim.type	ecp_nistz256_point_add_affinex,\@function,3
2586289848Sjkim.align	32
2587289848Sjkimecp_nistz256_point_add_affinex:
2588289848Sjkim.Lpoint_add_affinex:
2589289848Sjkim___
2590289848Sjkim    }
2591289848Sjkim$code.=<<___;
2592289848Sjkim	push	%rbp
2593289848Sjkim	push	%rbx
2594289848Sjkim	push	%r12
2595289848Sjkim	push	%r13
2596289848Sjkim	push	%r14
2597289848Sjkim	push	%r15
2598289848Sjkim	sub	\$32*15+8, %rsp
2599289848Sjkim
2600289848Sjkim	movdqu	0x00($a_ptr), %xmm0	# copy	*(P256_POINT *)$a_ptr
2601289848Sjkim	mov	$b_org, $b_ptr		# reassign
2602289848Sjkim	movdqu	0x10($a_ptr), %xmm1
2603289848Sjkim	movdqu	0x20($a_ptr), %xmm2
2604289848Sjkim	movdqu	0x30($a_ptr), %xmm3
2605289848Sjkim	movdqu	0x40($a_ptr), %xmm4
2606289848Sjkim	movdqu	0x50($a_ptr), %xmm5
2607289848Sjkim	 mov	0x40+8*0($a_ptr), $src0	# load original in1_z
2608289848Sjkim	 mov	0x40+8*1($a_ptr), $acc6
2609289848Sjkim	 mov	0x40+8*2($a_ptr), $acc7
2610289848Sjkim	 mov	0x40+8*3($a_ptr), $acc0
2611289848Sjkim	movdqa	%xmm0, $in1_x(%rsp)
2612289848Sjkim	movdqa	%xmm1, $in1_x+0x10(%rsp)
2613289848Sjkim	movdqa	%xmm2, $in1_y(%rsp)
2614289848Sjkim	movdqa	%xmm3, $in1_y+0x10(%rsp)
2615289848Sjkim	movdqa	%xmm4, $in1_z(%rsp)
2616289848Sjkim	movdqa	%xmm5, $in1_z+0x10(%rsp)
2617306195Sjkim	por	%xmm4, %xmm5
2618289848Sjkim
2619289848Sjkim	movdqu	0x00($b_ptr), %xmm0	# copy	*(P256_POINT_AFFINE *)$b_ptr
2620306195Sjkim	 pshufd	\$0xb1, %xmm5, %xmm3
2621289848Sjkim	movdqu	0x10($b_ptr), %xmm1
2622289848Sjkim	movdqu	0x20($b_ptr), %xmm2
2623289848Sjkim	 por	%xmm3, %xmm5
2624289848Sjkim	movdqu	0x30($b_ptr), %xmm3
2625289848Sjkim	movdqa	%xmm0, $in2_x(%rsp)
2626289848Sjkim	 pshufd	\$0x1e, %xmm5, %xmm4
2627289848Sjkim	movdqa	%xmm1, $in2_x+0x10(%rsp)
2628289848Sjkim	por	%xmm0, %xmm1
2629289848Sjkim	 movq	$r_ptr, %xmm0		# save $r_ptr
2630289848Sjkim	movdqa	%xmm2, $in2_y(%rsp)
2631289848Sjkim	movdqa	%xmm3, $in2_y+0x10(%rsp)
2632289848Sjkim	por	%xmm2, %xmm3
2633289848Sjkim	 por	%xmm4, %xmm5
2634289848Sjkim	 pxor	%xmm4, %xmm4
2635289848Sjkim	por	%xmm1, %xmm3
2636289848Sjkim
2637289848Sjkim	lea	0x40-$bias($a_ptr), $a_ptr	# $a_ptr is still valid
2638289848Sjkim	lea	$Z1sqr(%rsp), $r_ptr		# Z1^2
2639289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z1sqr, in1_z);
2640289848Sjkim
2641289848Sjkim	pcmpeqd	%xmm4, %xmm5
2642289848Sjkim	pshufd	\$0xb1, %xmm3, %xmm4
2643289848Sjkim	 mov	0x00($b_ptr), $src0		# $b_ptr is still valid
2644289848Sjkim	 #lea	0x00($b_ptr), $b_ptr
2645289848Sjkim	 mov	$acc4, $acc1			# harmonize sqr output and mul input
2646289848Sjkim	por	%xmm3, %xmm4
2647289848Sjkim	pshufd	\$0, %xmm5, %xmm5		# in1infty
2648289848Sjkim	pshufd	\$0x1e, %xmm4, %xmm3
2649289848Sjkim	 mov	$acc5, $acc2
2650289848Sjkim	por	%xmm3, %xmm4
2651289848Sjkim	pxor	%xmm3, %xmm3
2652289848Sjkim	 mov	$acc6, $acc3
2653289848Sjkim	pcmpeqd	%xmm3, %xmm4
2654289848Sjkim	pshufd	\$0, %xmm4, %xmm4		# in2infty
2655289848Sjkim
2656289848Sjkim	lea	$Z1sqr-$bias(%rsp), $a_ptr
2657289848Sjkim	mov	$acc7, $acc4
2658289848Sjkim	lea	$U2(%rsp), $r_ptr		# U2 = X2*Z1^2
2659289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, Z1sqr, in2_x);
2660289848Sjkim
2661289848Sjkim	lea	$in1_x(%rsp), $b_ptr
2662289848Sjkim	lea	$H(%rsp), $r_ptr		# H = U2 - U1
2663289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(H, U2, in1_x);
2664289848Sjkim
2665289848Sjkim	`&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2666289848Sjkim	lea	$S2(%rsp), $r_ptr		# S2 = Z1^3
2667289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Z1sqr, in1_z);
2668289848Sjkim
2669289848Sjkim	`&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2670289848Sjkim	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
2671289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, H, in1_z);
2672289848Sjkim
2673289848Sjkim	`&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2674289848Sjkim	lea	$S2(%rsp), $r_ptr		# S2 = Y2*Z1^3
2675289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S2, in2_y);
2676289848Sjkim
2677289848Sjkim	lea	$in1_y(%rsp), $b_ptr
2678289848Sjkim	lea	$R(%rsp), $r_ptr		# R = S2 - S1
2679289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(R, S2, in1_y);
2680289848Sjkim
2681289848Sjkim	`&load_for_sqr("$H(%rsp)", "$src0")`
2682289848Sjkim	lea	$Hsqr(%rsp), $r_ptr		# H^2
2683289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Hsqr, H);
2684289848Sjkim
2685289848Sjkim	`&load_for_sqr("$R(%rsp)", "$src0")`
2686289848Sjkim	lea	$Rsqr(%rsp), $r_ptr		# R^2
2687289848Sjkim	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Rsqr, R);
2688289848Sjkim
2689289848Sjkim	`&load_for_mul("$H(%rsp)", "$Hsqr(%rsp)", "$src0")`
2690289848Sjkim	lea	$Hcub(%rsp), $r_ptr		# H^3
2691289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(Hcub, Hsqr, H);
2692289848Sjkim
2693289848Sjkim	`&load_for_mul("$Hsqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2694289848Sjkim	lea	$U2(%rsp), $r_ptr		# U1*H^2
2695289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, in1_x, Hsqr);
2696289848Sjkim___
2697289848Sjkim{
2698289848Sjkim#######################################################################
2699289848Sjkim# operate in 4-5-0-1 "name space" that matches multiplication output
2700289848Sjkim#
2701289848Sjkimmy ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2702289848Sjkimmy ($poly1, $poly3)=($acc6,$acc7);
2703289848Sjkim
2704289848Sjkim$code.=<<___;
2705289848Sjkim	#lea	$U2(%rsp), $a_ptr
2706289848Sjkim	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
2707289848Sjkim	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
2708289848Sjkim
2709306195Sjkim	xor	$t4, $t4
2710289848Sjkim	add	$acc0, $acc0		# a0:a3+a0:a3
2711289848Sjkim	lea	$Rsqr(%rsp), $a_ptr
2712289848Sjkim	adc	$acc1, $acc1
2713289848Sjkim	 mov	$acc0, $t0
2714289848Sjkim	adc	$acc2, $acc2
2715289848Sjkim	adc	$acc3, $acc3
2716289848Sjkim	 mov	$acc1, $t1
2717306195Sjkim	adc	\$0, $t4
2718289848Sjkim
2719289848Sjkim	sub	\$-1, $acc0
2720289848Sjkim	 mov	$acc2, $t2
2721289848Sjkim	sbb	$poly1, $acc1
2722289848Sjkim	sbb	\$0, $acc2
2723289848Sjkim	 mov	$acc3, $t3
2724289848Sjkim	sbb	$poly3, $acc3
2725306195Sjkim	sbb	\$0, $t4
2726289848Sjkim
2727306195Sjkim	cmovc	$t0, $acc0
2728289848Sjkim	mov	8*0($a_ptr), $t0
2729306195Sjkim	cmovc	$t1, $acc1
2730289848Sjkim	mov	8*1($a_ptr), $t1
2731306195Sjkim	cmovc	$t2, $acc2
2732289848Sjkim	mov	8*2($a_ptr), $t2
2733306195Sjkim	cmovc	$t3, $acc3
2734289848Sjkim	mov	8*3($a_ptr), $t3
2735289848Sjkim
2736289848Sjkim	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
2737289848Sjkim
2738289848Sjkim	lea	$Hcub(%rsp), $b_ptr
2739289848Sjkim	lea	$res_x(%rsp), $r_ptr
2740289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, Hcub);
2741289848Sjkim
2742289848Sjkim	mov	$U2+8*0(%rsp), $t0
2743289848Sjkim	mov	$U2+8*1(%rsp), $t1
2744289848Sjkim	mov	$U2+8*2(%rsp), $t2
2745289848Sjkim	mov	$U2+8*3(%rsp), $t3
2746289848Sjkim	lea	$H(%rsp), $r_ptr
2747289848Sjkim
2748289848Sjkim	call	__ecp_nistz256_sub$x		# p256_sub(H, U2, res_x);
2749289848Sjkim
2750289848Sjkim	mov	$acc0, 8*0($r_ptr)		# save the result, as
2751289848Sjkim	mov	$acc1, 8*1($r_ptr)		# __ecp_nistz256_sub doesn't
2752289848Sjkim	mov	$acc2, 8*2($r_ptr)
2753289848Sjkim	mov	$acc3, 8*3($r_ptr)
2754289848Sjkim___
2755289848Sjkim}
2756289848Sjkim$code.=<<___;
2757289848Sjkim	`&load_for_mul("$Hcub(%rsp)", "$in1_y(%rsp)", "$src0")`
2758289848Sjkim	lea	$S2(%rsp), $r_ptr
2759289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Hcub, in1_y);
2760289848Sjkim
2761289848Sjkim	`&load_for_mul("$H(%rsp)", "$R(%rsp)", "$src0")`
2762289848Sjkim	lea	$H(%rsp), $r_ptr
2763289848Sjkim	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(H, H, R);
2764289848Sjkim
2765289848Sjkim	lea	$S2(%rsp), $b_ptr
2766289848Sjkim	lea	$res_y(%rsp), $r_ptr
2767289848Sjkim	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, H, S2);
2768289848Sjkim
2769289848Sjkim	movq	%xmm0, $r_ptr		# restore $r_ptr
2770289848Sjkim
2771289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_z, ONE, in1infty);
2772289848Sjkim	movdqa	%xmm5, %xmm1
2773289848Sjkim	pandn	$res_z(%rsp), %xmm0
2774289848Sjkim	movdqa	%xmm5, %xmm2
2775289848Sjkim	pandn	$res_z+0x10(%rsp), %xmm1
2776289848Sjkim	movdqa	%xmm5, %xmm3
2777289848Sjkim	pand	.LONE_mont(%rip), %xmm2
2778289848Sjkim	pand	.LONE_mont+0x10(%rip), %xmm3
2779289848Sjkim	por	%xmm0, %xmm2
2780289848Sjkim	por	%xmm1, %xmm3
2781289848Sjkim
2782289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_z, in1_z, in2infty);
2783289848Sjkim	movdqa	%xmm4, %xmm1
2784289848Sjkim	pandn	%xmm2, %xmm0
2785289848Sjkim	movdqa	%xmm4, %xmm2
2786289848Sjkim	pandn	%xmm3, %xmm1
2787289848Sjkim	movdqa	%xmm4, %xmm3
2788289848Sjkim	pand	$in1_z(%rsp), %xmm2
2789289848Sjkim	pand	$in1_z+0x10(%rsp), %xmm3
2790289848Sjkim	por	%xmm0, %xmm2
2791289848Sjkim	por	%xmm1, %xmm3
2792289848Sjkim	movdqu	%xmm2, 0x40($r_ptr)
2793289848Sjkim	movdqu	%xmm3, 0x50($r_ptr)
2794289848Sjkim
2795289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_x, in2_x, in1infty);
2796289848Sjkim	movdqa	%xmm5, %xmm1
2797289848Sjkim	pandn	$res_x(%rsp), %xmm0
2798289848Sjkim	movdqa	%xmm5, %xmm2
2799289848Sjkim	pandn	$res_x+0x10(%rsp), %xmm1
2800289848Sjkim	movdqa	%xmm5, %xmm3
2801289848Sjkim	pand	$in2_x(%rsp), %xmm2
2802289848Sjkim	pand	$in2_x+0x10(%rsp), %xmm3
2803289848Sjkim	por	%xmm0, %xmm2
2804289848Sjkim	por	%xmm1, %xmm3
2805289848Sjkim
2806289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_x, in1_x, in2infty);
2807289848Sjkim	movdqa	%xmm4, %xmm1
2808289848Sjkim	pandn	%xmm2, %xmm0
2809289848Sjkim	movdqa	%xmm4, %xmm2
2810289848Sjkim	pandn	%xmm3, %xmm1
2811289848Sjkim	movdqa	%xmm4, %xmm3
2812289848Sjkim	pand	$in1_x(%rsp), %xmm2
2813289848Sjkim	pand	$in1_x+0x10(%rsp), %xmm3
2814289848Sjkim	por	%xmm0, %xmm2
2815289848Sjkim	por	%xmm1, %xmm3
2816289848Sjkim	movdqu	%xmm2, 0x00($r_ptr)
2817289848Sjkim	movdqu	%xmm3, 0x10($r_ptr)
2818289848Sjkim
2819289848Sjkim	movdqa	%xmm5, %xmm0		# copy_conditional(res_y, in2_y, in1infty);
2820289848Sjkim	movdqa	%xmm5, %xmm1
2821289848Sjkim	pandn	$res_y(%rsp), %xmm0
2822289848Sjkim	movdqa	%xmm5, %xmm2
2823289848Sjkim	pandn	$res_y+0x10(%rsp), %xmm1
2824289848Sjkim	movdqa	%xmm5, %xmm3
2825289848Sjkim	pand	$in2_y(%rsp), %xmm2
2826289848Sjkim	pand	$in2_y+0x10(%rsp), %xmm3
2827289848Sjkim	por	%xmm0, %xmm2
2828289848Sjkim	por	%xmm1, %xmm3
2829289848Sjkim
2830289848Sjkim	movdqa	%xmm4, %xmm0		# copy_conditional(res_y, in1_y, in2infty);
2831289848Sjkim	movdqa	%xmm4, %xmm1
2832289848Sjkim	pandn	%xmm2, %xmm0
2833289848Sjkim	movdqa	%xmm4, %xmm2
2834289848Sjkim	pandn	%xmm3, %xmm1
2835289848Sjkim	movdqa	%xmm4, %xmm3
2836289848Sjkim	pand	$in1_y(%rsp), %xmm2
2837289848Sjkim	pand	$in1_y+0x10(%rsp), %xmm3
2838289848Sjkim	por	%xmm0, %xmm2
2839289848Sjkim	por	%xmm1, %xmm3
2840289848Sjkim	movdqu	%xmm2, 0x20($r_ptr)
2841289848Sjkim	movdqu	%xmm3, 0x30($r_ptr)
2842289848Sjkim
2843289848Sjkim	add	\$32*15+8, %rsp
2844289848Sjkim	pop	%r15
2845289848Sjkim	pop	%r14
2846289848Sjkim	pop	%r13
2847289848Sjkim	pop	%r12
2848289848Sjkim	pop	%rbx
2849289848Sjkim	pop	%rbp
2850289848Sjkim	ret
2851289848Sjkim.size	ecp_nistz256_point_add_affine$sfx,.-ecp_nistz256_point_add_affine$sfx
2852289848Sjkim___
2853289848Sjkim}
2854289848Sjkim&gen_add_affine("q");
2855289848Sjkim
2856289848Sjkim########################################################################
2857289848Sjkim# AD*X magic
2858289848Sjkim#
2859289848Sjkimif ($addx) {								{
2860289848Sjkim########################################################################
2861289848Sjkim# operate in 4-5-0-1 "name space" that matches multiplication output
2862289848Sjkim#
2863289848Sjkimmy ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2864289848Sjkim
2865289848Sjkim$code.=<<___;
2866289848Sjkim.type	__ecp_nistz256_add_tox,\@abi-omnipotent
2867289848Sjkim.align	32
2868289848Sjkim__ecp_nistz256_add_tox:
2869289848Sjkim	xor	$t4, $t4
2870289848Sjkim	adc	8*0($b_ptr), $a0
2871289848Sjkim	adc	8*1($b_ptr), $a1
2872289848Sjkim	 mov	$a0, $t0
2873289848Sjkim	adc	8*2($b_ptr), $a2
2874289848Sjkim	adc	8*3($b_ptr), $a3
2875289848Sjkim	 mov	$a1, $t1
2876289848Sjkim	adc	\$0, $t4
2877289848Sjkim
2878289848Sjkim	xor	$t3, $t3
2879289848Sjkim	sbb	\$-1, $a0
2880289848Sjkim	 mov	$a2, $t2
2881289848Sjkim	sbb	$poly1, $a1
2882289848Sjkim	sbb	\$0, $a2
2883289848Sjkim	 mov	$a3, $t3
2884289848Sjkim	sbb	$poly3, $a3
2885306195Sjkim	sbb	\$0, $t4
2886289848Sjkim
2887306195Sjkim	cmovc	$t0, $a0
2888306195Sjkim	cmovc	$t1, $a1
2889289848Sjkim	mov	$a0, 8*0($r_ptr)
2890306195Sjkim	cmovc	$t2, $a2
2891289848Sjkim	mov	$a1, 8*1($r_ptr)
2892306195Sjkim	cmovc	$t3, $a3
2893289848Sjkim	mov	$a2, 8*2($r_ptr)
2894289848Sjkim	mov	$a3, 8*3($r_ptr)
2895289848Sjkim
2896289848Sjkim	ret
2897289848Sjkim.size	__ecp_nistz256_add_tox,.-__ecp_nistz256_add_tox
2898289848Sjkim
2899289848Sjkim.type	__ecp_nistz256_sub_fromx,\@abi-omnipotent
2900289848Sjkim.align	32
2901289848Sjkim__ecp_nistz256_sub_fromx:
2902289848Sjkim	xor	$t4, $t4
2903289848Sjkim	sbb	8*0($b_ptr), $a0
2904289848Sjkim	sbb	8*1($b_ptr), $a1
2905289848Sjkim	 mov	$a0, $t0
2906289848Sjkim	sbb	8*2($b_ptr), $a2
2907289848Sjkim	sbb	8*3($b_ptr), $a3
2908289848Sjkim	 mov	$a1, $t1
2909289848Sjkim	sbb	\$0, $t4
2910289848Sjkim
2911289848Sjkim	xor	$t3, $t3
2912289848Sjkim	adc	\$-1, $a0
2913289848Sjkim	 mov	$a2, $t2
2914289848Sjkim	adc	$poly1, $a1
2915289848Sjkim	adc	\$0, $a2
2916289848Sjkim	 mov	$a3, $t3
2917289848Sjkim	adc	$poly3, $a3
2918289848Sjkim
2919289848Sjkim	bt	\$0, $t4
2920289848Sjkim	cmovnc	$t0, $a0
2921289848Sjkim	cmovnc	$t1, $a1
2922289848Sjkim	mov	$a0, 8*0($r_ptr)
2923289848Sjkim	cmovnc	$t2, $a2
2924289848Sjkim	mov	$a1, 8*1($r_ptr)
2925289848Sjkim	cmovnc	$t3, $a3
2926289848Sjkim	mov	$a2, 8*2($r_ptr)
2927289848Sjkim	mov	$a3, 8*3($r_ptr)
2928289848Sjkim
2929289848Sjkim	ret
2930289848Sjkim.size	__ecp_nistz256_sub_fromx,.-__ecp_nistz256_sub_fromx
2931289848Sjkim
2932289848Sjkim.type	__ecp_nistz256_subx,\@abi-omnipotent
2933289848Sjkim.align	32
2934289848Sjkim__ecp_nistz256_subx:
2935289848Sjkim	xor	$t4, $t4
2936289848Sjkim	sbb	$a0, $t0
2937289848Sjkim	sbb	$a1, $t1
2938289848Sjkim	 mov	$t0, $a0
2939289848Sjkim	sbb	$a2, $t2
2940289848Sjkim	sbb	$a3, $t3
2941289848Sjkim	 mov	$t1, $a1
2942289848Sjkim	sbb	\$0, $t4
2943289848Sjkim
2944289848Sjkim	xor	$a3 ,$a3
2945289848Sjkim	adc	\$-1, $t0
2946289848Sjkim	 mov	$t2, $a2
2947289848Sjkim	adc	$poly1, $t1
2948289848Sjkim	adc	\$0, $t2
2949289848Sjkim	 mov	$t3, $a3
2950289848Sjkim	adc	$poly3, $t3
2951289848Sjkim
2952289848Sjkim	bt	\$0, $t4
2953289848Sjkim	cmovc	$t0, $a0
2954289848Sjkim	cmovc	$t1, $a1
2955289848Sjkim	cmovc	$t2, $a2
2956289848Sjkim	cmovc	$t3, $a3
2957289848Sjkim
2958289848Sjkim	ret
2959289848Sjkim.size	__ecp_nistz256_subx,.-__ecp_nistz256_subx
2960289848Sjkim
2961289848Sjkim.type	__ecp_nistz256_mul_by_2x,\@abi-omnipotent
2962289848Sjkim.align	32
2963289848Sjkim__ecp_nistz256_mul_by_2x:
2964289848Sjkim	xor	$t4, $t4
2965289848Sjkim	adc	$a0, $a0		# a0:a3+a0:a3
2966289848Sjkim	adc	$a1, $a1
2967289848Sjkim	 mov	$a0, $t0
2968289848Sjkim	adc	$a2, $a2
2969289848Sjkim	adc	$a3, $a3
2970289848Sjkim	 mov	$a1, $t1
2971289848Sjkim	adc	\$0, $t4
2972289848Sjkim
2973289848Sjkim	xor	$t3, $t3
2974289848Sjkim	sbb	\$-1, $a0
2975289848Sjkim	 mov	$a2, $t2
2976289848Sjkim	sbb	$poly1, $a1
2977289848Sjkim	sbb	\$0, $a2
2978289848Sjkim	 mov	$a3, $t3
2979289848Sjkim	sbb	$poly3, $a3
2980306195Sjkim	sbb	\$0, $t4
2981289848Sjkim
2982306195Sjkim	cmovc	$t0, $a0
2983306195Sjkim	cmovc	$t1, $a1
2984289848Sjkim	mov	$a0, 8*0($r_ptr)
2985306195Sjkim	cmovc	$t2, $a2
2986289848Sjkim	mov	$a1, 8*1($r_ptr)
2987306195Sjkim	cmovc	$t3, $a3
2988289848Sjkim	mov	$a2, 8*2($r_ptr)
2989289848Sjkim	mov	$a3, 8*3($r_ptr)
2990289848Sjkim
2991289848Sjkim	ret
2992289848Sjkim.size	__ecp_nistz256_mul_by_2x,.-__ecp_nistz256_mul_by_2x
2993289848Sjkim___
2994289848Sjkim									}
2995289848Sjkim&gen_double("x");
2996289848Sjkim&gen_add("x");
2997289848Sjkim&gen_add_affine("x");
2998289848Sjkim}
2999289848Sjkim}}}
3000289848Sjkim
3001289848Sjkim$code =~ s/\`([^\`]*)\`/eval $1/gem;
3002289848Sjkimprint $code;
3003289848Sjkimclose STDOUT;
3004