summary refs log tree commit diff
path: root/sysdeps/powerpc/powerpc32/lshift.S
blob: 9f5870d828c372536d1bb8df422648a8a817c44a (plain) (blame)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* Shift a limb left, low level routine.
   Copyright (C) 1996, 1997, 1999, 2000 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, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <sysdep.h>
#include <bp-sym.h>
#include <bp-asm.h>

/* mp_limb_t mpn_lshift (mp_ptr wp, mp_srcptr up, mp_size_t usize,
  			 unsigned int cnt)  */

EALIGN (BP_SYM (__mpn_lshift), 3, 0)

#if __BOUNDED_POINTERS__
	slwi r10,r5,2		/* convert limbs to bytes */
	CHECK_BOUNDS_BOTH_WIDE (r3, r8, r9, r10)
	CHECK_BOUNDS_BOTH_WIDE (r4, r8, r9, r10)
#endif
	mtctr	r5		# copy size into CTR
	cmplwi	cr0,r5,16	# is size < 16
	slwi	r0,r5,2
	add	r7,r3,r0	# make r7 point at end of res
	add	r4,r4,r0	# make r4 point at end of s1
	lwzu	r11,-4(r4)	# load first s1 limb
	subfic	r8,r6,32
	srw	r3,r11,r8	# compute function return value
	bge	cr0,L(big)	# branch if size >= 16

	bdz	L(end1)

L(0):	lwzu	r10,-4(r4)
	slw	r9,r11,r6
	srw	r12,r10,r8
	or	r9,r9,r12
	stwu	r9,-4(r7)
	bdz	L(end2)
	lwzu	r11,-4(r4)
	slw	r9,r10,r6
	srw	r12,r11,r8
	or	r9,r9,r12
	stwu	r9,-4(r7)
	bdnz	L(0)

L(end1):slw	r0,r11,r6
	stw	r0,-4(r7)
	blr


/* Guaranteed not to succeed.  */
L(boom): tweq    r0,r0

/* We imitate a case statement, by using (yuk!) fixed-length code chunks,
   of size 4*12 bytes.  We have to do this (or something) to make this PIC.  */
L(big):	mflr    r9
	bltl-   cr0,L(boom)	# Never taken, only used to set LR.
	slwi    r10,r6,4
	mflr    r12
	add     r10,r12,r10
	slwi	r8,r6,5
	add     r10,r8,r10
	mtctr   r10
	addi	r5,r5,-1
	mtlr    r9
	bctr

L(end2):slw	r0,r10,r6
	stw	r0,-4(r7)
	blr

#define DO_LSHIFT(n) \
	mtctr	r5;							\
L(n):	lwzu	r10,-4(r4);						\
	slwi	r9,r11,n;						\
	inslwi	r9,r10,n,32-n;					\
	stwu	r9,-4(r7);						\
	bdz-	L(end2);						\
	lwzu	r11,-4(r4);						\
	slwi	r9,r10,n;						\
	inslwi	r9,r11,n,32-n;					\
	stwu	r9,-4(r7);						\
	bdnz	L(n);							\
	b	L(end1)

	DO_LSHIFT(1)
	DO_LSHIFT(2)
	DO_LSHIFT(3)
	DO_LSHIFT(4)
	DO_LSHIFT(5)
	DO_LSHIFT(6)
	DO_LSHIFT(7)
	DO_LSHIFT(8)
	DO_LSHIFT(9)
	DO_LSHIFT(10)
	DO_LSHIFT(11)
	DO_LSHIFT(12)
	DO_LSHIFT(13)
	DO_LSHIFT(14)
	DO_LSHIFT(15)
	DO_LSHIFT(16)
	DO_LSHIFT(17)
	DO_LSHIFT(18)
	DO_LSHIFT(19)
	DO_LSHIFT(20)
	DO_LSHIFT(21)
	DO_LSHIFT(22)
	DO_LSHIFT(23)
	DO_LSHIFT(24)
	DO_LSHIFT(25)
	DO_LSHIFT(26)
	DO_LSHIFT(27)
	DO_LSHIFT(28)
	DO_LSHIFT(29)
	DO_LSHIFT(30)
	DO_LSHIFT(31)

END (BP_SYM (__mpn_lshift))