rind 0.1.12

Pure-Rust cryptography for MoQ, forked from graviola
Documentation
// Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Generated by admin/import-aws-lc from aws-lc 91c93a8eb860e51482a871a8772cb9b1b310baea:
// generated-src/linux-aarch64/crypto/fipsmodule/ghash-neon-armv8.S, which aws-lc generates from crypto/fipsmodule/modes/asm/ghash-neon-armv8.pl.
// Do not edit by hand.
.align	4
	
	ld1	{{v0.16b}}, [x0]		// load Xi
	ld1	{{v5.1d}}, [x1], #8		// load twisted H
	ld1	{{v6.1d}}, [x1]
	adrp	x9, {masks}		// load constants
	add	x9, x9, :lo12:{masks}
	ld1	{{v24.2d, v25.2d}}, [x9]
	rev64	v0.16b, v0.16b		// byteswap Xi
	ext	v0.16b, v0.16b, v0.16b, #8
	eor	v7.8b, v5.8b, v6.8b	// Karatsuba pre-processing

.Lghash_oop_neon:
	ld1	{{v3.16b}}, [x2], #16	// load inp
	rev64	v3.16b, v3.16b		// byteswap inp
	ext	v3.16b, v3.16b, v3.16b, #8
	eor	v3.16b, v3.16b, v0.16b	// inp ^= Xi

.Lghash_gmult_neon:
	// Split the input into v3 and v4. (The upper halves are unused,
	// so it is okay to leave them alone.)
	ins	v4.d[0], v3.d[1]
	ext	v16.8b, v5.8b, v5.8b, #1	// A1
	pmull	v16.8h, v16.8b, v3.8b		// F = A1*B
	ext	v0.8b, v3.8b, v3.8b, #1		// B1
	pmull	v0.8h, v5.8b, v0.8b		// E = A*B1
	ext	v17.8b, v5.8b, v5.8b, #2	// A2
	pmull	v17.8h, v17.8b, v3.8b		// H = A2*B
	ext	v19.8b, v3.8b, v3.8b, #2	// B2
	pmull	v19.8h, v5.8b, v19.8b		// G = A*B2
	ext	v18.8b, v5.8b, v5.8b, #3	// A3
	eor	v16.16b, v16.16b, v0.16b	// L = E + F
	pmull	v18.8h, v18.8b, v3.8b		// J = A3*B
	ext	v0.8b, v3.8b, v3.8b, #3		// B3
	eor	v17.16b, v17.16b, v19.16b	// M = G + H
	pmull	v0.8h, v5.8b, v0.8b		// I = A*B3

	// Here we diverge from the 32-bit version. It computes the following
	// (instructions reordered for clarity):
	//
	//     veor	$t0#lo, $t0#lo, $t0#hi	@ t0 = P0 + P1 (L)
	//     vand	$t0#hi, $t0#hi, $k48
	//     veor	$t0#lo, $t0#lo, $t0#hi
	//
	//     veor	$t1#lo, $t1#lo, $t1#hi	@ t1 = P2 + P3 (M)
	//     vand	$t1#hi, $t1#hi, $k32
	//     veor	$t1#lo, $t1#lo, $t1#hi
	//
	//     veor	$t2#lo, $t2#lo, $t2#hi	@ t2 = P4 + P5 (N)
	//     vand	$t2#hi, $t2#hi, $k16
	//     veor	$t2#lo, $t2#lo, $t2#hi
	//
	//     veor	$t3#lo, $t3#lo, $t3#hi	@ t3 = P6 + P7 (K)
	//     vmov.i64	$t3#hi, #0
	//
	// $kN is a mask with the bottom N bits set. AArch64 cannot compute on
	// upper halves of SIMD registers, so we must split each half into
	// separate registers. To compensate, we pair computations up and
	// parallelize.

	ext	v19.8b, v3.8b, v3.8b, #4	// B4
	eor	v18.16b, v18.16b, v0.16b	// N = I + J
	pmull	v19.8h, v5.8b, v19.8b		// K = A*B4

	// This can probably be scheduled more efficiently. For now, we just
	// pair up independent instructions.
	zip1	v20.2d, v16.2d, v17.2d
	zip1	v22.2d, v18.2d, v19.2d
	zip2	v21.2d, v16.2d, v17.2d
	zip2	v23.2d, v18.2d, v19.2d
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	and	v21.16b, v21.16b, v24.16b
	and	v23.16b, v23.16b, v25.16b
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	zip1	v16.2d, v20.2d, v21.2d
	zip1	v18.2d, v22.2d, v23.2d
	zip2	v17.2d, v20.2d, v21.2d
	zip2	v19.2d, v22.2d, v23.2d

	ext	v16.16b, v16.16b, v16.16b, #15	// t0 = t0 << 8
	ext	v17.16b, v17.16b, v17.16b, #14	// t1 = t1 << 16
	pmull	v0.8h, v5.8b, v3.8b		// D = A*B
	ext	v19.16b, v19.16b, v19.16b, #12	// t3 = t3 << 32
	ext	v18.16b, v18.16b, v18.16b, #13	// t2 = t2 << 24
	eor	v16.16b, v16.16b, v17.16b
	eor	v18.16b, v18.16b, v19.16b
	eor	v0.16b, v0.16b, v16.16b
	eor	v0.16b, v0.16b, v18.16b
	eor	v3.8b, v3.8b, v4.8b	// Karatsuba pre-processing
	ext	v16.8b, v7.8b, v7.8b, #1	// A1
	pmull	v16.8h, v16.8b, v3.8b		// F = A1*B
	ext	v1.8b, v3.8b, v3.8b, #1		// B1
	pmull	v1.8h, v7.8b, v1.8b		// E = A*B1
	ext	v17.8b, v7.8b, v7.8b, #2	// A2
	pmull	v17.8h, v17.8b, v3.8b		// H = A2*B
	ext	v19.8b, v3.8b, v3.8b, #2	// B2
	pmull	v19.8h, v7.8b, v19.8b		// G = A*B2
	ext	v18.8b, v7.8b, v7.8b, #3	// A3
	eor	v16.16b, v16.16b, v1.16b	// L = E + F
	pmull	v18.8h, v18.8b, v3.8b		// J = A3*B
	ext	v1.8b, v3.8b, v3.8b, #3		// B3
	eor	v17.16b, v17.16b, v19.16b	// M = G + H
	pmull	v1.8h, v7.8b, v1.8b		// I = A*B3

	// Here we diverge from the 32-bit version. It computes the following
	// (instructions reordered for clarity):
	//
	//     veor	$t0#lo, $t0#lo, $t0#hi	@ t0 = P0 + P1 (L)
	//     vand	$t0#hi, $t0#hi, $k48
	//     veor	$t0#lo, $t0#lo, $t0#hi
	//
	//     veor	$t1#lo, $t1#lo, $t1#hi	@ t1 = P2 + P3 (M)
	//     vand	$t1#hi, $t1#hi, $k32
	//     veor	$t1#lo, $t1#lo, $t1#hi
	//
	//     veor	$t2#lo, $t2#lo, $t2#hi	@ t2 = P4 + P5 (N)
	//     vand	$t2#hi, $t2#hi, $k16
	//     veor	$t2#lo, $t2#lo, $t2#hi
	//
	//     veor	$t3#lo, $t3#lo, $t3#hi	@ t3 = P6 + P7 (K)
	//     vmov.i64	$t3#hi, #0
	//
	// $kN is a mask with the bottom N bits set. AArch64 cannot compute on
	// upper halves of SIMD registers, so we must split each half into
	// separate registers. To compensate, we pair computations up and
	// parallelize.

	ext	v19.8b, v3.8b, v3.8b, #4	// B4
	eor	v18.16b, v18.16b, v1.16b	// N = I + J
	pmull	v19.8h, v7.8b, v19.8b		// K = A*B4

	// This can probably be scheduled more efficiently. For now, we just
	// pair up independent instructions.
	zip1	v20.2d, v16.2d, v17.2d
	zip1	v22.2d, v18.2d, v19.2d
	zip2	v21.2d, v16.2d, v17.2d
	zip2	v23.2d, v18.2d, v19.2d
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	and	v21.16b, v21.16b, v24.16b
	and	v23.16b, v23.16b, v25.16b
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	zip1	v16.2d, v20.2d, v21.2d
	zip1	v18.2d, v22.2d, v23.2d
	zip2	v17.2d, v20.2d, v21.2d
	zip2	v19.2d, v22.2d, v23.2d

	ext	v16.16b, v16.16b, v16.16b, #15	// t0 = t0 << 8
	ext	v17.16b, v17.16b, v17.16b, #14	// t1 = t1 << 16
	pmull	v1.8h, v7.8b, v3.8b		// D = A*B
	ext	v19.16b, v19.16b, v19.16b, #12	// t3 = t3 << 32
	ext	v18.16b, v18.16b, v18.16b, #13	// t2 = t2 << 24
	eor	v16.16b, v16.16b, v17.16b
	eor	v18.16b, v18.16b, v19.16b
	eor	v1.16b, v1.16b, v16.16b
	eor	v1.16b, v1.16b, v18.16b
	ext	v16.8b, v6.8b, v6.8b, #1	// A1
	pmull	v16.8h, v16.8b, v4.8b		// F = A1*B
	ext	v2.8b, v4.8b, v4.8b, #1		// B1
	pmull	v2.8h, v6.8b, v2.8b		// E = A*B1
	ext	v17.8b, v6.8b, v6.8b, #2	// A2
	pmull	v17.8h, v17.8b, v4.8b		// H = A2*B
	ext	v19.8b, v4.8b, v4.8b, #2	// B2
	pmull	v19.8h, v6.8b, v19.8b		// G = A*B2
	ext	v18.8b, v6.8b, v6.8b, #3	// A3
	eor	v16.16b, v16.16b, v2.16b	// L = E + F
	pmull	v18.8h, v18.8b, v4.8b		// J = A3*B
	ext	v2.8b, v4.8b, v4.8b, #3		// B3
	eor	v17.16b, v17.16b, v19.16b	// M = G + H
	pmull	v2.8h, v6.8b, v2.8b		// I = A*B3

	// Here we diverge from the 32-bit version. It computes the following
	// (instructions reordered for clarity):
	//
	//     veor	$t0#lo, $t0#lo, $t0#hi	@ t0 = P0 + P1 (L)
	//     vand	$t0#hi, $t0#hi, $k48
	//     veor	$t0#lo, $t0#lo, $t0#hi
	//
	//     veor	$t1#lo, $t1#lo, $t1#hi	@ t1 = P2 + P3 (M)
	//     vand	$t1#hi, $t1#hi, $k32
	//     veor	$t1#lo, $t1#lo, $t1#hi
	//
	//     veor	$t2#lo, $t2#lo, $t2#hi	@ t2 = P4 + P5 (N)
	//     vand	$t2#hi, $t2#hi, $k16
	//     veor	$t2#lo, $t2#lo, $t2#hi
	//
	//     veor	$t3#lo, $t3#lo, $t3#hi	@ t3 = P6 + P7 (K)
	//     vmov.i64	$t3#hi, #0
	//
	// $kN is a mask with the bottom N bits set. AArch64 cannot compute on
	// upper halves of SIMD registers, so we must split each half into
	// separate registers. To compensate, we pair computations up and
	// parallelize.

	ext	v19.8b, v4.8b, v4.8b, #4	// B4
	eor	v18.16b, v18.16b, v2.16b	// N = I + J
	pmull	v19.8h, v6.8b, v19.8b		// K = A*B4

	// This can probably be scheduled more efficiently. For now, we just
	// pair up independent instructions.
	zip1	v20.2d, v16.2d, v17.2d
	zip1	v22.2d, v18.2d, v19.2d
	zip2	v21.2d, v16.2d, v17.2d
	zip2	v23.2d, v18.2d, v19.2d
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	and	v21.16b, v21.16b, v24.16b
	and	v23.16b, v23.16b, v25.16b
	eor	v20.16b, v20.16b, v21.16b
	eor	v22.16b, v22.16b, v23.16b
	zip1	v16.2d, v20.2d, v21.2d
	zip1	v18.2d, v22.2d, v23.2d
	zip2	v17.2d, v20.2d, v21.2d
	zip2	v19.2d, v22.2d, v23.2d

	ext	v16.16b, v16.16b, v16.16b, #15	// t0 = t0 << 8
	ext	v17.16b, v17.16b, v17.16b, #14	// t1 = t1 << 16
	pmull	v2.8h, v6.8b, v4.8b		// D = A*B
	ext	v19.16b, v19.16b, v19.16b, #12	// t3 = t3 << 32
	ext	v18.16b, v18.16b, v18.16b, #13	// t2 = t2 << 24
	eor	v16.16b, v16.16b, v17.16b
	eor	v18.16b, v18.16b, v19.16b
	eor	v2.16b, v2.16b, v16.16b
	eor	v2.16b, v2.16b, v18.16b
	ext	v16.16b, v0.16b, v2.16b, #8
	eor	v1.16b, v1.16b, v0.16b	// Karatsuba post-processing
	eor	v1.16b, v1.16b, v2.16b
	eor	v1.16b, v1.16b, v16.16b	// Xm overlaps Xh.lo and Xl.hi
	ins	v0.d[1], v1.d[0]		// Xh|Xl - 256-bit result
	// This is a no-op due to the ins instruction below.
	// ins	v2.d[0], v1.d[1]

	// equivalent of reduction_avx from ghash-x86_64.pl
	shl	v17.2d, v0.2d, #57		// 1st phase
	shl	v18.2d, v0.2d, #62
	eor	v18.16b, v18.16b, v17.16b	//
	shl	v17.2d, v0.2d, #63
	eor	v18.16b, v18.16b, v17.16b	//
	// Note Xm contains {{Xl.d[1], Xh.d[0]}}.
	eor	v18.16b, v18.16b, v1.16b
	ins	v0.d[1], v18.d[0]		// Xl.d[1] ^= t2.d[0]
	ins	v2.d[0], v18.d[1]		// Xh.d[0] ^= t2.d[1]

	ushr	v18.2d, v0.2d, #1		// 2nd phase
	eor	v2.16b, v2.16b,v0.16b
	eor	v0.16b, v0.16b,v18.16b	//
	ushr	v18.2d, v18.2d, #6
	ushr	v0.2d, v0.2d, #1		//
	eor	v0.16b, v0.16b, v2.16b	//
	eor	v0.16b, v0.16b, v18.16b	//

	subs	x3, x3, #16
	bne	.Lghash_oop_neon

	rev64	v0.16b, v0.16b		// byteswap Xi and write
	ext	v0.16b, v0.16b, v0.16b, #8
	st1	{{v0.16b}}, [x0]

	ret