1/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3
4   The GNU C Library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8
9   The GNU C Library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with the GNU C Library.  If not, see
16   <https://www.gnu.org/licenses/>.  */
17
18#include "div_libc.h"
19
20#undef FRAME
21#ifdef __alpha_fix__
22#define FRAME 0
23#else
24#define FRAME 16
25#endif
26
27#undef X
28#undef Y
29#define X $17
30#define Y $18
31
32	.set noat
33
34	.align 4
35	.globl ldiv
36	.ent ldiv
37ldiv:
38	.frame sp, FRAME, ra
39#if FRAME > 0
40	lda	sp, -FRAME(sp)
41#endif
42#ifdef PROF
43	.set	macro
44	ldgp	gp, 0(pv)
45	lda	AT, _mcount
46	jsr	AT, (AT), _mcount
47	.set	nomacro
48	.prologue 1
49#else
50	.prologue 0
51#endif
52
53	beq	Y, $divbyzero
54	excb
55	mf_fpcr	$f10
56
57	_ITOFT2	X, $f0, 0, Y, $f1, 8
58
59	.align	4
60	cvtqt	$f0, $f0
61	cvtqt	$f1, $f1
62	divt/c	$f0, $f1, $f0
63	unop
64
65	/* Check to see if X fit in the double as an exact value.  */
66	sll	X, (64-53), AT
67	sra	AT, (64-53), AT
68	cmpeq	X, AT, AT
69	beq	AT, $x_big
70
71	/* If we get here, we're expecting exact results from the division.
72	   Do nothing else besides convert and clean up.  */
73	cvttq/c	$f0, $f0
74	excb
75	mt_fpcr	$f10
76	_FTOIT	$f0, $0, 0
77
78$egress:
79	mulq	$0, Y, $1
80	subq	X, $1, $1
81
82	stq	$0, 0($16)
83	stq	$1, 8($16)
84	mov	$16, $0
85
86#if FRAME > 0
87	lda	sp, FRAME(sp)
88#endif
89	ret
90
91	.align	4
92$x_big:
93	/* If we get here, X is large enough that we don't expect exact
94	   results, and neither X nor Y got mis-translated for the fp
95	   division.  Our task is to take the fp result, figure out how
96	   far it's off from the correct result and compute a fixup.  */
97
98#define Q	v0		/* quotient */
99#define R	t0		/* remainder */
100#define SY	t1		/* scaled Y */
101#define S	t2		/* scalar */
102#define QY	t3		/* Q*Y */
103
104	/* The fixup code below can only handle unsigned values.  */
105	or	X, Y, AT
106	mov	$31, t5
107	blt	AT, $fix_sign_in
108$fix_sign_in_ret1:
109	cvttq/c	$f0, $f0
110
111	_FTOIT	$f0, Q, 8
112$fix_sign_in_ret2:
113	mulq	Q, Y, QY
114	excb
115	mt_fpcr	$f10
116
117	.align	4
118	subq	QY, X, R
119	mov	Y, SY
120	mov	1, S
121	bgt	R, $q_high
122
123$q_high_ret:
124	subq	X, QY, R
125	mov	Y, SY
126	mov	1, S
127	bgt	R, $q_low
128
129$q_low_ret:
130	negq	Q, t4
131	cmovlbs	t5, t4, Q
132	br	$egress
133
134	.align	4
135	/* The quotient that we computed was too large.  We need to reduce
136	   it by S such that Y*S >= R.  Obviously the closer we get to the
137	   correct value the better, but overshooting high is ok, as we'll
138	   fix that up later.  */
1390:
140	addq	SY, SY, SY
141	addq	S, S, S
142$q_high:
143	cmpult	SY, R, AT
144	bne	AT, 0b
145
146	subq	Q, S, Q
147	unop
148	subq	QY, SY, QY
149	br	$q_high_ret
150
151	.align	4
152	/* The quotient that we computed was too small.  Divide Y by the
153	   current remainder (R) and add that to the existing quotient (Q).
154	   The expectation, of course, is that R is much smaller than X.  */
155	/* Begin with a shift-up loop.  Compute S such that Y*S >= R.  We
156	   already have a copy of Y in SY and the value 1 in S.  */
1570:
158	addq	SY, SY, SY
159	addq	S, S, S
160$q_low:
161	cmpult	SY, R, AT
162	bne	AT, 0b
163
164	/* Shift-down and subtract loop.  Each iteration compares our scaled
165	   Y (SY) with the remainder (R); if SY <= R then X is divisible by
166	   Y's scalar (S) so add it to the quotient (Q).  */
1672:	addq	Q, S, t3
168	srl	S, 1, S
169	cmpule	SY, R, AT
170	subq	R, SY, t4
171
172	cmovne	AT, t3, Q
173	cmovne	AT, t4, R
174	srl	SY, 1, SY
175	bne	S, 2b
176
177	br	$q_low_ret
178
179	.align	4
180$fix_sign_in:
181	/* If we got here, then X|Y is negative.  Need to adjust everything
182	   such that we're doing unsigned division in the fixup loop.  */
183	/* T5 is true if result should be negative.  */
184	xor	X, Y, AT
185	cmplt	AT, 0, t5
186	cmplt	X, 0, AT
187	negq	X, t0
188
189	cmovne	AT, t0, X
190	cmplt	Y, 0, AT
191	negq	Y, t0
192
193	cmovne	AT, t0, Y
194	blbc	t5, $fix_sign_in_ret1
195
196	cvttq/c	$f0, $f0
197	_FTOIT	$f0, Q, 8
198	.align	3
199	negq	Q, Q
200	br	$fix_sign_in_ret2
201
202$divbyzero:
203	mov	a0, v0
204	lda	a0, GEN_INTDIV
205	call_pal PAL_gentrap
206	stq	zero, 0(v0)
207	stq	zero, 8(v0)
208
209#if FRAME > 0
210	lda	sp, FRAME(sp)
211#endif
212	ret
213
214	.end	ldiv
215
216weak_alias (ldiv, lldiv)
217weak_alias (ldiv, imaxdiv)
218