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