diff options
Diffstat (limited to 'sys/lib/libkern/arch/alpha/__reml.S')
-rw-r--r-- | sys/lib/libkern/arch/alpha/__reml.S | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/sys/lib/libkern/arch/alpha/__reml.S b/sys/lib/libkern/arch/alpha/__reml.S new file mode 100644 index 00000000000..069cfa5ebec --- /dev/null +++ b/sys/lib/libkern/arch/alpha/__reml.S @@ -0,0 +1,192 @@ + + +/* $OpenBSD: __reml.S,v 1.1 2007/11/25 18:25:34 deraadt Exp $ */ +/* $NetBSD: divrem.m4,v 1.5 1996/10/17 04:26:25 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Division and remainder. + * + * The use of m4 is modeled after the sparc code, but the algorithm is + * simple binary long division. + * + * Note that the loops could probably benefit from unrolling. + */ + +/* + * M4 Parameters + * __reml name of function to generate + * rem rem=div: t10 / t11 -> t12; rem=rem: t10 % t11 -> t12 + * true true=true: signed; true=false: unsigned + * 32 total number of bits + */ + + + + + + + + + + + +#include <machine/asm.h> + +LEAF(__reml, 0) /* XXX */ + lda sp, -64(sp) + stq t0, 0(sp) + stq t1, 8(sp) + stq t2, 16(sp) + stq t3, 24(sp) + stq t4, 32(sp) + stq t10, 40(sp) + stq t11, 48(sp) + mov zero, t12 /* Initialize result to zero */ + + + /* Compute sign of result. If either is negative, this is easy. */ + or t10, t11, t4 /* not the sign, but... */ + srl t4, 32 - 1, t4 /* rather, or of high bits */ + blbc t4, Ldoit /* neither negative? do it! */ + + mov t10, t4 /* sign follows t10. */ + + srl t4, 32 - 1, t4 /* make negation the low bit. */ + + srl t10, 32 - 1, t1 /* is t10 negative? */ + blbc t1, LnegB /* no. */ + /* t10 is negative; flip it. */ + + /* top 32 bits may be random junk */ + zap t10, 0xf0, t10 + + subq zero, t10, t10 + srl t11, 32 - 1, t1 /* is t11 negative? */ + blbc t1, Ldoit /* no. */ +LnegB: + /* t11 is definitely negative, no matter how we got here. */ + + /* top 32 bits may be random junk */ + zap t11, 0xf0, t11 + + subq zero, t11, t11 +Ldoit: + + + /* + * Clear the top 32 bits of each operand, as they may + * sign extension (if negated above), or random junk. + */ + zap t10, 0xf0, t10 + zap t11, 0xf0, t11 + + + /* kill the special cases. */ + beq t11, Ldotrap /* division by zero! */ + + cmpult t10, t11, t2 /* t10 < t11? */ + /* t12 is already zero, from above. t10 is untouched. */ + bne t2, Lret_result + + cmpeq t10, t11, t2 /* t10 == t11? */ + cmovne t2, 1, t12 + cmovne t2, zero, t10 + bne t2, Lret_result + + /* + * Find out how many bits of zeros are at the beginning of the divisor. + */ +LBbits: + ldiq t3, 1 /* t1 = 0; t0 = 1<<32-1 */ + mov zero, t1 + sll t3, 32-1, t0 +LBloop: + and t11, t0, t2 /* if bit in t11 is set, done. */ + bne t2, LAbits + addq t1, 1, t1 /* increment t1, bit */ + srl t0, 1, t0 + cmplt t1, 32-1, t2 /* if t1 leaves one bit, done. */ + bne t2, LBloop + +LAbits: + beq t1, Ldodiv /* If t1 = 0, divide now. */ + ldiq t3, 1 /* t0 = 1<<32-1 */ + sll t3, 32-1, t0 + +LAloop: + and t10, t0, t2 /* if bit in t10 is set, done. */ + bne t2, Ldodiv + subq t1, 1, t1 /* decrement t1, bit */ + srl t0, 1, t0 + bne t1, LAloop /* If t1 != 0, loop again */ + +Ldodiv: + sll t11, t1, t11 /* t11 <<= i */ + ldiq t3, 1 + sll t3, t1, t0 + +Ldivloop: + cmpult t10, t11, t2 + or t12, t0, t3 + cmoveq t2, t3, t12 + subq t10, t11, t3 + cmoveq t2, t3, t10 + srl t0, 1, t0 + srl t11, 1, t11 + beq t10, Lret_result + bne t0, Ldivloop + +Lret_result: + mov t10, t12 + + + /* Check to see if we should negate it. */ + subqv zero, t12, t3 + cmovlbs t4, t3, t12 + + + ldq t0, 0(sp) + ldq t1, 8(sp) + ldq t2, 16(sp) + ldq t3, 24(sp) + ldq t4, 32(sp) + ldq t10, 40(sp) + ldq t11, 48(sp) + lda sp, 64(sp) + ret zero, (t9), 1 + +Ldotrap: + ldiq a0, -2 /* This is the signal to SIGFPE! */ + call_pal PAL_gentrap + mov zero, t10 /* so that zero will be returned */ + + br zero, Lret_result + +END(__reml) |