Initial import from FreeBSD RELENG_4:
[dragonfly.git] / lib / libc / alpha / gen / divrem.m4
1 /*      $NetBSD: divrem.m4,v 1.7 1996/10/17 03:08:04 cgd Exp $  */
2 /* $FreeBSD: src/lib/libc/alpha/gen/divrem.m4,v 1.2.2.1 2000/08/21 21:09:28 jhb Exp $ */
3
4 /*
5  * Copyright (c) 1994, 1995 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Chris G. Demetriou
9  * 
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  * 
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  * 
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30
31 /*
32  * Division and remainder.
33  *
34  * The use of m4 is modeled after the sparc code, but the algorithm is
35  * simple binary long division.
36  *
37  * Note that the loops could probably benefit from unrolling.
38  */
39
40 /*
41  * M4 Parameters
42  * NAME         name of function to generate
43  * OP           OP=div: t10 / t11 -> t12; OP=rem: t10 % t11 -> t12
44  * S            S=true: signed; S=false: unsigned
45  * WORDSIZE     total number of bits
46  */
47
48 define(A, `t10')
49 define(B, `t11')
50 define(RESULT, `t12')
51
52 define(BIT, `t0')
53 define(I, `t1')
54 define(CC, `t2')
55 define(T_0, `t3')
56 ifelse(S, `true', `define(NEG, `t4')')
57
58 #include <machine/asm.h>
59
60 NESTED(NAME, 0, 0, t9, 0, 0)                    /* Get the right ra */
61         lda     sp, -64(sp)
62         stq     BIT, 0(sp)
63         stq     I, 8(sp)
64         stq     CC, 16(sp)
65         stq     T_0, 24(sp)
66 ifelse(S, `true',
67 `       stq     NEG, 32(sp)')
68         stq     A, 40(sp)
69         stq     B, 48(sp)
70         mov     zero, RESULT                    /* Initialize result to zero */
71
72 ifelse(S, `true',
73 `
74         /* Compute sign of result.  If either is negative, this is easy.  */
75         or      A, B, NEG                       /* not the sign, but... */
76         srl     NEG, WORDSIZE - 1, NEG          /* rather, or of high bits */
77         blbc    NEG, Ldoit                      /* neither negative? do it! */
78
79 ifelse(OP, `div',
80 `       xor     A, B, NEG                       /* THIS is the sign! */
81 ', `    mov     A, NEG                          /* sign follows A. */
82 ')
83         srl     NEG, WORDSIZE - 1, NEG          /* make negation the low bit. */
84
85         srl     A, WORDSIZE - 1, I              /* is A negative? */
86         blbc    I, LnegB                        /* no. */
87         /* A is negative; flip it. */
88 ifelse(WORDSIZE, `32', `
89         /* top 32 bits may be random junk */
90         zap     A, 0xf0, A
91 ')
92         subq    zero, A, A
93         srl     B, WORDSIZE - 1, I              /* is B negative? */
94         blbc    I, Ldoit                        /* no. */
95 LnegB:
96         /* B is definitely negative, no matter how we got here. */
97 ifelse(WORDSIZE, `32', `
98         /* top 32 bits may be random junk */
99         zap     B, 0xf0, B
100 ')
101         subq    zero, B, B
102 Ldoit:
103 ')
104 ifelse(WORDSIZE, `32', `
105         /*
106          * Clear the top 32 bits of each operand, as they may
107          * sign extension (if negated above), or random junk.
108          */
109         zap     A, 0xf0, A
110         zap     B, 0xf0, B
111 ')
112
113         /* kill the special cases. */
114         beq     B, Ldotrap                      /* division by zero! */
115
116         cmpult  A, B, CC                        /* A < B? */
117         /* RESULT is already zero, from above.  A is untouched. */
118         bne     CC, Lret_result
119
120         cmpeq   A, B, CC                        /* A == B? */
121         cmovne  CC, 1, RESULT
122         cmovne  CC, zero, A
123         bne     CC, Lret_result
124
125         /*
126          * Find out how many bits of zeros are at the beginning of the divisor.
127          */
128 LBbits:
129         ldiq    T_0, 1                          /* I = 0; BIT = 1<<WORDSIZE-1 */
130         mov     zero, I
131         sll     T_0, WORDSIZE-1, BIT
132 LBloop:
133         and     B, BIT, CC                      /* if bit in B is set, done. */
134         bne     CC, LAbits
135         addq    I, 1, I                         /* increment I, shift bit */
136         srl     BIT, 1, BIT
137         cmplt   I, WORDSIZE-1, CC               /* if I leaves one bit, done. */
138         bne     CC, LBloop
139
140 LAbits:
141         beq     I, Ldodiv                       /* If I = 0, divide now.  */
142         ldiq    T_0, 1                          /* BIT = 1<<WORDSIZE-1 */
143         sll     T_0, WORDSIZE-1, BIT
144
145 LAloop:
146         and     A, BIT, CC                      /* if bit in A is set, done. */
147         bne     CC, Ldodiv
148         subq    I, 1, I                         /* decrement I, shift bit */
149         srl     BIT, 1, BIT 
150         bne     I, LAloop                       /* If I != 0, loop again */
151
152 Ldodiv:
153         sll     B, I, B                         /* B <<= i */
154         ldiq    T_0, 1
155         sll     T_0, I, BIT
156
157 Ldivloop:
158         cmpult  A, B, CC
159         or      RESULT, BIT, T_0
160         cmoveq  CC, T_0, RESULT
161         subq    A, B, T_0
162         cmoveq  CC, T_0, A
163         srl     BIT, 1, BIT     
164         srl     B, 1, B
165         beq     A, Lret_result
166         bne     BIT, Ldivloop
167
168 Lret_result:
169 ifelse(OP, `div',
170 `', `   mov     A, RESULT
171 ')
172 ifelse(S, `true',
173 `
174         /* Check to see if we should negate it. */
175         subqv   zero, RESULT, T_0
176         cmovlbs NEG, T_0, RESULT
177 ')
178
179         ldq     BIT, 0(sp)
180         ldq     I, 8(sp)
181         ldq     CC, 16(sp)
182         ldq     T_0, 24(sp)
183 ifelse(S, `true',
184 `       ldq     NEG, 32(sp)')
185         ldq     A, 40(sp)
186         ldq     B, 48(sp)
187         lda     sp, 64(sp)
188         ret     zero, (t9), 1
189
190 Ldotrap:
191         ldiq    a0, -2                  /* This is the signal to SIGFPE! */
192         call_pal PAL_gentrap
193 ifelse(OP, `div',
194 `', `   mov     zero, A                 /* so that zero will be returned */
195 ')
196         br      zero, Lret_result
197
198 END(NAME)