OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [alpha/] [lib1funcs.asm] - Diff between revs 154 and 816

Only display areas with differences | Details | Blame | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.