1/* mpn_add_n -- add (or subtract) bignums.
2   Copyright (C) 2013-2022 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library.  If not, see
17   <https://www.gnu.org/licenses/>.  */
18
19#include <sysdep.h>
20#include <arm-features.h>
21
22	.syntax unified
23	.text
24
25#ifdef USE_AS_SUB_N
26# define INITC	cmp r0, r0
27# define OPC	sbcs
28# define RETC	sbc r0, r0, r0; neg r0, r0
29# define FUNC	__mpn_sub_n
30#else
31# define INITC	cmn r0, #0
32# define OPC	adcs
33# define RETC	mov r0, #0; adc r0, r0, r0
34# define FUNC	__mpn_add_n
35#endif
36
37/* mp_limb_t mpn_add_n(res_ptr, src1_ptr, src2_ptr, size) */
38
39ENTRY (FUNC)
40	push	{ r4, r5, r6, r7, r8, r10, lr }
41	cfi_adjust_cfa_offset (28)
42	cfi_rel_offset (r4, 0)
43	cfi_rel_offset (r5, 4)
44	cfi_rel_offset (r6, 8)
45	cfi_rel_offset (r7, 12)
46	cfi_rel_offset (r8, 16)
47	cfi_rel_offset (r10, 20)
48	cfi_rel_offset (lr, 24)
49
50	INITC				/* initialize carry flag */
51	tst	r3, #1			/* count & 1 == 1? */
52	add	lr, r1, r3, lsl #2	/* compute end src1 */
53	beq	1f
54
55	ldr	r4, [r1], #4		/* do one to make count even */
56	ldr	r5, [r2], #4
57	OPC	r4, r4, r5
58	teq	r1, lr			/* end of count? (preserve carry) */
59	str	r4, [r0], #4
60	beq	9f
611:
62	tst	r3, #2			/* count & 2 == 2?  */
63	beq	2f
64	ldm	r1!, { r4, r5 }		/* do two to make count 0 mod 4 */
65	ldm	r2!, { r6, r7 }
66	OPC	r4, r4, r6
67	OPC	r5, r5, r7
68	teq	r1, lr			/* end of count? */
69	stm	r0!, { r4, r5 }
70	beq	9f
712:
72	ldm	r1!, { r3, r5, r7, r10 }	/* do four each loop */
73	ldm	r2!, { r4, r6, r8, ip }
74	OPC	r3, r3, r4
75	OPC	r5, r5, r6
76	OPC	r7, r7, r8
77	OPC	r10, r10, ip
78	teq	r1, lr
79	stm	r0!, { r3, r5, r7, r10 }
80	bne	2b
81
829:
83	RETC				/* copy carry out */
84#ifndef ARM_ALWAYS_BX
85	pop	{ r4, r5, r6, r7, r8, r10, pc }
86#else
87	pop	{ r4, r5, r6, r7, r8, r10, lr }
88	bx	lr
89#endif
90END (FUNC)
91