1*404b540aSrobert/* DEC Alpha division and remainder support. 2*404b540aSrobert Copyright (C) 1994, 1999 Free Software Foundation, Inc. 3*404b540aSrobert 4*404b540aSrobertThis file is free software; you can redistribute it and/or modify it 5*404b540aSrobertunder the terms of the GNU General Public License as published by the 6*404b540aSrobertFree Software Foundation; either version 2, or (at your option) any 7*404b540aSrobertlater version. 8*404b540aSrobert 9*404b540aSrobertIn addition to the permissions in the GNU General Public License, the 10*404b540aSrobertFree Software Foundation gives you unlimited permission to link the 11*404b540aSrobertcompiled version of this file into combinations with other programs, 12*404b540aSrobertand to distribute those combinations without any restriction coming 13*404b540aSrobertfrom the use of this file. (The General Public License restrictions 14*404b540aSrobertdo apply in other respects; for example, they cover modification of 15*404b540aSrobertthe file, and distribution when not linked into a combine 16*404b540aSrobertexecutable.) 17*404b540aSrobert 18*404b540aSrobertThis file is distributed in the hope that it will be useful, but 19*404b540aSrobertWITHOUT ANY WARRANTY; without even the implied warranty of 20*404b540aSrobertMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21*404b540aSrobertGeneral Public License for more details. 22*404b540aSrobert 23*404b540aSrobertYou should have received a copy of the GNU General Public License 24*404b540aSrobertalong with this program; see the file COPYING. If not, write to 25*404b540aSrobertthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 26*404b540aSrobertBoston, MA 02110-1301, USA. */ 27*404b540aSrobert 28*404b540aSrobert/* This had to be written in assembler because the division functions 29*404b540aSrobert use a non-standard calling convention. 30*404b540aSrobert 31*404b540aSrobert This file provides an implementation of __divqu, __divq, __divlu, 32*404b540aSrobert __divl, __remqu, __remq, __remlu and __reml. CPP macros control 33*404b540aSrobert the exact operation. 34*404b540aSrobert 35*404b540aSrobert Operation performed: $27 := $24 o $25, clobber $28, return address to 36*404b540aSrobert caller in $23, where o one of the operations. 37*404b540aSrobert 38*404b540aSrobert The following macros need to be defined: 39*404b540aSrobert 40*404b540aSrobert SIZE, the number of bits, 32 or 64. 41*404b540aSrobert 42*404b540aSrobert TYPE, either UNSIGNED or SIGNED 43*404b540aSrobert 44*404b540aSrobert OPERATION, either DIVISION or REMAINDER 45*404b540aSrobert 46*404b540aSrobert SPECIAL_CALLING_CONVENTION, 0 or 1. It is useful for debugging to 47*404b540aSrobert define this to 0. That removes the `__' prefix to make the function 48*404b540aSrobert name not collide with the existing libc.a names, and uses the 49*404b540aSrobert standard Alpha procedure calling convention. 50*404b540aSrobert*/ 51*404b540aSrobert 52*404b540aSrobert#ifndef SPECIAL_CALLING_CONVENTION 53*404b540aSrobert#define SPECIAL_CALLING_CONVENTION 1 54*404b540aSrobert#endif 55*404b540aSrobert 56*404b540aSrobert#ifdef L_divl 57*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 58*404b540aSrobert#define FUNCTION_NAME __divl 59*404b540aSrobert#else 60*404b540aSrobert#define FUNCTION_NAME divl 61*404b540aSrobert#endif 62*404b540aSrobert#define SIZE 32 63*404b540aSrobert#define TYPE SIGNED 64*404b540aSrobert#define OPERATION DIVISION 65*404b540aSrobert#endif 66*404b540aSrobert 67*404b540aSrobert#ifdef L_divlu 68*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 69*404b540aSrobert#define FUNCTION_NAME __divlu 70*404b540aSrobert#else 71*404b540aSrobert#define FUNCTION_NAME divlu 72*404b540aSrobert#endif 73*404b540aSrobert#define SIZE 32 74*404b540aSrobert#define TYPE UNSIGNED 75*404b540aSrobert#define OPERATION DIVISION 76*404b540aSrobert#endif 77*404b540aSrobert 78*404b540aSrobert#ifdef L_divq 79*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 80*404b540aSrobert#define FUNCTION_NAME __divq 81*404b540aSrobert#else 82*404b540aSrobert#define FUNCTION_NAME divq 83*404b540aSrobert#endif 84*404b540aSrobert#define SIZE 64 85*404b540aSrobert#define TYPE SIGNED 86*404b540aSrobert#define OPERATION DIVISION 87*404b540aSrobert#endif 88*404b540aSrobert 89*404b540aSrobert#ifdef L_divqu 90*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 91*404b540aSrobert#define FUNCTION_NAME __divqu 92*404b540aSrobert#else 93*404b540aSrobert#define FUNCTION_NAME divqu 94*404b540aSrobert#endif 95*404b540aSrobert#define SIZE 64 96*404b540aSrobert#define TYPE UNSIGNED 97*404b540aSrobert#define OPERATION DIVISION 98*404b540aSrobert#endif 99*404b540aSrobert 100*404b540aSrobert#ifdef L_reml 101*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 102*404b540aSrobert#define FUNCTION_NAME __reml 103*404b540aSrobert#else 104*404b540aSrobert#define FUNCTION_NAME reml 105*404b540aSrobert#endif 106*404b540aSrobert#define SIZE 32 107*404b540aSrobert#define TYPE SIGNED 108*404b540aSrobert#define OPERATION REMAINDER 109*404b540aSrobert#endif 110*404b540aSrobert 111*404b540aSrobert#ifdef L_remlu 112*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 113*404b540aSrobert#define FUNCTION_NAME __remlu 114*404b540aSrobert#else 115*404b540aSrobert#define FUNCTION_NAME remlu 116*404b540aSrobert#endif 117*404b540aSrobert#define SIZE 32 118*404b540aSrobert#define TYPE UNSIGNED 119*404b540aSrobert#define OPERATION REMAINDER 120*404b540aSrobert#endif 121*404b540aSrobert 122*404b540aSrobert#ifdef L_remq 123*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 124*404b540aSrobert#define FUNCTION_NAME __remq 125*404b540aSrobert#else 126*404b540aSrobert#define FUNCTION_NAME remq 127*404b540aSrobert#endif 128*404b540aSrobert#define SIZE 64 129*404b540aSrobert#define TYPE SIGNED 130*404b540aSrobert#define OPERATION REMAINDER 131*404b540aSrobert#endif 132*404b540aSrobert 133*404b540aSrobert#ifdef L_remqu 134*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 135*404b540aSrobert#define FUNCTION_NAME __remqu 136*404b540aSrobert#else 137*404b540aSrobert#define FUNCTION_NAME remqu 138*404b540aSrobert#endif 139*404b540aSrobert#define SIZE 64 140*404b540aSrobert#define TYPE UNSIGNED 141*404b540aSrobert#define OPERATION REMAINDER 142*404b540aSrobert#endif 143*404b540aSrobert 144*404b540aSrobert#define tmp0 $3 145*404b540aSrobert#define tmp1 $28 146*404b540aSrobert#define cnt $1 147*404b540aSrobert#define result_sign $2 148*404b540aSrobert 149*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 150*404b540aSrobert#define N $24 151*404b540aSrobert#define D $25 152*404b540aSrobert#define Q RETREG 153*404b540aSrobert#define RETREG $27 154*404b540aSrobert#else 155*404b540aSrobert#define N $16 156*404b540aSrobert#define D $17 157*404b540aSrobert#define Q RETREG 158*404b540aSrobert#define RETREG $0 159*404b540aSrobert#endif 160*404b540aSrobert 161*404b540aSrobert/* Misc symbols to make alpha assembler easier to read. */ 162*404b540aSrobert#define zero $31 163*404b540aSrobert#define sp $30 164*404b540aSrobert 165*404b540aSrobert/* Symbols to make interface nicer. */ 166*404b540aSrobert#define UNSIGNED 0 167*404b540aSrobert#define SIGNED 1 168*404b540aSrobert#define DIVISION 0 169*404b540aSrobert#define REMAINDER 1 170*404b540aSrobert 171*404b540aSrobert .set noreorder 172*404b540aSrobert .set noat 173*404b540aSrobert.text 174*404b540aSrobert .align 3 175*404b540aSrobert .globl FUNCTION_NAME 176*404b540aSrobert .ent FUNCTION_NAME 177*404b540aSrobertFUNCTION_NAME: 178*404b540aSrobert 179*404b540aSrobert .frame $30,0,$26,0 180*404b540aSrobert .prologue 0 181*404b540aSrobert 182*404b540aSrobert/* Under the special calling convention, we have to preserve all register 183*404b540aSrobert values but $23 and $28. */ 184*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 185*404b540aSrobert lda sp,-64(sp) 186*404b540aSrobert#if OPERATION == DIVISION 187*404b540aSrobert stq N,0(sp) 188*404b540aSrobert#endif 189*404b540aSrobert stq D,8(sp) 190*404b540aSrobert stq cnt,16(sp) 191*404b540aSrobert stq result_sign,24(sp) 192*404b540aSrobert stq tmp0,32(sp) 193*404b540aSrobert#endif 194*404b540aSrobert 195*404b540aSrobert/* If we are computing the remainder, move N to the register that is used 196*404b540aSrobert for the return value, and redefine what register is used for N. */ 197*404b540aSrobert#if OPERATION == REMAINDER 198*404b540aSrobert bis N,N,RETREG 199*404b540aSrobert#undef N 200*404b540aSrobert#define N RETREG 201*404b540aSrobert#endif 202*404b540aSrobert 203*404b540aSrobert/* Perform conversion from 32 bit types to 64 bit types. */ 204*404b540aSrobert#if SIZE == 32 205*404b540aSrobert#if TYPE == SIGNED 206*404b540aSrobert /* If there are problems with the signed case, add these instructions. 207*404b540aSrobert The caller should already have done this. 208*404b540aSrobert addl N,0,N # sign extend N 209*404b540aSrobert addl D,0,D # sign extend D 210*404b540aSrobert */ 211*404b540aSrobert#else /* UNSIGNED */ 212*404b540aSrobert zap N,0xf0,N # zero extend N (caller required to sign extend) 213*404b540aSrobert zap D,0xf0,D # zero extend D 214*404b540aSrobert#endif 215*404b540aSrobert#endif 216*404b540aSrobert 217*404b540aSrobert/* Check for divide by zero. */ 218*404b540aSrobert bne D,$34 219*404b540aSrobert lda $16,-2(zero) 220*404b540aSrobert call_pal 0xaa 221*404b540aSrobert$34: 222*404b540aSrobert 223*404b540aSrobert#if TYPE == SIGNED 224*404b540aSrobert#if OPERATION == DIVISION 225*404b540aSrobert xor N,D,result_sign 226*404b540aSrobert#else 227*404b540aSrobert bis N,N,result_sign 228*404b540aSrobert#endif 229*404b540aSrobert/* Get the absolute values of N and D. */ 230*404b540aSrobert subq zero,N,tmp0 231*404b540aSrobert cmovlt N,tmp0,N 232*404b540aSrobert subq zero,D,tmp0 233*404b540aSrobert cmovlt D,tmp0,D 234*404b540aSrobert#endif 235*404b540aSrobert 236*404b540aSrobert/* Compute CNT = ceil(log2(N)) - ceil(log2(D)). This is the number of 237*404b540aSrobert divide iterations we will have to perform. Should you wish to optimize 238*404b540aSrobert this, check a few bits at a time, preferably using zap/zapnot. Be 239*404b540aSrobert careful though, this code runs fast fro the most common cases, when the 240*404b540aSrobert quotient is small. */ 241*404b540aSrobert bge N,$35 242*404b540aSrobert bis zero,1,cnt 243*404b540aSrobert blt D,$40 244*404b540aSrobert .align 3 245*404b540aSrobert$39: addq D,D,D 246*404b540aSrobert addl cnt,1,cnt 247*404b540aSrobert bge D,$39 248*404b540aSrobert br zero,$40 249*404b540aSrobert$35: cmpult N,D,tmp0 250*404b540aSrobert bis zero,zero,cnt 251*404b540aSrobert bne tmp0,$42 252*404b540aSrobert .align 3 253*404b540aSrobert$44: addq D,D,D 254*404b540aSrobert cmpult N,D,tmp0 255*404b540aSrobert addl cnt,1,cnt 256*404b540aSrobert beq tmp0,$44 257*404b540aSrobert$42: srl D,1,D 258*404b540aSrobert$40: 259*404b540aSrobert subl cnt,1,cnt 260*404b540aSrobert 261*404b540aSrobert 262*404b540aSrobert/* Actual divide. Could be optimized with unrolling. */ 263*404b540aSrobert#if OPERATION == DIVISION 264*404b540aSrobert bis zero,zero,Q 265*404b540aSrobert#endif 266*404b540aSrobert blt cnt,$46 267*404b540aSrobert .align 3 268*404b540aSrobert$49: cmpule D,N,tmp1 269*404b540aSrobert subq N,D,tmp0 270*404b540aSrobert srl D,1,D 271*404b540aSrobert subl cnt,1,cnt 272*404b540aSrobert cmovne tmp1,tmp0,N 273*404b540aSrobert#if OPERATION == DIVISION 274*404b540aSrobert addq Q,Q,Q 275*404b540aSrobert bis Q,tmp1,Q 276*404b540aSrobert#endif 277*404b540aSrobert bge cnt,$49 278*404b540aSrobert$46: 279*404b540aSrobert 280*404b540aSrobert 281*404b540aSrobert/* The result is now in RETREG. NOTE! It was written to RETREG using 282*404b540aSrobert either N or Q as a synonym! */ 283*404b540aSrobert 284*404b540aSrobert 285*404b540aSrobert/* Change the sign of the result as needed. */ 286*404b540aSrobert#if TYPE == SIGNED 287*404b540aSrobert subq zero,RETREG,tmp0 288*404b540aSrobert cmovlt result_sign,tmp0,RETREG 289*404b540aSrobert#endif 290*404b540aSrobert 291*404b540aSrobert 292*404b540aSrobert/* Restore clobbered registers. */ 293*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 294*404b540aSrobert#if OPERATION == DIVISION 295*404b540aSrobert ldq N,0(sp) 296*404b540aSrobert#endif 297*404b540aSrobert ldq D,8(sp) 298*404b540aSrobert ldq cnt,16(sp) 299*404b540aSrobert ldq result_sign,24(sp) 300*404b540aSrobert ldq tmp0,32(sp) 301*404b540aSrobert 302*404b540aSrobert lda sp,64(sp) 303*404b540aSrobert#endif 304*404b540aSrobert 305*404b540aSrobert 306*404b540aSrobert/* Sign extend an *unsigned* 32 bit result, as required by the Alpha 307*404b540aSrobert conventions. */ 308*404b540aSrobert#if TYPE == UNSIGNED && SIZE == 32 309*404b540aSrobert /* This could be avoided by adding some CPP hair to the divide loop. 310*404b540aSrobert It is probably not worth the added complexity. */ 311*404b540aSrobert addl RETREG,0,RETREG 312*404b540aSrobert#endif 313*404b540aSrobert 314*404b540aSrobert 315*404b540aSrobert#if SPECIAL_CALLING_CONVENTION 316*404b540aSrobert ret zero,($23),1 317*404b540aSrobert#else 318*404b540aSrobert ret zero,($26),1 319*404b540aSrobert#endif 320*404b540aSrobert .end FUNCTION_NAME 321