#!/usr/bin/env perl
# Copyright 2023 The BoringSSL Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

use strict;

my $flavour = shift;
my $output  = shift;
if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }

$0 =~ m/(.*[\/\\])[^\/\\]+$/;
my $dir = $1;
my $xlate;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";

open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT = *OUT;

my ($rp, $ap, $bp, $num) = ("x0", "x1", "x2", "x3");
my ($a0, $a1, $b0, $b1, $num_pairs) = ("x4", "x5", "x6", "x7", "x8");
my $code = <<____;
.text

// BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
//                       size_t num);
.type	bn_add_words, %function
.globl	bn_add_words
.align	4
bn_add_words:
	AARCH64_VALID_CALL_TARGET
	# Clear the carry flag.
	cmn	xzr, xzr

	# aarch64 can load two registers at a time, so we do two loop iterations at
	# at a time. Split $num = 2 * $num_pairs + $num. This allows loop
	# operations to use CBNZ without clobbering the carry flag.
	lsr	$num_pairs, $num, #1
	and	$num, $num, #1

	cbz	$num_pairs, .Ladd_tail
.Ladd_loop:
	ldp	$a0, $a1, [$ap], #16
	ldp	$b0, $b1, [$bp], #16
	sub	$num_pairs, $num_pairs, #1
	adcs	$a0, $a0, $b0
	adcs	$a1, $a1, $b1
	stp	$a0, $a1, [$rp], #16
	cbnz	$num_pairs, .Ladd_loop

.Ladd_tail:
	cbz	$num, .Ladd_exit
	ldr	$a0, [$ap], #8
	ldr	$b0, [$bp], #8
	adcs	$a0, $a0, $b0
	str	$a0, [$rp], #8

.Ladd_exit:
	cset	x0, cs
	ret
.size	bn_add_words,.-bn_add_words

// BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
//                       size_t num);
.type	bn_sub_words, %function
.globl	bn_sub_words
.align	4
bn_sub_words:
	AARCH64_VALID_CALL_TARGET
	# Set the carry flag. Arm's borrow bit is flipped from the carry flag,
	# so we want C = 1 here.
	cmp	xzr, xzr

	# aarch64 can load two registers at a time, so we do two loop iterations at
	# at a time. Split $num = 2 * $num_pairs + $num. This allows loop
	# operations to use CBNZ without clobbering the carry flag.
	lsr	$num_pairs, $num, #1
	and	$num, $num, #1

	cbz	$num_pairs, .Lsub_tail
.Lsub_loop:
	ldp	$a0, $a1, [$ap], #16
	ldp	$b0, $b1, [$bp], #16
	sub	$num_pairs, $num_pairs, #1
	sbcs	$a0, $a0, $b0
	sbcs	$a1, $a1, $b1
	stp	$a0, $a1, [$rp], #16
	cbnz	$num_pairs, .Lsub_loop

.Lsub_tail:
	cbz	$num, .Lsub_exit
	ldr	$a0, [$ap], #8
	ldr	$b0, [$bp], #8
	sbcs	$a0, $a0, $b0
	str	$a0, [$rp], #8

.Lsub_exit:
	cset x0, cc
	ret
size	bn_sub_words,.-bn_sub_words
____

print $code;
close STDOUT or die "error closing STDOUT: $!";
