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