summary refs log tree commit diff
path: root/sysdeps/sparc/add_n.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/sparc/add_n.S')
-rw-r--r--sysdeps/sparc/add_n.S304
1 files changed, 194 insertions, 110 deletions
diff --git a/sysdeps/sparc/add_n.S b/sysdeps/sparc/add_n.S
index 13704d32d2..80c3b99640 100644
--- a/sysdeps/sparc/add_n.S
+++ b/sysdeps/sparc/add_n.S
@@ -1,7 +1,7 @@
 ! sparc __mpn_add_n -- Add two limb vectors of the same length > 0 and store
 ! sum in a third limb vector.
 
-! Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+! Copyright (C) 1995 Free Software Foundation, Inc.
 
 ! This file is part of the GNU MP Library.
 
@@ -21,10 +21,10 @@
 
 
 ! INPUT PARAMETERS
-! res_ptr	%o0
-! s1_ptr	%o1
-! s2_ptr	%o2
-! size		%o3
+#define res_ptr	%o0
+#define s1_ptr	%o1
+#define s2_ptr	%o2
+#define size	%o3
 
 #include "sysdep.h"
 
@@ -32,108 +32,192 @@
 	.align	4
 	.global	C_SYMBOL_NAME(__mpn_add_n)
 C_SYMBOL_NAME(__mpn_add_n):
-	ld	[%o1+0],%o4		! read first limb from s1_ptr
-	srl	%o3,4,%g1
-	ld	[%o2+0],%o5		! read first limb from s2_ptr
-
-	sub	%g0,%o3,%o3
-	andcc	%o3,(16-1),%o3
-	be	Lzero
-	 mov	%o4,%g2			! put first s1_limb in g2 too
-
-	sll	%o3,2,%o3		! multiply by 4
-	sub	%o0,%o3,%o0		! adjust res_ptr
-	sub	%o1,%o3,%o1		! adjust s1_ptr
-	sub	%o2,%o3,%o2		! adjust s2_ptr
-
-#if PIC
-	mov	%o7,%g4			! Save return address register
-	call	1f
-	add	%o7,Lbase-1f,%g3
-1:	mov	%g4,%o7			! Restore return address register
-#else
-	sethi	%hi(Lbase),%g3
-	or	%g3,%lo(Lbase),%g3
-#endif
-	sll	%o3,2,%o3		! multiply by 4
-	jmp	%g3+%o3
-	 mov	%o5,%g3			! put first s2_limb in g3 too
-
-Loop:	addxcc	%g2,%g3,%o3
-	add	%o1,64,%o1
-	st	%o3,[%o0+60]
-	add	%o2,64,%o2
-	ld	[%o1+0],%o4
-	add	%o0,64,%o0
-	ld	[%o2+0],%o5
-Lzero:	sub	%g1,1,%g1	! add 0 + 16r limbs (adjust loop counter)
-Lbase:	ld	[%o1+4],%g2
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+4],%g3
-	st	%o3,[%o0+0]
-	ld	[%o1+8],%o4	! add 15 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+8],%o5
-	st	%o3,[%o0+4]
-	ld	[%o1+12],%g2	! add 14 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+12],%g3
-	st	%o3,[%o0+8]
-	ld	[%o1+16],%o4	! add 13 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+16],%o5
-	st	%o3,[%o0+12]
-	ld	[%o1+20],%g2	! add 12 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+20],%g3
-	st	%o3,[%o0+16]
-	ld	[%o1+24],%o4	! add 11 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+24],%o5
-	st	%o3,[%o0+20]
-	ld	[%o1+28],%g2	! add 10 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+28],%g3
-	st	%o3,[%o0+24]
-	ld	[%o1+32],%o4	! add 9 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+32],%o5
-	st	%o3,[%o0+28]
-	ld	[%o1+36],%g2	! add 8 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+36],%g3
-	st	%o3,[%o0+32]
-	ld	[%o1+40],%o4	! add 7 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+40],%o5
-	st	%o3,[%o0+36]
-	ld	[%o1+44],%g2	! add 6 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+44],%g3
-	st	%o3,[%o0+40]
-	ld	[%o1+48],%o4	! add 5 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+48],%o5
-	st	%o3,[%o0+44]
-	ld	[%o1+52],%g2	! add 4 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+52],%g3
-	st	%o3,[%o0+48]
-	ld	[%o1+56],%o4	! add 3 + 16r limbs
-	addxcc	%g2,%g3,%o3
-	ld	[%o2+56],%o5
-	st	%o3,[%o0+52]
-	ld	[%o1+60],%g2	! add 2 + 16r limbs
-	addxcc	%o4,%o5,%o3
-	ld	[%o2+60],%g3
-	st	%o3,[%o0+56]
-	addx	%g0,%g0,%o4
-	tst	%g1
-	bne	Loop
-	 subcc	%g0,%o4,%g0	! restore cy (delay slot)
-
-	addxcc	%g2,%g3,%o3
-	st	%o3,[%o0+60]	! store most significant limb
-
-	retl
-	 addx	%g0,%g0,%o0	! return carry-out from most sign. limb
+	cmp	size,8
+	mov	0,%o4			! clear cy-save register
+	blt,a	Ltriv
+	addcc	size,-2,size
+	xor	s2_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L1			! branch if alignment differs
+	nop
+L0:	andcc	res_ptr,4,%g0		! res_ptr unaligned? Side effect: cy=0
+	beq	L_v1			! if no, branch
+	nop
+! **  V1a  **
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	size,-1,size
+	addcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+
+L_v1:	ld	[s1_ptr+0],%g4
+	ld	[s1_ptr+4],%g1
+	ldd	[s2_ptr+0],%g2
+	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-10,size
+	blt	Lfin1
+	subcc	%g0,%o4,%g0		! restore cy
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+Loop1:	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+16],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+20],%g1
+	ldd	[s2_ptr+16],%g2
+	std	%o4,[res_ptr+8]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+24],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+28],%g1
+	ldd	[s2_ptr+24],%g2
+	std	%o4,[res_ptr+16]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+32],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+36],%g1
+	ldd	[s2_ptr+32],%g2
+	std	%o4,[res_ptr+24]
+	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-8,size
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	Loop1
+	subcc	%g0,%o4,%g0		! restore cy
+
+Lfin1:	addcc	size,8-2,size
+	blt	Lend1
+	subcc	%g0,%o4,%g0		! restore cy
+/* Add blocks of 2 limbs until less than 2 limbs remain */
+Loop1b:	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-2,size
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	Loop1b
+	subcc	%g0,%o4,%g0		! restore cy
+Lend1:	addxcc	%g4,%g2,%o4
+	addxcc	%g1,%g3,%o5
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		! save cy in register
+
+	andcc	size,1,%g0
+	be	Lret1
+	subcc	%g0,%o4,%g0		! restore cy
+/* Add last limb */
+	ld	[s1_ptr+8],%g4
+	ld	[s2_ptr+8],%g2
+	addxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr+8]
+
+Lret1:	retl
+	addx	%g0,%g0,%o0	! return carry-out from most sign. limb
+
+L1:	xor	s1_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L2
+	nop
+! **  V1b  **
+	mov	s2_ptr,%g1
+	mov	s1_ptr,s2_ptr
+	b	L0
+	mov	%g1,s1_ptr
+
+! **  V2  **
+/* If we come here, the alignment of s1_ptr and res_ptr as well as the
+   alignment of s2_ptr and res_ptr differ.  Since there are only two ways
+   things can be aligned (that we care about) we now know that the alignment
+   of s1_ptr and s2_ptr are the same.  */
+
+L2:	andcc	s1_ptr,4,%g0		! s1_ptr unaligned? Side effect: cy=0
+	beq	L_v2			! if no, branch
+	nop
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	size,-1,size
+	addcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+
+L_v2:	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-8,size
+	blt	Lfin2
+	subcc	%g0,%o4,%g0		! restore cy
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+Loop2:	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	ldd	[s1_ptr+8],%g2
+	ldd	[s2_ptr+8],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+8]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+12]
+	ldd	[s1_ptr+16],%g2
+	ldd	[s2_ptr+16],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+16]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+20]
+	ldd	[s1_ptr+24],%g2
+	ldd	[s2_ptr+24],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+24]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+28]
+	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-8,size
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	Loop2
+	subcc	%g0,%o4,%g0		! restore cy
+
+Lfin2:	addcc	size,8-2,size
+Ltriv:	blt	Lend2
+	subcc	%g0,%o4,%g0		! restore cy
+Loop2b:	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	addx	%g0,%g0,%o4		! save cy in register
+	addcc	size,-2,size
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	Loop2b
+	subcc	%g0,%o4,%g0		! restore cy
+Lend2:	andcc	size,1,%g0
+	be	Lret2
+	subcc	%g0,%o4,%g0		! restore cy
+/* Add last limb */
+	ld	[s1_ptr],%g4
+	ld	[s2_ptr],%g2
+	addxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+
+Lret2:	retl
+	addx	%g0,%g0,%o0	! return carry-out from most sign. limb