xref: /openbsd/gnu/gcc/gcc/config/alpha/lib1funcs.asm (revision 404b540a)
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