diff options
Diffstat (limited to 'sysdeps/alpha/div.S')
-rw-r--r-- | sysdeps/alpha/div.S | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/sysdeps/alpha/div.S b/sysdeps/alpha/div.S new file mode 100644 index 0000000000..6c461c40d4 --- /dev/null +++ b/sysdeps/alpha/div.S @@ -0,0 +1,110 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Richard Henderson (rth@tamu.edu) + + 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., 675 Mass Ave, + Cambridge, MA 02139, USA. */ + + +#include <sysdep.h> + +#ifdef __linux__ +# include <asm/gentrap.h> +# include <asm/pal.h> +#else +# include <machine/pal.h> +#endif + + .set noat + + .align 4 + .globl div + .ent div +div: + .frame sp, 0, ra +#ifdef PROF + ldgp gp, 0(pv) + lda AT, _mcount + jsr AT, (AT), _mcount + .prologue 1 +#else + .prologue 0 +#endif + +#define dividend t0 +#define divisor t1 +#define mask t2 +#define quotient t3 +#define modulus t4 +#define tmp1 t5 +#define tmp2 t6 +#define compare t7 + + /* find correct sign for input to unsigned divide loop. */ + sextl a1, a1 # e0 : + sextl a2, a2 # .. e1 : + negl a1, dividend # e0 : + negl a2, divisor # .. e1 : + cmovge a1, a1, dividend # e0 : + cmovge a2, a2, divisor # .. e1 : + beq a2, $divbyzero # e1 : + unop # : + + /* shift divisor left, using 3-bit shifts for 32-bit divides as we + can't overflow. Three-bit shifts will result in looping three + times less here, but can result in two loops more later. Thus + using a large shift isn't worth it (and s8addq pairs better than + a shift). */ + +1: cmpult divisor, modulus, compare # e0 : + s8addq divisor, zero, divisor # .. e1 : + s8addq mask, zero, mask # e0 : + bne compare, 1b # .. e1 : + + /* start to go right again. */ +2: addq quotient, mask, tmp2 # e1 : + srl mask, 1, mask # .. e0 : + cmpule divisor, modulus, compare # e0 : + subq modulus, divisor, tmp1 # .. e1 : + cmovne compare, tmp2, quotient # e1 : + srl divisor, 1, divisor # .. e0 : + cmovne compare, tmp1, modulus # e0 : + bne mask, 2b # .. e1 : + + /* find correct sign for result. */ + xor a1, a2, compare # e0 : + negl quotient, tmp1 # .. e1 : + negl modulus, tmp2 # e0 : + cmovlt compare, tmp1, quotient # .. e1 : + cmovlt a1, tmp2, modulus # e1 : + + /* and store it away in the structure. */ + stl quotient, 0(a0) # .. e0 : + mov a0, v0 # e1 : + stl modulus, 4(a0) # .. e0 : + ret # e1 : + +$divbyzero: + mov a0, v0 + ldiq a0, GEN_INTDIV + call_pal PAL_gentrap + + /* if trap returns, return zero. */ + stl zero, 0(v0) + stl zero, 4(v0) + ret + + .end div |