summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/alpha
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-05-30 03:04:12 +0000
committerEric Andersen <andersen@codepoet.org>2002-05-30 03:04:12 +0000
commitbf15958a133ca8c02250cc27c0db28cc6085729b (patch)
treec3ea3323b2aa9ffc74fd8605863bf13c42b4dc47 /libc/sysdeps/linux/alpha
parent2bbf3bbde1d63c20e82830d699f1dc529ab2ef5f (diff)
Needed for the alpha port
-Erik
Diffstat (limited to 'libc/sysdeps/linux/alpha')
-rw-r--r--libc/sysdeps/linux/alpha/Makefile3
-rw-r--r--libc/sysdeps/linux/alpha/divl.S6
-rw-r--r--libc/sysdeps/linux/alpha/divq.S6
-rw-r--r--libc/sysdeps/linux/alpha/divrem.h266
-rw-r--r--libc/sysdeps/linux/alpha/reml.S6
-rw-r--r--libc/sysdeps/linux/alpha/remq.S6
6 files changed, 292 insertions, 1 deletions
diff --git a/libc/sysdeps/linux/alpha/Makefile b/libc/sysdeps/linux/alpha/Makefile
index 2cad8ad20..5e19b6ca9 100644
--- a/libc/sysdeps/linux/alpha/Makefile
+++ b/libc/sysdeps/linux/alpha/Makefile
@@ -28,7 +28,8 @@ CRT0=crt0.S
CRT0_OBJ=$(patsubst %.S,%.o, $(CRT0))
-SSRC=__longjmp.S brk.S bsd-_setjmp.S bsd-setjmp.S clone.S setjmp.S
+SSRC=__longjmp.S brk.S bsd-_setjmp.S bsd-setjmp.S clone.S \
+ setjmp.S divl.S reml.S remq.S divq.S
SOBJS=$(patsubst %.S,%.o, $(SSRC))
CSRC=sysdep.c #brk.c
diff --git a/libc/sysdeps/linux/alpha/divl.S b/libc/sysdeps/linux/alpha/divl.S
new file mode 100644
index 000000000..fdf053fc2
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/divl.S
@@ -0,0 +1,6 @@
+#define IS_REM 0
+#define SIZE 4
+#define UFUNC_NAME __divlu
+#define SFUNC_NAME __divl
+
+#include "divrem.h"
diff --git a/libc/sysdeps/linux/alpha/divq.S b/libc/sysdeps/linux/alpha/divq.S
new file mode 100644
index 000000000..8c88af973
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/divq.S
@@ -0,0 +1,6 @@
+#define IS_REM 0
+#define SIZE 8
+#define UFUNC_NAME __divqu
+#define SFUNC_NAME __divq
+
+#include "divrem.h"
diff --git a/libc/sysdeps/linux/alpha/divrem.h b/libc/sysdeps/linux/alpha/divrem.h
new file mode 100644
index 000000000..d22759e40
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/divrem.h
@@ -0,0 +1,266 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by David Mosberger (davidm@cs.arizona.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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* The current Alpha chips don't provide hardware for integer
+ division. The C compiler expects the functions
+
+ __divqu: 64-bit unsigned long divide
+ __remqu: 64-bit unsigned long remainder
+ __divqs/__remqs: signed 64-bit
+ __divlu/__remlu: unsigned 32-bit
+ __divls/__remls: signed 32-bit
+
+ These are not normal C functions: instead of the normal calling
+ sequence, these expect their arguments in registers t10 and t11, and
+ return the result in t12 (aka pv). Register AT may be clobbered
+ (assembly temporary), anything else must be saved. */
+
+#include <features.h>
+
+#ifdef __linux__
+# include <asm/gentrap.h>
+# include <asm/pal.h>
+#else
+# include <machine/pal.h>
+#endif
+
+#define mask v0
+#define divisor t0
+#define compare AT
+#define tmp1 t2
+#define tmp2 t3
+#define retaddr t9
+#define arg1 t10
+#define arg2 t11
+#define result t12
+
+#define v0 $0 /* function return value */
+
+#define t0 $1 /* temporary registers (caller-saved) */
+#define t1 $2
+#define t2 $3
+#define t3 $4
+#define t4 $5
+#define t5 $6
+#define t6 $7
+#define t7 $8
+
+#define s0 $9 /* saved-registers (callee-saved registers) */
+#define s1 $10
+#define s2 $11
+#define s3 $12
+#define s4 $13
+#define s5 $14
+#define s6 $15
+#define fp s6 /* frame-pointer (s6 in frame-less procedures) */
+
+#define a0 $16 /* argument registers (caller-saved) */
+#define a1 $17
+#define a2 $18
+#define a3 $19
+#define a4 $20
+#define a5 $21
+
+#define t8 $22 /* more temps (caller-saved) */
+#define t9 $23
+#define t10 $24
+#define t11 $25
+#define ra $26 /* return address register */
+#define t12 $27
+
+#define pv t12 /* procedure-variable register */
+#define AT $at /* assembler temporary */
+#define gp $29 /* global pointer */
+#define sp $30 /* stack pointer */
+#define zero $31 /* reads as zero, writes are noops */
+
+
+
+#if IS_REM
+# define DIV_ONLY(x,y...)
+# define REM_ONLY(x,y...) x,##y
+# define modulus result
+# define quotient t1
+# define GETSIGN(x) mov arg1, x
+# define STACK 32
+#else
+# define DIV_ONLY(x,y...) x,##y
+# define REM_ONLY(x,y...)
+# define modulus t1
+# define quotient result
+# define GETSIGN(x) xor arg1, arg2, x
+# define STACK 48
+#endif
+
+#if SIZE == 8
+# define LONGIFY(x,y) mov x,y
+# define SLONGIFY(x,y) mov x,y
+# define _SLONGIFY(x)
+# define NEG(x,y) negq x,y
+#else
+# define LONGIFY(x,y) zapnot x,15,y
+# define SLONGIFY(x,y) sextl x,y
+# define _SLONGIFY(x) sextl x,x
+# define NEG(x,y) negl x,y
+#endif
+
+ .set noreorder
+ .set noat
+
+ .ent UFUNC_NAME
+ .globl UFUNC_NAME
+
+ .align 3
+UFUNC_NAME:
+ lda sp, -STACK(sp)
+ .frame sp, STACK, retaddr, 0
+#ifdef PROF
+ stq ra, 0(sp)
+ stq pv, 8(sp)
+ stq gp, 16(sp)
+
+ br AT, 1f
+1: ldgp gp, 0(AT)
+
+ mov retaddr, ra
+ lda AT, _mcount
+ jsr AT, (AT), _mcount
+
+ ldq ra, 0(sp)
+ ldq pv, 8(sp)
+ ldq gp, 16(sp)
+#endif
+ .prologue 0
+
+$udiv:
+ stq t0, 0(sp)
+ LONGIFY (arg2, divisor)
+ stq t1, 8(sp)
+ LONGIFY (arg1, modulus)
+ stq v0, 16(sp)
+ clr quotient
+ stq tmp1, 24(sp)
+ ldiq mask, 1
+ DIV_ONLY(stq tmp2,32(sp))
+
+ beq divisor, $divbyzero
+
+ .align 3
+#if SIZE == 8
+ /* Shift divisor left. */
+1: cmpult divisor, modulus, compare
+ blt divisor, 2f
+ addq divisor, divisor, divisor
+ addq mask, mask, mask
+ bne compare, 1b
+ unop
+2:
+#else
+ /* Shift divisor left using 3-bit shifts as we can't overflow.
+ This results in looping three times less here, but up to
+ two more times later. Thus using a large shift isn't worth it. */
+1: cmpult divisor, modulus, compare
+ s8addq divisor, zero, divisor
+ s8addq mask, zero, mask
+ bne compare, 1b
+#endif
+
+ /* Now go back to the right. */
+3: DIV_ONLY(addq quotient, mask, tmp2)
+ srl mask, 1, mask
+ cmpule divisor, modulus, compare
+ subq modulus, divisor, tmp1
+ DIV_ONLY(cmovne compare, tmp2, quotient)
+ srl divisor, 1, divisor
+ cmovne compare, tmp1, modulus
+ bne mask, 3b
+
+$done: ldq t0, 0(sp)
+ ldq t1, 8(sp)
+ ldq v0, 16(sp)
+ ldq tmp1, 24(sp)
+ DIV_ONLY(ldq tmp2, 32(sp))
+ lda sp, STACK(sp)
+ ret zero, (retaddr), 1
+
+$divbyzero:
+ mov a0, tmp1
+ ldiq a0, GEN_INTDIV
+ call_pal PAL_gentrap
+ mov tmp1, a0
+ clr result /* If trap returns, return zero. */
+ br $done
+
+ .end UFUNC_NAME
+
+ .ent SFUNC_NAME
+ .globl SFUNC_NAME
+
+ .align 3
+SFUNC_NAME:
+ lda sp, -STACK(sp)
+ .frame sp, STACK, retaddr, 0
+#ifdef PROF
+ stq ra, 0(sp)
+ stq pv, 8(sp)
+ stq gp, 16(sp)
+
+ br AT, 1f
+1: ldgp gp, 0(AT)
+
+ mov retaddr, ra
+ jsr AT, _mcount
+
+ ldq ra, 0(sp)
+ ldq pv, 8(sp)
+ ldq gp, 16(sp)
+#endif
+ .prologue 0
+
+ or arg1, arg2, AT
+ _SLONGIFY(AT)
+ bge AT, $udiv /* don't need to mess with signs */
+
+ /* Save originals and find absolute values. */
+ stq arg1, 0(sp)
+ NEG (arg1, AT)
+ stq arg2, 8(sp)
+ cmovge AT, AT, arg1
+ stq retaddr, 16(sp)
+ NEG (arg2, AT)
+ stq tmp1, 24(sp)
+ cmovge AT, AT, arg2
+
+ /* Do the unsigned division. */
+ bsr retaddr, UFUNC_NAME
+
+ /* Restore originals and adjust the sign of the result. */
+ ldq arg1, 0(sp)
+ ldq arg2, 8(sp)
+ GETSIGN (AT)
+ NEG (result, tmp1)
+ _SLONGIFY(AT)
+ ldq retaddr, 16(sp)
+ cmovlt AT, tmp1, result
+ ldq tmp1, 24(sp)
+
+ lda sp, STACK(sp)
+ ret zero, (retaddr), 1
+
+ .end SFUNC_NAME
diff --git a/libc/sysdeps/linux/alpha/reml.S b/libc/sysdeps/linux/alpha/reml.S
new file mode 100644
index 000000000..8c00365ee
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/reml.S
@@ -0,0 +1,6 @@
+#define IS_REM 1
+#define SIZE 4
+#define UFUNC_NAME __remlu
+#define SFUNC_NAME __reml
+
+#include "divrem.h"
diff --git a/libc/sysdeps/linux/alpha/remq.S b/libc/sysdeps/linux/alpha/remq.S
new file mode 100644
index 000000000..cd1064af4
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/remq.S
@@ -0,0 +1,6 @@
+#define IS_REM 1
+#define SIZE 8
+#define UFUNC_NAME __remqu
+#define SFUNC_NAME __remq
+
+#include "divrem.h"