aboutsummaryrefslogtreecommitdiff
path: root/ports/sysdeps/arm/add_n.S
blob: c6b01479723f27407069e905c82ee82bb931ee76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* mpn_add_n -- add (or subtract) bignums.
   Copyright (C) 2013 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library.  If not, see
   <http://www.gnu.org/licenses/>.  */

#include <sysdep.h>
#include <arm-features.h>

	.syntax unified
	.text

#ifdef USE_AS_SUB_N
# define INITC	cmp r0, r0
# define OPC	sbcs
# define RETC	sbc r0, r0, r0; neg r0, r0
# define FUNC	__mpn_sub_n
#else
# define INITC	cmn r0, #0
# define OPC	adcs
# define RETC	mov r0, #0; adc r0, r0, r0
# define FUNC	__mpn_add_n
#endif

/* mp_limb_t mpn_add_n(res_ptr, src1_ptr, src2_ptr, size) */

ENTRY (FUNC)
	push	{ r4, r5, r6, r7, r8, r10, lr }
	cfi_adjust_cfa_offset (28)
	cfi_rel_offset (r4, 0)
	cfi_rel_offset (r5, 4)
	cfi_rel_offset (r6, 8)
	cfi_rel_offset (r7, 12)
	cfi_rel_offset (r8, 16)
	cfi_rel_offset (r10, 20)
	cfi_rel_offset (lr, 24)

	INITC				/* initialize carry flag */
	tst	r3, #1			/* count & 1 == 1? */
	add	lr, r1, r3, lsl #2	/* compute end src1 */
	beq	1f

	sfi_breg r1, \
	ldr	r4, [\B], #4		/* do one to make count even */
	sfi_breg r2, \
	ldr	r5, [\B], #4
	OPC	r4, r4, r5
	teq	r1, lr			/* end of count? (preserve carry) */
	sfi_breg r0, \
	str	r4, [\B], #4
	beq	9f
1:
	tst	r3, #2			/* count & 2 == 2?  */
	beq	2f
	sfi_breg r1, \
	ldm	\B!, { r4, r5 }		/* do two to make count 0 mod 4 */
	sfi_breg r2, \
	ldm	\B!, { r6, r7 }
	OPC	r4, r4, r6
	OPC	r5, r5, r7
	teq	r1, lr			/* end of count? */
	sfi_breg r0, \
	stm	\B!, { r4, r5 }
	beq	9f
2:
	sfi_breg r1, \
	ldm	\B!, { r3, r5, r7, r10 }	/* do four each loop */
	sfi_breg r2, \
	ldm	\B!, { r4, r6, r8, ip }
	OPC	r3, r3, r4
	OPC	r5, r5, r6
	OPC	r7, r7, r8
	OPC	r10, r10, ip
	teq	r1, lr
	sfi_breg r0, \
	stm	\B!, { r3, r5, r7, r10 }
	bne	2b

9:
	RETC				/* copy carry out */
#ifndef ARM_ALWAYS_BX
	pop	{ r4, r5, r6, r7, r8, r10, pc }
#else
	pop	{ r4, r5, r6, r7, r8, r10, lr }
	bx	lr
#endif
END (FUNC)