162306a36Sopenharmony_ci#! /usr/bin/env perl
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci# This code is taken from the OpenSSL project but the author (Andy Polyakov)
562306a36Sopenharmony_ci# has relicensed it under the GPLv2. Therefore this program is free software;
662306a36Sopenharmony_ci# you can redistribute it and/or modify it under the terms of the GNU General
762306a36Sopenharmony_ci# Public License version 2 as published by the Free Software Foundation.
862306a36Sopenharmony_ci#
962306a36Sopenharmony_ci# The original headers, including the original license headers, are
1062306a36Sopenharmony_ci# included below for completeness.
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
1362306a36Sopenharmony_ci#
1462306a36Sopenharmony_ci# Licensed under the OpenSSL license (the "License").  You may not use
1562306a36Sopenharmony_ci# this file except in compliance with the License.  You can obtain a copy
1662306a36Sopenharmony_ci# in the file LICENSE in the source distribution or at
1762306a36Sopenharmony_ci# https://www.openssl.org/source/license.html
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci# ====================================================================
2062306a36Sopenharmony_ci# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
2162306a36Sopenharmony_ci# project. The module is, however, dual licensed under OpenSSL and
2262306a36Sopenharmony_ci# CRYPTOGAMS licenses depending on where you obtain it. For further
2362306a36Sopenharmony_ci# details see http://www.openssl.org/~appro/cryptogams/.
2462306a36Sopenharmony_ci# ====================================================================
2562306a36Sopenharmony_ci#
2662306a36Sopenharmony_ci# SHA256/512 for ARMv8.
2762306a36Sopenharmony_ci#
2862306a36Sopenharmony_ci# Performance in cycles per processed byte and improvement coefficient
2962306a36Sopenharmony_ci# over code generated with "default" compiler:
3062306a36Sopenharmony_ci#
3162306a36Sopenharmony_ci#		SHA256-hw	SHA256(*)	SHA512
3262306a36Sopenharmony_ci# Apple A7	1.97		10.5 (+33%)	6.73 (-1%(**))
3362306a36Sopenharmony_ci# Cortex-A53	2.38		15.5 (+115%)	10.0 (+150%(***))
3462306a36Sopenharmony_ci# Cortex-A57	2.31		11.6 (+86%)	7.51 (+260%(***))
3562306a36Sopenharmony_ci# Denver	2.01		10.5 (+26%)	6.70 (+8%)
3662306a36Sopenharmony_ci# X-Gene			20.0 (+100%)	12.8 (+300%(***))
3762306a36Sopenharmony_ci# Mongoose	2.36		13.0 (+50%)	8.36 (+33%)
3862306a36Sopenharmony_ci#
3962306a36Sopenharmony_ci# (*)	Software SHA256 results are of lesser relevance, presented
4062306a36Sopenharmony_ci#	mostly for informational purposes.
4162306a36Sopenharmony_ci# (**)	The result is a trade-off: it's possible to improve it by
4262306a36Sopenharmony_ci#	10% (or by 1 cycle per round), but at the cost of 20% loss
4362306a36Sopenharmony_ci#	on Cortex-A53 (or by 4 cycles per round).
4462306a36Sopenharmony_ci# (***)	Super-impressive coefficients over gcc-generated code are
4562306a36Sopenharmony_ci#	indication of some compiler "pathology", most notably code
4662306a36Sopenharmony_ci#	generated with -mgeneral-regs-only is significantly faster
4762306a36Sopenharmony_ci#	and the gap is only 40-90%.
4862306a36Sopenharmony_ci#
4962306a36Sopenharmony_ci# October 2016.
5062306a36Sopenharmony_ci#
5162306a36Sopenharmony_ci# Originally it was reckoned that it makes no sense to implement NEON
5262306a36Sopenharmony_ci# version of SHA256 for 64-bit processors. This is because performance
5362306a36Sopenharmony_ci# improvement on most wide-spread Cortex-A5x processors was observed
5462306a36Sopenharmony_ci# to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
5562306a36Sopenharmony_ci# observed that 32-bit NEON SHA256 performs significantly better than
5662306a36Sopenharmony_ci# 64-bit scalar version on *some* of the more recent processors. As
5762306a36Sopenharmony_ci# result 64-bit NEON version of SHA256 was added to provide best
5862306a36Sopenharmony_ci# all-round performance. For example it executes ~30% faster on X-Gene
5962306a36Sopenharmony_ci# and Mongoose. [For reference, NEON version of SHA512 is bound to
6062306a36Sopenharmony_ci# deliver much less improvement, likely *negative* on Cortex-A5x.
6162306a36Sopenharmony_ci# Which is why NEON support is limited to SHA256.]
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci$output=pop;
6462306a36Sopenharmony_ci$flavour=pop;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciif ($flavour && $flavour ne "void") {
6762306a36Sopenharmony_ci    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
6862306a36Sopenharmony_ci    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
6962306a36Sopenharmony_ci    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
7062306a36Sopenharmony_ci    die "can't locate arm-xlate.pl";
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci    open OUT,"| \"$^X\" $xlate $flavour $output";
7362306a36Sopenharmony_ci    *STDOUT=*OUT;
7462306a36Sopenharmony_ci} else {
7562306a36Sopenharmony_ci    open STDOUT,">$output";
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciif ($output =~ /512/) {
7962306a36Sopenharmony_ci	$BITS=512;
8062306a36Sopenharmony_ci	$SZ=8;
8162306a36Sopenharmony_ci	@Sigma0=(28,34,39);
8262306a36Sopenharmony_ci	@Sigma1=(14,18,41);
8362306a36Sopenharmony_ci	@sigma0=(1,  8, 7);
8462306a36Sopenharmony_ci	@sigma1=(19,61, 6);
8562306a36Sopenharmony_ci	$rounds=80;
8662306a36Sopenharmony_ci	$reg_t="x";
8762306a36Sopenharmony_ci} else {
8862306a36Sopenharmony_ci	$BITS=256;
8962306a36Sopenharmony_ci	$SZ=4;
9062306a36Sopenharmony_ci	@Sigma0=( 2,13,22);
9162306a36Sopenharmony_ci	@Sigma1=( 6,11,25);
9262306a36Sopenharmony_ci	@sigma0=( 7,18, 3);
9362306a36Sopenharmony_ci	@sigma1=(17,19,10);
9462306a36Sopenharmony_ci	$rounds=64;
9562306a36Sopenharmony_ci	$reg_t="w";
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci$func="sha${BITS}_block_data_order";
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci($ctx,$inp,$num,$Ktbl)=map("x$_",(0..2,30));
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci@X=map("$reg_t$_",(3..15,0..2));
10362306a36Sopenharmony_ci@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("$reg_t$_",(20..27));
10462306a36Sopenharmony_ci($t0,$t1,$t2,$t3)=map("$reg_t$_",(16,17,19,28));
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cisub BODY_00_xx {
10762306a36Sopenharmony_cimy ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
10862306a36Sopenharmony_cimy $j=($i+1)&15;
10962306a36Sopenharmony_cimy ($T0,$T1,$T2)=(@X[($i-8)&15],@X[($i-9)&15],@X[($i-10)&15]);
11062306a36Sopenharmony_ci   $T0=@X[$i+3] if ($i<11);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci$code.=<<___	if ($i<16);
11362306a36Sopenharmony_ci#ifndef	__AARCH64EB__
11462306a36Sopenharmony_ci	rev	@X[$i],@X[$i]			// $i
11562306a36Sopenharmony_ci#endif
11662306a36Sopenharmony_ci___
11762306a36Sopenharmony_ci$code.=<<___	if ($i<13 && ($i&1));
11862306a36Sopenharmony_ci	ldp	@X[$i+1],@X[$i+2],[$inp],#2*$SZ
11962306a36Sopenharmony_ci___
12062306a36Sopenharmony_ci$code.=<<___	if ($i==13);
12162306a36Sopenharmony_ci	ldp	@X[14],@X[15],[$inp]
12262306a36Sopenharmony_ci___
12362306a36Sopenharmony_ci$code.=<<___	if ($i>=14);
12462306a36Sopenharmony_ci	ldr	@X[($i-11)&15],[sp,#`$SZ*(($i-11)%4)`]
12562306a36Sopenharmony_ci___
12662306a36Sopenharmony_ci$code.=<<___	if ($i>0 && $i<16);
12762306a36Sopenharmony_ci	add	$a,$a,$t1			// h+=Sigma0(a)
12862306a36Sopenharmony_ci___
12962306a36Sopenharmony_ci$code.=<<___	if ($i>=11);
13062306a36Sopenharmony_ci	str	@X[($i-8)&15],[sp,#`$SZ*(($i-8)%4)`]
13162306a36Sopenharmony_ci___
13262306a36Sopenharmony_ci# While ARMv8 specifies merged rotate-n-logical operation such as
13362306a36Sopenharmony_ci# 'eor x,y,z,ror#n', it was found to negatively affect performance
13462306a36Sopenharmony_ci# on Apple A7. The reason seems to be that it requires even 'y' to
13562306a36Sopenharmony_ci# be available earlier. This means that such merged instruction is
13662306a36Sopenharmony_ci# not necessarily best choice on critical path... On the other hand
13762306a36Sopenharmony_ci# Cortex-A5x handles merged instructions much better than disjoint
13862306a36Sopenharmony_ci# rotate and logical... See (**) footnote above.
13962306a36Sopenharmony_ci$code.=<<___	if ($i<15);
14062306a36Sopenharmony_ci	ror	$t0,$e,#$Sigma1[0]
14162306a36Sopenharmony_ci	add	$h,$h,$t2			// h+=K[i]
14262306a36Sopenharmony_ci	eor	$T0,$e,$e,ror#`$Sigma1[2]-$Sigma1[1]`
14362306a36Sopenharmony_ci	and	$t1,$f,$e
14462306a36Sopenharmony_ci	bic	$t2,$g,$e
14562306a36Sopenharmony_ci	add	$h,$h,@X[$i&15]			// h+=X[i]
14662306a36Sopenharmony_ci	orr	$t1,$t1,$t2			// Ch(e,f,g)
14762306a36Sopenharmony_ci	eor	$t2,$a,$b			// a^b, b^c in next round
14862306a36Sopenharmony_ci	eor	$t0,$t0,$T0,ror#$Sigma1[1]	// Sigma1(e)
14962306a36Sopenharmony_ci	ror	$T0,$a,#$Sigma0[0]
15062306a36Sopenharmony_ci	add	$h,$h,$t1			// h+=Ch(e,f,g)
15162306a36Sopenharmony_ci	eor	$t1,$a,$a,ror#`$Sigma0[2]-$Sigma0[1]`
15262306a36Sopenharmony_ci	add	$h,$h,$t0			// h+=Sigma1(e)
15362306a36Sopenharmony_ci	and	$t3,$t3,$t2			// (b^c)&=(a^b)
15462306a36Sopenharmony_ci	add	$d,$d,$h			// d+=h
15562306a36Sopenharmony_ci	eor	$t3,$t3,$b			// Maj(a,b,c)
15662306a36Sopenharmony_ci	eor	$t1,$T0,$t1,ror#$Sigma0[1]	// Sigma0(a)
15762306a36Sopenharmony_ci	add	$h,$h,$t3			// h+=Maj(a,b,c)
15862306a36Sopenharmony_ci	ldr	$t3,[$Ktbl],#$SZ		// *K++, $t2 in next round
15962306a36Sopenharmony_ci	//add	$h,$h,$t1			// h+=Sigma0(a)
16062306a36Sopenharmony_ci___
16162306a36Sopenharmony_ci$code.=<<___	if ($i>=15);
16262306a36Sopenharmony_ci	ror	$t0,$e,#$Sigma1[0]
16362306a36Sopenharmony_ci	add	$h,$h,$t2			// h+=K[i]
16462306a36Sopenharmony_ci	ror	$T1,@X[($j+1)&15],#$sigma0[0]
16562306a36Sopenharmony_ci	and	$t1,$f,$e
16662306a36Sopenharmony_ci	ror	$T2,@X[($j+14)&15],#$sigma1[0]
16762306a36Sopenharmony_ci	bic	$t2,$g,$e
16862306a36Sopenharmony_ci	ror	$T0,$a,#$Sigma0[0]
16962306a36Sopenharmony_ci	add	$h,$h,@X[$i&15]			// h+=X[i]
17062306a36Sopenharmony_ci	eor	$t0,$t0,$e,ror#$Sigma1[1]
17162306a36Sopenharmony_ci	eor	$T1,$T1,@X[($j+1)&15],ror#$sigma0[1]
17262306a36Sopenharmony_ci	orr	$t1,$t1,$t2			// Ch(e,f,g)
17362306a36Sopenharmony_ci	eor	$t2,$a,$b			// a^b, b^c in next round
17462306a36Sopenharmony_ci	eor	$t0,$t0,$e,ror#$Sigma1[2]	// Sigma1(e)
17562306a36Sopenharmony_ci	eor	$T0,$T0,$a,ror#$Sigma0[1]
17662306a36Sopenharmony_ci	add	$h,$h,$t1			// h+=Ch(e,f,g)
17762306a36Sopenharmony_ci	and	$t3,$t3,$t2			// (b^c)&=(a^b)
17862306a36Sopenharmony_ci	eor	$T2,$T2,@X[($j+14)&15],ror#$sigma1[1]
17962306a36Sopenharmony_ci	eor	$T1,$T1,@X[($j+1)&15],lsr#$sigma0[2]	// sigma0(X[i+1])
18062306a36Sopenharmony_ci	add	$h,$h,$t0			// h+=Sigma1(e)
18162306a36Sopenharmony_ci	eor	$t3,$t3,$b			// Maj(a,b,c)
18262306a36Sopenharmony_ci	eor	$t1,$T0,$a,ror#$Sigma0[2]	// Sigma0(a)
18362306a36Sopenharmony_ci	eor	$T2,$T2,@X[($j+14)&15],lsr#$sigma1[2]	// sigma1(X[i+14])
18462306a36Sopenharmony_ci	add	@X[$j],@X[$j],@X[($j+9)&15]
18562306a36Sopenharmony_ci	add	$d,$d,$h			// d+=h
18662306a36Sopenharmony_ci	add	$h,$h,$t3			// h+=Maj(a,b,c)
18762306a36Sopenharmony_ci	ldr	$t3,[$Ktbl],#$SZ		// *K++, $t2 in next round
18862306a36Sopenharmony_ci	add	@X[$j],@X[$j],$T1
18962306a36Sopenharmony_ci	add	$h,$h,$t1			// h+=Sigma0(a)
19062306a36Sopenharmony_ci	add	@X[$j],@X[$j],$T2
19162306a36Sopenharmony_ci___
19262306a36Sopenharmony_ci	($t2,$t3)=($t3,$t2);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci$code.=<<___;
19662306a36Sopenharmony_ci#ifndef	__KERNEL__
19762306a36Sopenharmony_ci# include "arm_arch.h"
19862306a36Sopenharmony_ci#endif
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci.text
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci.extern	OPENSSL_armcap_P
20362306a36Sopenharmony_ci.globl	$func
20462306a36Sopenharmony_ci.type	$func,%function
20562306a36Sopenharmony_ci.align	6
20662306a36Sopenharmony_ci$func:
20762306a36Sopenharmony_ci___
20862306a36Sopenharmony_ci$code.=<<___	if ($SZ==4);
20962306a36Sopenharmony_ci#ifndef	__KERNEL__
21062306a36Sopenharmony_ci# ifdef	__ILP32__
21162306a36Sopenharmony_ci	ldrsw	x16,.LOPENSSL_armcap_P
21262306a36Sopenharmony_ci# else
21362306a36Sopenharmony_ci	ldr	x16,.LOPENSSL_armcap_P
21462306a36Sopenharmony_ci# endif
21562306a36Sopenharmony_ci	adr	x17,.LOPENSSL_armcap_P
21662306a36Sopenharmony_ci	add	x16,x16,x17
21762306a36Sopenharmony_ci	ldr	w16,[x16]
21862306a36Sopenharmony_ci	tst	w16,#ARMV8_SHA256
21962306a36Sopenharmony_ci	b.ne	.Lv8_entry
22062306a36Sopenharmony_ci	tst	w16,#ARMV7_NEON
22162306a36Sopenharmony_ci	b.ne	.Lneon_entry
22262306a36Sopenharmony_ci#endif
22362306a36Sopenharmony_ci___
22462306a36Sopenharmony_ci$code.=<<___;
22562306a36Sopenharmony_ci	stp	x29,x30,[sp,#-128]!
22662306a36Sopenharmony_ci	add	x29,sp,#0
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	stp	x19,x20,[sp,#16]
22962306a36Sopenharmony_ci	stp	x21,x22,[sp,#32]
23062306a36Sopenharmony_ci	stp	x23,x24,[sp,#48]
23162306a36Sopenharmony_ci	stp	x25,x26,[sp,#64]
23262306a36Sopenharmony_ci	stp	x27,x28,[sp,#80]
23362306a36Sopenharmony_ci	sub	sp,sp,#4*$SZ
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	ldp	$A,$B,[$ctx]				// load context
23662306a36Sopenharmony_ci	ldp	$C,$D,[$ctx,#2*$SZ]
23762306a36Sopenharmony_ci	ldp	$E,$F,[$ctx,#4*$SZ]
23862306a36Sopenharmony_ci	add	$num,$inp,$num,lsl#`log(16*$SZ)/log(2)`	// end of input
23962306a36Sopenharmony_ci	ldp	$G,$H,[$ctx,#6*$SZ]
24062306a36Sopenharmony_ci	adr	$Ktbl,.LK$BITS
24162306a36Sopenharmony_ci	stp	$ctx,$num,[x29,#96]
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci.Loop:
24462306a36Sopenharmony_ci	ldp	@X[0],@X[1],[$inp],#2*$SZ
24562306a36Sopenharmony_ci	ldr	$t2,[$Ktbl],#$SZ			// *K++
24662306a36Sopenharmony_ci	eor	$t3,$B,$C				// magic seed
24762306a36Sopenharmony_ci	str	$inp,[x29,#112]
24862306a36Sopenharmony_ci___
24962306a36Sopenharmony_cifor ($i=0;$i<16;$i++)	{ &BODY_00_xx($i,@V); unshift(@V,pop(@V)); }
25062306a36Sopenharmony_ci$code.=".Loop_16_xx:\n";
25162306a36Sopenharmony_cifor (;$i<32;$i++)	{ &BODY_00_xx($i,@V); unshift(@V,pop(@V)); }
25262306a36Sopenharmony_ci$code.=<<___;
25362306a36Sopenharmony_ci	cbnz	$t2,.Loop_16_xx
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	ldp	$ctx,$num,[x29,#96]
25662306a36Sopenharmony_ci	ldr	$inp,[x29,#112]
25762306a36Sopenharmony_ci	sub	$Ktbl,$Ktbl,#`$SZ*($rounds+1)`		// rewind
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	ldp	@X[0],@X[1],[$ctx]
26062306a36Sopenharmony_ci	ldp	@X[2],@X[3],[$ctx,#2*$SZ]
26162306a36Sopenharmony_ci	add	$inp,$inp,#14*$SZ			// advance input pointer
26262306a36Sopenharmony_ci	ldp	@X[4],@X[5],[$ctx,#4*$SZ]
26362306a36Sopenharmony_ci	add	$A,$A,@X[0]
26462306a36Sopenharmony_ci	ldp	@X[6],@X[7],[$ctx,#6*$SZ]
26562306a36Sopenharmony_ci	add	$B,$B,@X[1]
26662306a36Sopenharmony_ci	add	$C,$C,@X[2]
26762306a36Sopenharmony_ci	add	$D,$D,@X[3]
26862306a36Sopenharmony_ci	stp	$A,$B,[$ctx]
26962306a36Sopenharmony_ci	add	$E,$E,@X[4]
27062306a36Sopenharmony_ci	add	$F,$F,@X[5]
27162306a36Sopenharmony_ci	stp	$C,$D,[$ctx,#2*$SZ]
27262306a36Sopenharmony_ci	add	$G,$G,@X[6]
27362306a36Sopenharmony_ci	add	$H,$H,@X[7]
27462306a36Sopenharmony_ci	cmp	$inp,$num
27562306a36Sopenharmony_ci	stp	$E,$F,[$ctx,#4*$SZ]
27662306a36Sopenharmony_ci	stp	$G,$H,[$ctx,#6*$SZ]
27762306a36Sopenharmony_ci	b.ne	.Loop
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ldp	x19,x20,[x29,#16]
28062306a36Sopenharmony_ci	add	sp,sp,#4*$SZ
28162306a36Sopenharmony_ci	ldp	x21,x22,[x29,#32]
28262306a36Sopenharmony_ci	ldp	x23,x24,[x29,#48]
28362306a36Sopenharmony_ci	ldp	x25,x26,[x29,#64]
28462306a36Sopenharmony_ci	ldp	x27,x28,[x29,#80]
28562306a36Sopenharmony_ci	ldp	x29,x30,[sp],#128
28662306a36Sopenharmony_ci	ret
28762306a36Sopenharmony_ci.size	$func,.-$func
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci.align	6
29062306a36Sopenharmony_ci.type	.LK$BITS,%object
29162306a36Sopenharmony_ci.LK$BITS:
29262306a36Sopenharmony_ci___
29362306a36Sopenharmony_ci$code.=<<___ if ($SZ==8);
29462306a36Sopenharmony_ci	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
29562306a36Sopenharmony_ci	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
29662306a36Sopenharmony_ci	.quad	0x3956c25bf348b538,0x59f111f1b605d019
29762306a36Sopenharmony_ci	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
29862306a36Sopenharmony_ci	.quad	0xd807aa98a3030242,0x12835b0145706fbe
29962306a36Sopenharmony_ci	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
30062306a36Sopenharmony_ci	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
30162306a36Sopenharmony_ci	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
30262306a36Sopenharmony_ci	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
30362306a36Sopenharmony_ci	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
30462306a36Sopenharmony_ci	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
30562306a36Sopenharmony_ci	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
30662306a36Sopenharmony_ci	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
30762306a36Sopenharmony_ci	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
30862306a36Sopenharmony_ci	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
30962306a36Sopenharmony_ci	.quad	0x06ca6351e003826f,0x142929670a0e6e70
31062306a36Sopenharmony_ci	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
31162306a36Sopenharmony_ci	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
31262306a36Sopenharmony_ci	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
31362306a36Sopenharmony_ci	.quad	0x81c2c92e47edaee6,0x92722c851482353b
31462306a36Sopenharmony_ci	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
31562306a36Sopenharmony_ci	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
31662306a36Sopenharmony_ci	.quad	0xd192e819d6ef5218,0xd69906245565a910
31762306a36Sopenharmony_ci	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
31862306a36Sopenharmony_ci	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
31962306a36Sopenharmony_ci	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
32062306a36Sopenharmony_ci	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
32162306a36Sopenharmony_ci	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
32262306a36Sopenharmony_ci	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
32362306a36Sopenharmony_ci	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
32462306a36Sopenharmony_ci	.quad	0x90befffa23631e28,0xa4506cebde82bde9
32562306a36Sopenharmony_ci	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
32662306a36Sopenharmony_ci	.quad	0xca273eceea26619c,0xd186b8c721c0c207
32762306a36Sopenharmony_ci	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
32862306a36Sopenharmony_ci	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
32962306a36Sopenharmony_ci	.quad	0x113f9804bef90dae,0x1b710b35131c471b
33062306a36Sopenharmony_ci	.quad	0x28db77f523047d84,0x32caab7b40c72493
33162306a36Sopenharmony_ci	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
33262306a36Sopenharmony_ci	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
33362306a36Sopenharmony_ci	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
33462306a36Sopenharmony_ci	.quad	0	// terminator
33562306a36Sopenharmony_ci___
33662306a36Sopenharmony_ci$code.=<<___ if ($SZ==4);
33762306a36Sopenharmony_ci	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
33862306a36Sopenharmony_ci	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
33962306a36Sopenharmony_ci	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
34062306a36Sopenharmony_ci	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
34162306a36Sopenharmony_ci	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
34262306a36Sopenharmony_ci	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
34362306a36Sopenharmony_ci	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
34462306a36Sopenharmony_ci	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
34562306a36Sopenharmony_ci	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
34662306a36Sopenharmony_ci	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
34762306a36Sopenharmony_ci	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
34862306a36Sopenharmony_ci	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
34962306a36Sopenharmony_ci	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
35062306a36Sopenharmony_ci	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
35162306a36Sopenharmony_ci	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
35262306a36Sopenharmony_ci	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
35362306a36Sopenharmony_ci	.long	0	//terminator
35462306a36Sopenharmony_ci___
35562306a36Sopenharmony_ci$code.=<<___;
35662306a36Sopenharmony_ci.size	.LK$BITS,.-.LK$BITS
35762306a36Sopenharmony_ci#ifndef	__KERNEL__
35862306a36Sopenharmony_ci.align	3
35962306a36Sopenharmony_ci.LOPENSSL_armcap_P:
36062306a36Sopenharmony_ci# ifdef	__ILP32__
36162306a36Sopenharmony_ci	.long	OPENSSL_armcap_P-.
36262306a36Sopenharmony_ci# else
36362306a36Sopenharmony_ci	.quad	OPENSSL_armcap_P-.
36462306a36Sopenharmony_ci# endif
36562306a36Sopenharmony_ci#endif
36662306a36Sopenharmony_ci.asciz	"SHA$BITS block transform for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
36762306a36Sopenharmony_ci.align	2
36862306a36Sopenharmony_ci___
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ciif ($SZ==4) {
37162306a36Sopenharmony_cimy $Ktbl="x3";
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cimy ($ABCD,$EFGH,$abcd)=map("v$_.16b",(0..2));
37462306a36Sopenharmony_cimy @MSG=map("v$_.16b",(4..7));
37562306a36Sopenharmony_cimy ($W0,$W1)=("v16.4s","v17.4s");
37662306a36Sopenharmony_cimy ($ABCD_SAVE,$EFGH_SAVE)=("v18.16b","v19.16b");
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci$code.=<<___;
37962306a36Sopenharmony_ci#ifndef	__KERNEL__
38062306a36Sopenharmony_ci.type	sha256_block_armv8,%function
38162306a36Sopenharmony_ci.align	6
38262306a36Sopenharmony_cisha256_block_armv8:
38362306a36Sopenharmony_ci.Lv8_entry:
38462306a36Sopenharmony_ci	stp		x29,x30,[sp,#-16]!
38562306a36Sopenharmony_ci	add		x29,sp,#0
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ld1.32		{$ABCD,$EFGH},[$ctx]
38862306a36Sopenharmony_ci	adr		$Ktbl,.LK256
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci.Loop_hw:
39162306a36Sopenharmony_ci	ld1		{@MSG[0]-@MSG[3]},[$inp],#64
39262306a36Sopenharmony_ci	sub		$num,$num,#1
39362306a36Sopenharmony_ci	ld1.32		{$W0},[$Ktbl],#16
39462306a36Sopenharmony_ci	rev32		@MSG[0],@MSG[0]
39562306a36Sopenharmony_ci	rev32		@MSG[1],@MSG[1]
39662306a36Sopenharmony_ci	rev32		@MSG[2],@MSG[2]
39762306a36Sopenharmony_ci	rev32		@MSG[3],@MSG[3]
39862306a36Sopenharmony_ci	orr		$ABCD_SAVE,$ABCD,$ABCD		// offload
39962306a36Sopenharmony_ci	orr		$EFGH_SAVE,$EFGH,$EFGH
40062306a36Sopenharmony_ci___
40162306a36Sopenharmony_cifor($i=0;$i<12;$i++) {
40262306a36Sopenharmony_ci$code.=<<___;
40362306a36Sopenharmony_ci	ld1.32		{$W1},[$Ktbl],#16
40462306a36Sopenharmony_ci	add.i32		$W0,$W0,@MSG[0]
40562306a36Sopenharmony_ci	sha256su0	@MSG[0],@MSG[1]
40662306a36Sopenharmony_ci	orr		$abcd,$ABCD,$ABCD
40762306a36Sopenharmony_ci	sha256h		$ABCD,$EFGH,$W0
40862306a36Sopenharmony_ci	sha256h2	$EFGH,$abcd,$W0
40962306a36Sopenharmony_ci	sha256su1	@MSG[0],@MSG[2],@MSG[3]
41062306a36Sopenharmony_ci___
41162306a36Sopenharmony_ci	($W0,$W1)=($W1,$W0);	push(@MSG,shift(@MSG));
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci$code.=<<___;
41462306a36Sopenharmony_ci	ld1.32		{$W1},[$Ktbl],#16
41562306a36Sopenharmony_ci	add.i32		$W0,$W0,@MSG[0]
41662306a36Sopenharmony_ci	orr		$abcd,$ABCD,$ABCD
41762306a36Sopenharmony_ci	sha256h		$ABCD,$EFGH,$W0
41862306a36Sopenharmony_ci	sha256h2	$EFGH,$abcd,$W0
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	ld1.32		{$W0},[$Ktbl],#16
42162306a36Sopenharmony_ci	add.i32		$W1,$W1,@MSG[1]
42262306a36Sopenharmony_ci	orr		$abcd,$ABCD,$ABCD
42362306a36Sopenharmony_ci	sha256h		$ABCD,$EFGH,$W1
42462306a36Sopenharmony_ci	sha256h2	$EFGH,$abcd,$W1
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	ld1.32		{$W1},[$Ktbl]
42762306a36Sopenharmony_ci	add.i32		$W0,$W0,@MSG[2]
42862306a36Sopenharmony_ci	sub		$Ktbl,$Ktbl,#$rounds*$SZ-16	// rewind
42962306a36Sopenharmony_ci	orr		$abcd,$ABCD,$ABCD
43062306a36Sopenharmony_ci	sha256h		$ABCD,$EFGH,$W0
43162306a36Sopenharmony_ci	sha256h2	$EFGH,$abcd,$W0
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	add.i32		$W1,$W1,@MSG[3]
43462306a36Sopenharmony_ci	orr		$abcd,$ABCD,$ABCD
43562306a36Sopenharmony_ci	sha256h		$ABCD,$EFGH,$W1
43662306a36Sopenharmony_ci	sha256h2	$EFGH,$abcd,$W1
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	add.i32		$ABCD,$ABCD,$ABCD_SAVE
43962306a36Sopenharmony_ci	add.i32		$EFGH,$EFGH,$EFGH_SAVE
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	cbnz		$num,.Loop_hw
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	st1.32		{$ABCD,$EFGH},[$ctx]
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	ldr		x29,[sp],#16
44662306a36Sopenharmony_ci	ret
44762306a36Sopenharmony_ci.size	sha256_block_armv8,.-sha256_block_armv8
44862306a36Sopenharmony_ci#endif
44962306a36Sopenharmony_ci___
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciif ($SZ==4) {	######################################### NEON stuff #
45362306a36Sopenharmony_ci# You'll surely note a lot of similarities with sha256-armv4 module,
45462306a36Sopenharmony_ci# and of course it's not a coincidence. sha256-armv4 was used as
45562306a36Sopenharmony_ci# initial template, but was adapted for ARMv8 instruction set and
45662306a36Sopenharmony_ci# extensively re-tuned for all-round performance.
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cimy @V = ($A,$B,$C,$D,$E,$F,$G,$H) = map("w$_",(3..10));
45962306a36Sopenharmony_cimy ($t0,$t1,$t2,$t3,$t4) = map("w$_",(11..15));
46062306a36Sopenharmony_cimy $Ktbl="x16";
46162306a36Sopenharmony_cimy $Xfer="x17";
46262306a36Sopenharmony_cimy @X = map("q$_",(0..3));
46362306a36Sopenharmony_cimy ($T0,$T1,$T2,$T3,$T4,$T5,$T6,$T7) = map("q$_",(4..7,16..19));
46462306a36Sopenharmony_cimy $j=0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cisub AUTOLOAD()          # thunk [simplified] x86-style perlasm
46762306a36Sopenharmony_ci{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
46862306a36Sopenharmony_ci  my $arg = pop;
46962306a36Sopenharmony_ci    $arg = "#$arg" if ($arg*1 eq $arg);
47062306a36Sopenharmony_ci    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cisub Dscalar { shift =~ m|[qv]([0-9]+)|?"d$1":""; }
47462306a36Sopenharmony_cisub Dlo     { shift =~ m|[qv]([0-9]+)|?"v$1.d[0]":""; }
47562306a36Sopenharmony_cisub Dhi     { shift =~ m|[qv]([0-9]+)|?"v$1.d[1]":""; }
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cisub Xupdate()
47862306a36Sopenharmony_ci{ use integer;
47962306a36Sopenharmony_ci  my $body = shift;
48062306a36Sopenharmony_ci  my @insns = (&$body,&$body,&$body,&$body);
48162306a36Sopenharmony_ci  my ($a,$b,$c,$d,$e,$f,$g,$h);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	&ext_8		($T0,@X[0],@X[1],4);	# X[1..4]
48462306a36Sopenharmony_ci	 eval(shift(@insns));
48562306a36Sopenharmony_ci	 eval(shift(@insns));
48662306a36Sopenharmony_ci	 eval(shift(@insns));
48762306a36Sopenharmony_ci	&ext_8		($T3,@X[2],@X[3],4);	# X[9..12]
48862306a36Sopenharmony_ci	 eval(shift(@insns));
48962306a36Sopenharmony_ci	 eval(shift(@insns));
49062306a36Sopenharmony_ci	&mov		(&Dscalar($T7),&Dhi(@X[3]));	# X[14..15]
49162306a36Sopenharmony_ci	 eval(shift(@insns));
49262306a36Sopenharmony_ci	 eval(shift(@insns));
49362306a36Sopenharmony_ci	&ushr_32	($T2,$T0,$sigma0[0]);
49462306a36Sopenharmony_ci	 eval(shift(@insns));
49562306a36Sopenharmony_ci	&ushr_32	($T1,$T0,$sigma0[2]);
49662306a36Sopenharmony_ci	 eval(shift(@insns));
49762306a36Sopenharmony_ci	&add_32 	(@X[0],@X[0],$T3);	# X[0..3] += X[9..12]
49862306a36Sopenharmony_ci	 eval(shift(@insns));
49962306a36Sopenharmony_ci	&sli_32		($T2,$T0,32-$sigma0[0]);
50062306a36Sopenharmony_ci	 eval(shift(@insns));
50162306a36Sopenharmony_ci	 eval(shift(@insns));
50262306a36Sopenharmony_ci	&ushr_32	($T3,$T0,$sigma0[1]);
50362306a36Sopenharmony_ci	 eval(shift(@insns));
50462306a36Sopenharmony_ci	 eval(shift(@insns));
50562306a36Sopenharmony_ci	&eor_8		($T1,$T1,$T2);
50662306a36Sopenharmony_ci	 eval(shift(@insns));
50762306a36Sopenharmony_ci	 eval(shift(@insns));
50862306a36Sopenharmony_ci	&sli_32		($T3,$T0,32-$sigma0[1]);
50962306a36Sopenharmony_ci	 eval(shift(@insns));
51062306a36Sopenharmony_ci	 eval(shift(@insns));
51162306a36Sopenharmony_ci	  &ushr_32	($T4,$T7,$sigma1[0]);
51262306a36Sopenharmony_ci	 eval(shift(@insns));
51362306a36Sopenharmony_ci	 eval(shift(@insns));
51462306a36Sopenharmony_ci	&eor_8		($T1,$T1,$T3);		# sigma0(X[1..4])
51562306a36Sopenharmony_ci	 eval(shift(@insns));
51662306a36Sopenharmony_ci	 eval(shift(@insns));
51762306a36Sopenharmony_ci	  &sli_32	($T4,$T7,32-$sigma1[0]);
51862306a36Sopenharmony_ci	 eval(shift(@insns));
51962306a36Sopenharmony_ci	 eval(shift(@insns));
52062306a36Sopenharmony_ci	  &ushr_32	($T5,$T7,$sigma1[2]);
52162306a36Sopenharmony_ci	 eval(shift(@insns));
52262306a36Sopenharmony_ci	 eval(shift(@insns));
52362306a36Sopenharmony_ci	  &ushr_32	($T3,$T7,$sigma1[1]);
52462306a36Sopenharmony_ci	 eval(shift(@insns));
52562306a36Sopenharmony_ci	 eval(shift(@insns));
52662306a36Sopenharmony_ci	&add_32		(@X[0],@X[0],$T1);	# X[0..3] += sigma0(X[1..4])
52762306a36Sopenharmony_ci	 eval(shift(@insns));
52862306a36Sopenharmony_ci	 eval(shift(@insns));
52962306a36Sopenharmony_ci	  &sli_u32	($T3,$T7,32-$sigma1[1]);
53062306a36Sopenharmony_ci	 eval(shift(@insns));
53162306a36Sopenharmony_ci	 eval(shift(@insns));
53262306a36Sopenharmony_ci	  &eor_8	($T5,$T5,$T4);
53362306a36Sopenharmony_ci	 eval(shift(@insns));
53462306a36Sopenharmony_ci	 eval(shift(@insns));
53562306a36Sopenharmony_ci	 eval(shift(@insns));
53662306a36Sopenharmony_ci	  &eor_8	($T5,$T5,$T3);		# sigma1(X[14..15])
53762306a36Sopenharmony_ci	 eval(shift(@insns));
53862306a36Sopenharmony_ci	 eval(shift(@insns));
53962306a36Sopenharmony_ci	 eval(shift(@insns));
54062306a36Sopenharmony_ci	&add_32		(@X[0],@X[0],$T5);	# X[0..1] += sigma1(X[14..15])
54162306a36Sopenharmony_ci	 eval(shift(@insns));
54262306a36Sopenharmony_ci	 eval(shift(@insns));
54362306a36Sopenharmony_ci	 eval(shift(@insns));
54462306a36Sopenharmony_ci	  &ushr_32	($T6,@X[0],$sigma1[0]);
54562306a36Sopenharmony_ci	 eval(shift(@insns));
54662306a36Sopenharmony_ci	  &ushr_32	($T7,@X[0],$sigma1[2]);
54762306a36Sopenharmony_ci	 eval(shift(@insns));
54862306a36Sopenharmony_ci	 eval(shift(@insns));
54962306a36Sopenharmony_ci	  &sli_32	($T6,@X[0],32-$sigma1[0]);
55062306a36Sopenharmony_ci	 eval(shift(@insns));
55162306a36Sopenharmony_ci	  &ushr_32	($T5,@X[0],$sigma1[1]);
55262306a36Sopenharmony_ci	 eval(shift(@insns));
55362306a36Sopenharmony_ci	 eval(shift(@insns));
55462306a36Sopenharmony_ci	  &eor_8	($T7,$T7,$T6);
55562306a36Sopenharmony_ci	 eval(shift(@insns));
55662306a36Sopenharmony_ci	 eval(shift(@insns));
55762306a36Sopenharmony_ci	  &sli_32	($T5,@X[0],32-$sigma1[1]);
55862306a36Sopenharmony_ci	 eval(shift(@insns));
55962306a36Sopenharmony_ci	 eval(shift(@insns));
56062306a36Sopenharmony_ci	&ld1_32		("{$T0}","[$Ktbl], #16");
56162306a36Sopenharmony_ci	 eval(shift(@insns));
56262306a36Sopenharmony_ci	  &eor_8	($T7,$T7,$T5);		# sigma1(X[16..17])
56362306a36Sopenharmony_ci	 eval(shift(@insns));
56462306a36Sopenharmony_ci	 eval(shift(@insns));
56562306a36Sopenharmony_ci	&eor_8		($T5,$T5,$T5);
56662306a36Sopenharmony_ci	 eval(shift(@insns));
56762306a36Sopenharmony_ci	 eval(shift(@insns));
56862306a36Sopenharmony_ci	&mov		(&Dhi($T5), &Dlo($T7));
56962306a36Sopenharmony_ci	 eval(shift(@insns));
57062306a36Sopenharmony_ci	 eval(shift(@insns));
57162306a36Sopenharmony_ci	 eval(shift(@insns));
57262306a36Sopenharmony_ci	&add_32		(@X[0],@X[0],$T5);	# X[2..3] += sigma1(X[16..17])
57362306a36Sopenharmony_ci	 eval(shift(@insns));
57462306a36Sopenharmony_ci	 eval(shift(@insns));
57562306a36Sopenharmony_ci	 eval(shift(@insns));
57662306a36Sopenharmony_ci	&add_32		($T0,$T0,@X[0]);
57762306a36Sopenharmony_ci	 while($#insns>=1) { eval(shift(@insns)); }
57862306a36Sopenharmony_ci	&st1_32		("{$T0}","[$Xfer], #16");
57962306a36Sopenharmony_ci	 eval(shift(@insns));
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	push(@X,shift(@X));		# "rotate" X[]
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cisub Xpreload()
58562306a36Sopenharmony_ci{ use integer;
58662306a36Sopenharmony_ci  my $body = shift;
58762306a36Sopenharmony_ci  my @insns = (&$body,&$body,&$body,&$body);
58862306a36Sopenharmony_ci  my ($a,$b,$c,$d,$e,$f,$g,$h);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	 eval(shift(@insns));
59162306a36Sopenharmony_ci	 eval(shift(@insns));
59262306a36Sopenharmony_ci	&ld1_8		("{@X[0]}","[$inp],#16");
59362306a36Sopenharmony_ci	 eval(shift(@insns));
59462306a36Sopenharmony_ci	 eval(shift(@insns));
59562306a36Sopenharmony_ci	&ld1_32		("{$T0}","[$Ktbl],#16");
59662306a36Sopenharmony_ci	 eval(shift(@insns));
59762306a36Sopenharmony_ci	 eval(shift(@insns));
59862306a36Sopenharmony_ci	 eval(shift(@insns));
59962306a36Sopenharmony_ci	 eval(shift(@insns));
60062306a36Sopenharmony_ci	&rev32		(@X[0],@X[0]);
60162306a36Sopenharmony_ci	 eval(shift(@insns));
60262306a36Sopenharmony_ci	 eval(shift(@insns));
60362306a36Sopenharmony_ci	 eval(shift(@insns));
60462306a36Sopenharmony_ci	 eval(shift(@insns));
60562306a36Sopenharmony_ci	&add_32		($T0,$T0,@X[0]);
60662306a36Sopenharmony_ci	 foreach (@insns) { eval; }	# remaining instructions
60762306a36Sopenharmony_ci	&st1_32		("{$T0}","[$Xfer], #16");
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	push(@X,shift(@X));		# "rotate" X[]
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cisub body_00_15 () {
61362306a36Sopenharmony_ci	(
61462306a36Sopenharmony_ci	'($a,$b,$c,$d,$e,$f,$g,$h)=@V;'.
61562306a36Sopenharmony_ci	'&add	($h,$h,$t1)',			# h+=X[i]+K[i]
61662306a36Sopenharmony_ci	'&add	($a,$a,$t4);'.			# h+=Sigma0(a) from the past
61762306a36Sopenharmony_ci	'&and	($t1,$f,$e)',
61862306a36Sopenharmony_ci	'&bic	($t4,$g,$e)',
61962306a36Sopenharmony_ci	'&eor	($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))',
62062306a36Sopenharmony_ci	'&add	($a,$a,$t2)',			# h+=Maj(a,b,c) from the past
62162306a36Sopenharmony_ci	'&orr	($t1,$t1,$t4)',			# Ch(e,f,g)
62262306a36Sopenharmony_ci	'&eor	($t0,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))',	# Sigma1(e)
62362306a36Sopenharmony_ci	'&eor	($t4,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))',
62462306a36Sopenharmony_ci	'&add	($h,$h,$t1)',			# h+=Ch(e,f,g)
62562306a36Sopenharmony_ci	'&ror	($t0,$t0,"#$Sigma1[0]")',
62662306a36Sopenharmony_ci	'&eor	($t2,$a,$b)',			# a^b, b^c in next round
62762306a36Sopenharmony_ci	'&eor	($t4,$t4,$a,"ror#".($Sigma0[2]-$Sigma0[0]))',	# Sigma0(a)
62862306a36Sopenharmony_ci	'&add	($h,$h,$t0)',			# h+=Sigma1(e)
62962306a36Sopenharmony_ci	'&ldr	($t1,sprintf "[sp,#%d]",4*(($j+1)&15))	if (($j&15)!=15);'.
63062306a36Sopenharmony_ci	'&ldr	($t1,"[$Ktbl]")				if ($j==15);'.
63162306a36Sopenharmony_ci	'&and	($t3,$t3,$t2)',			# (b^c)&=(a^b)
63262306a36Sopenharmony_ci	'&ror	($t4,$t4,"#$Sigma0[0]")',
63362306a36Sopenharmony_ci	'&add	($d,$d,$h)',			# d+=h
63462306a36Sopenharmony_ci	'&eor	($t3,$t3,$b)',			# Maj(a,b,c)
63562306a36Sopenharmony_ci	'$j++;	unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);'
63662306a36Sopenharmony_ci	)
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci$code.=<<___;
64062306a36Sopenharmony_ci#ifdef	__KERNEL__
64162306a36Sopenharmony_ci.globl	sha256_block_neon
64262306a36Sopenharmony_ci#endif
64362306a36Sopenharmony_ci.type	sha256_block_neon,%function
64462306a36Sopenharmony_ci.align	4
64562306a36Sopenharmony_cisha256_block_neon:
64662306a36Sopenharmony_ci.Lneon_entry:
64762306a36Sopenharmony_ci	stp	x29, x30, [sp, #-16]!
64862306a36Sopenharmony_ci	mov	x29, sp
64962306a36Sopenharmony_ci	sub	sp,sp,#16*4
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	adr	$Ktbl,.LK256
65262306a36Sopenharmony_ci	add	$num,$inp,$num,lsl#6	// len to point at the end of inp
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	ld1.8	{@X[0]},[$inp], #16
65562306a36Sopenharmony_ci	ld1.8	{@X[1]},[$inp], #16
65662306a36Sopenharmony_ci	ld1.8	{@X[2]},[$inp], #16
65762306a36Sopenharmony_ci	ld1.8	{@X[3]},[$inp], #16
65862306a36Sopenharmony_ci	ld1.32	{$T0},[$Ktbl], #16
65962306a36Sopenharmony_ci	ld1.32	{$T1},[$Ktbl], #16
66062306a36Sopenharmony_ci	ld1.32	{$T2},[$Ktbl], #16
66162306a36Sopenharmony_ci	ld1.32	{$T3},[$Ktbl], #16
66262306a36Sopenharmony_ci	rev32	@X[0],@X[0]		// yes, even on
66362306a36Sopenharmony_ci	rev32	@X[1],@X[1]		// big-endian
66462306a36Sopenharmony_ci	rev32	@X[2],@X[2]
66562306a36Sopenharmony_ci	rev32	@X[3],@X[3]
66662306a36Sopenharmony_ci	mov	$Xfer,sp
66762306a36Sopenharmony_ci	add.32	$T0,$T0,@X[0]
66862306a36Sopenharmony_ci	add.32	$T1,$T1,@X[1]
66962306a36Sopenharmony_ci	add.32	$T2,$T2,@X[2]
67062306a36Sopenharmony_ci	st1.32	{$T0-$T1},[$Xfer], #32
67162306a36Sopenharmony_ci	add.32	$T3,$T3,@X[3]
67262306a36Sopenharmony_ci	st1.32	{$T2-$T3},[$Xfer]
67362306a36Sopenharmony_ci	sub	$Xfer,$Xfer,#32
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	ldp	$A,$B,[$ctx]
67662306a36Sopenharmony_ci	ldp	$C,$D,[$ctx,#8]
67762306a36Sopenharmony_ci	ldp	$E,$F,[$ctx,#16]
67862306a36Sopenharmony_ci	ldp	$G,$H,[$ctx,#24]
67962306a36Sopenharmony_ci	ldr	$t1,[sp,#0]
68062306a36Sopenharmony_ci	mov	$t2,wzr
68162306a36Sopenharmony_ci	eor	$t3,$B,$C
68262306a36Sopenharmony_ci	mov	$t4,wzr
68362306a36Sopenharmony_ci	b	.L_00_48
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci.align	4
68662306a36Sopenharmony_ci.L_00_48:
68762306a36Sopenharmony_ci___
68862306a36Sopenharmony_ci	&Xupdate(\&body_00_15);
68962306a36Sopenharmony_ci	&Xupdate(\&body_00_15);
69062306a36Sopenharmony_ci	&Xupdate(\&body_00_15);
69162306a36Sopenharmony_ci	&Xupdate(\&body_00_15);
69262306a36Sopenharmony_ci$code.=<<___;
69362306a36Sopenharmony_ci	cmp	$t1,#0				// check for K256 terminator
69462306a36Sopenharmony_ci	ldr	$t1,[sp,#0]
69562306a36Sopenharmony_ci	sub	$Xfer,$Xfer,#64
69662306a36Sopenharmony_ci	bne	.L_00_48
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	sub	$Ktbl,$Ktbl,#256		// rewind $Ktbl
69962306a36Sopenharmony_ci	cmp	$inp,$num
70062306a36Sopenharmony_ci	mov	$Xfer, #64
70162306a36Sopenharmony_ci	csel	$Xfer, $Xfer, xzr, eq
70262306a36Sopenharmony_ci	sub	$inp,$inp,$Xfer			// avoid SEGV
70362306a36Sopenharmony_ci	mov	$Xfer,sp
70462306a36Sopenharmony_ci___
70562306a36Sopenharmony_ci	&Xpreload(\&body_00_15);
70662306a36Sopenharmony_ci	&Xpreload(\&body_00_15);
70762306a36Sopenharmony_ci	&Xpreload(\&body_00_15);
70862306a36Sopenharmony_ci	&Xpreload(\&body_00_15);
70962306a36Sopenharmony_ci$code.=<<___;
71062306a36Sopenharmony_ci	add	$A,$A,$t4			// h+=Sigma0(a) from the past
71162306a36Sopenharmony_ci	ldp	$t0,$t1,[$ctx,#0]
71262306a36Sopenharmony_ci	add	$A,$A,$t2			// h+=Maj(a,b,c) from the past
71362306a36Sopenharmony_ci	ldp	$t2,$t3,[$ctx,#8]
71462306a36Sopenharmony_ci	add	$A,$A,$t0			// accumulate
71562306a36Sopenharmony_ci	add	$B,$B,$t1
71662306a36Sopenharmony_ci	ldp	$t0,$t1,[$ctx,#16]
71762306a36Sopenharmony_ci	add	$C,$C,$t2
71862306a36Sopenharmony_ci	add	$D,$D,$t3
71962306a36Sopenharmony_ci	ldp	$t2,$t3,[$ctx,#24]
72062306a36Sopenharmony_ci	add	$E,$E,$t0
72162306a36Sopenharmony_ci	add	$F,$F,$t1
72262306a36Sopenharmony_ci	 ldr	$t1,[sp,#0]
72362306a36Sopenharmony_ci	stp	$A,$B,[$ctx,#0]
72462306a36Sopenharmony_ci	add	$G,$G,$t2
72562306a36Sopenharmony_ci	 mov	$t2,wzr
72662306a36Sopenharmony_ci	stp	$C,$D,[$ctx,#8]
72762306a36Sopenharmony_ci	add	$H,$H,$t3
72862306a36Sopenharmony_ci	stp	$E,$F,[$ctx,#16]
72962306a36Sopenharmony_ci	 eor	$t3,$B,$C
73062306a36Sopenharmony_ci	stp	$G,$H,[$ctx,#24]
73162306a36Sopenharmony_ci	 mov	$t4,wzr
73262306a36Sopenharmony_ci	 mov	$Xfer,sp
73362306a36Sopenharmony_ci	b.ne	.L_00_48
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	ldr	x29,[x29]
73662306a36Sopenharmony_ci	add	sp,sp,#16*4+16
73762306a36Sopenharmony_ci	ret
73862306a36Sopenharmony_ci.size	sha256_block_neon,.-sha256_block_neon
73962306a36Sopenharmony_ci___
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci$code.=<<___;
74362306a36Sopenharmony_ci#ifndef	__KERNEL__
74462306a36Sopenharmony_ci.comm	OPENSSL_armcap_P,4,4
74562306a36Sopenharmony_ci#endif
74662306a36Sopenharmony_ci___
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci{   my  %opcode = (
74962306a36Sopenharmony_ci	"sha256h"	=> 0x5e004000,	"sha256h2"	=> 0x5e005000,
75062306a36Sopenharmony_ci	"sha256su0"	=> 0x5e282800,	"sha256su1"	=> 0x5e006000	);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci    sub unsha256 {
75362306a36Sopenharmony_ci	my ($mnemonic,$arg)=@_;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	$arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o
75662306a36Sopenharmony_ci	&&
75762306a36Sopenharmony_ci	sprintf ".inst\t0x%08x\t//%s %s",
75862306a36Sopenharmony_ci			$opcode{$mnemonic}|$1|($2<<5)|($3<<16),
75962306a36Sopenharmony_ci			$mnemonic,$arg;
76062306a36Sopenharmony_ci    }
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ciopen SELF,$0;
76462306a36Sopenharmony_ciwhile(<SELF>) {
76562306a36Sopenharmony_ci        next if (/^#!/);
76662306a36Sopenharmony_ci        last if (!s/^#/\/\// and !/^$/);
76762306a36Sopenharmony_ci        print;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ciclose SELF;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ciforeach(split("\n",$code)) {
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	s/\`([^\`]*)\`/eval($1)/ge;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	s/\b(sha256\w+)\s+([qv].*)/unsha256($1,$2)/ge;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	s/\bq([0-9]+)\b/v$1.16b/g;		# old->new registers
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	s/\.[ui]?8(\s)/$1/;
78062306a36Sopenharmony_ci	s/\.\w?32\b//		and s/\.16b/\.4s/g;
78162306a36Sopenharmony_ci	m/(ld|st)1[^\[]+\[0\]/	and s/\.4s/\.s/g;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	print $_,"\n";
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ciclose STDOUT;
787