aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1/gcc/config/alpha/lib1funcs.asm
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1/gcc/config/alpha/lib1funcs.asm')
-rw-r--r--gcc-4.2.1/gcc/config/alpha/lib1funcs.asm320
1 files changed, 320 insertions, 0 deletions
diff --git a/gcc-4.2.1/gcc/config/alpha/lib1funcs.asm b/gcc-4.2.1/gcc/config/alpha/lib1funcs.asm
new file mode 100644
index 000000000..41a551057
--- /dev/null
+++ b/gcc-4.2.1/gcc/config/alpha/lib1funcs.asm
@@ -0,0 +1,320 @@
+/* DEC Alpha division and remainder support.
+ Copyright (C) 1994, 1999 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+/* This had to be written in assembler because the division functions
+ use a non-standard calling convention.
+
+ This file provides an implementation of __divqu, __divq, __divlu,
+ __divl, __remqu, __remq, __remlu and __reml. CPP macros control
+ the exact operation.
+
+ Operation performed: $27 := $24 o $25, clobber $28, return address to
+ caller in $23, where o one of the operations.
+
+ The following macros need to be defined:
+
+ SIZE, the number of bits, 32 or 64.
+
+ TYPE, either UNSIGNED or SIGNED
+
+ OPERATION, either DIVISION or REMAINDER
+
+ SPECIAL_CALLING_CONVENTION, 0 or 1. It is useful for debugging to
+ define this to 0. That removes the `__' prefix to make the function
+ name not collide with the existing libc.a names, and uses the
+ standard Alpha procedure calling convention.
+*/
+
+#ifndef SPECIAL_CALLING_CONVENTION
+#define SPECIAL_CALLING_CONVENTION 1
+#endif
+
+#ifdef L_divl
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __divl
+#else
+#define FUNCTION_NAME divl
+#endif
+#define SIZE 32
+#define TYPE SIGNED
+#define OPERATION DIVISION
+#endif
+
+#ifdef L_divlu
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __divlu
+#else
+#define FUNCTION_NAME divlu
+#endif
+#define SIZE 32
+#define TYPE UNSIGNED
+#define OPERATION DIVISION
+#endif
+
+#ifdef L_divq
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __divq
+#else
+#define FUNCTION_NAME divq
+#endif
+#define SIZE 64
+#define TYPE SIGNED
+#define OPERATION DIVISION
+#endif
+
+#ifdef L_divqu
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __divqu
+#else
+#define FUNCTION_NAME divqu
+#endif
+#define SIZE 64
+#define TYPE UNSIGNED
+#define OPERATION DIVISION
+#endif
+
+#ifdef L_reml
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __reml
+#else
+#define FUNCTION_NAME reml
+#endif
+#define SIZE 32
+#define TYPE SIGNED
+#define OPERATION REMAINDER
+#endif
+
+#ifdef L_remlu
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __remlu
+#else
+#define FUNCTION_NAME remlu
+#endif
+#define SIZE 32
+#define TYPE UNSIGNED
+#define OPERATION REMAINDER
+#endif
+
+#ifdef L_remq
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __remq
+#else
+#define FUNCTION_NAME remq
+#endif
+#define SIZE 64
+#define TYPE SIGNED
+#define OPERATION REMAINDER
+#endif
+
+#ifdef L_remqu
+#if SPECIAL_CALLING_CONVENTION
+#define FUNCTION_NAME __remqu
+#else
+#define FUNCTION_NAME remqu
+#endif
+#define SIZE 64
+#define TYPE UNSIGNED
+#define OPERATION REMAINDER
+#endif
+
+#define tmp0 $3
+#define tmp1 $28
+#define cnt $1
+#define result_sign $2
+
+#if SPECIAL_CALLING_CONVENTION
+#define N $24
+#define D $25
+#define Q RETREG
+#define RETREG $27
+#else
+#define N $16
+#define D $17
+#define Q RETREG
+#define RETREG $0
+#endif
+
+/* Misc symbols to make alpha assembler easier to read. */
+#define zero $31
+#define sp $30
+
+/* Symbols to make interface nicer. */
+#define UNSIGNED 0
+#define SIGNED 1
+#define DIVISION 0
+#define REMAINDER 1
+
+ .set noreorder
+ .set noat
+.text
+ .align 3
+ .globl FUNCTION_NAME
+ .ent FUNCTION_NAME
+FUNCTION_NAME:
+
+ .frame $30,0,$26,0
+ .prologue 0
+
+/* Under the special calling convention, we have to preserve all register
+ values but $23 and $28. */
+#if SPECIAL_CALLING_CONVENTION
+ lda sp,-64(sp)
+#if OPERATION == DIVISION
+ stq N,0(sp)
+#endif
+ stq D,8(sp)
+ stq cnt,16(sp)
+ stq result_sign,24(sp)
+ stq tmp0,32(sp)
+#endif
+
+/* If we are computing the remainder, move N to the register that is used
+ for the return value, and redefine what register is used for N. */
+#if OPERATION == REMAINDER
+ bis N,N,RETREG
+#undef N
+#define N RETREG
+#endif
+
+/* Perform conversion from 32 bit types to 64 bit types. */
+#if SIZE == 32
+#if TYPE == SIGNED
+ /* If there are problems with the signed case, add these instructions.
+ The caller should already have done this.
+ addl N,0,N # sign extend N
+ addl D,0,D # sign extend D
+ */
+#else /* UNSIGNED */
+ zap N,0xf0,N # zero extend N (caller required to sign extend)
+ zap D,0xf0,D # zero extend D
+#endif
+#endif
+
+/* Check for divide by zero. */
+ bne D,$34
+ lda $16,-2(zero)
+ call_pal 0xaa
+$34:
+
+#if TYPE == SIGNED
+#if OPERATION == DIVISION
+ xor N,D,result_sign
+#else
+ bis N,N,result_sign
+#endif
+/* Get the absolute values of N and D. */
+ subq zero,N,tmp0
+ cmovlt N,tmp0,N
+ subq zero,D,tmp0
+ cmovlt D,tmp0,D
+#endif
+
+/* Compute CNT = ceil(log2(N)) - ceil(log2(D)). This is the number of
+ divide iterations we will have to perform. Should you wish to optimize
+ this, check a few bits at a time, preferably using zap/zapnot. Be
+ careful though, this code runs fast fro the most common cases, when the
+ quotient is small. */
+ bge N,$35
+ bis zero,1,cnt
+ blt D,$40
+ .align 3
+$39: addq D,D,D
+ addl cnt,1,cnt
+ bge D,$39
+ br zero,$40
+$35: cmpult N,D,tmp0
+ bis zero,zero,cnt
+ bne tmp0,$42
+ .align 3
+$44: addq D,D,D
+ cmpult N,D,tmp0
+ addl cnt,1,cnt
+ beq tmp0,$44
+$42: srl D,1,D
+$40:
+ subl cnt,1,cnt
+
+
+/* Actual divide. Could be optimized with unrolling. */
+#if OPERATION == DIVISION
+ bis zero,zero,Q
+#endif
+ blt cnt,$46
+ .align 3
+$49: cmpule D,N,tmp1
+ subq N,D,tmp0
+ srl D,1,D
+ subl cnt,1,cnt
+ cmovne tmp1,tmp0,N
+#if OPERATION == DIVISION
+ addq Q,Q,Q
+ bis Q,tmp1,Q
+#endif
+ bge cnt,$49
+$46:
+
+
+/* The result is now in RETREG. NOTE! It was written to RETREG using
+ either N or Q as a synonym! */
+
+
+/* Change the sign of the result as needed. */
+#if TYPE == SIGNED
+ subq zero,RETREG,tmp0
+ cmovlt result_sign,tmp0,RETREG
+#endif
+
+
+/* Restore clobbered registers. */
+#if SPECIAL_CALLING_CONVENTION
+#if OPERATION == DIVISION
+ ldq N,0(sp)
+#endif
+ ldq D,8(sp)
+ ldq cnt,16(sp)
+ ldq result_sign,24(sp)
+ ldq tmp0,32(sp)
+
+ lda sp,64(sp)
+#endif
+
+
+/* Sign extend an *unsigned* 32 bit result, as required by the Alpha
+ conventions. */
+#if TYPE == UNSIGNED && SIZE == 32
+ /* This could be avoided by adding some CPP hair to the divide loop.
+ It is probably not worth the added complexity. */
+ addl RETREG,0,RETREG
+#endif
+
+
+#if SPECIAL_CALLING_CONVENTION
+ ret zero,($23),1
+#else
+ ret zero,($26),1
+#endif
+ .end FUNCTION_NAME