hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame sysdeps/alpha/ldiv.S

Packit 6c4009
/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Richard Henderson <rth@tamu.edu>.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library.  If not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include "div_libc.h"
Packit 6c4009
Packit 6c4009
#undef FRAME
Packit 6c4009
#ifdef __alpha_fix__
Packit 6c4009
#define FRAME 0
Packit 6c4009
#else
Packit 6c4009
#define FRAME 16
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#undef X
Packit 6c4009
#undef Y
Packit 6c4009
#define X $17
Packit 6c4009
#define Y $18
Packit 6c4009
Packit 6c4009
	.set noat
Packit 6c4009
Packit 6c4009
	.align 4
Packit 6c4009
	.globl ldiv
Packit 6c4009
	.ent ldiv
Packit 6c4009
ldiv:
Packit 6c4009
	.frame sp, FRAME, ra
Packit 6c4009
#if FRAME > 0
Packit 6c4009
	lda	sp, -FRAME(sp)
Packit 6c4009
#endif
Packit 6c4009
#ifdef PROF
Packit 6c4009
	.set	macro
Packit 6c4009
	ldgp	gp, 0(pv)
Packit 6c4009
	lda	AT, _mcount
Packit 6c4009
	jsr	AT, (AT), _mcount
Packit 6c4009
	.set	nomacro
Packit 6c4009
	.prologue 1
Packit 6c4009
#else
Packit 6c4009
	.prologue 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	beq	Y, $divbyzero
Packit 6c4009
	excb
Packit 6c4009
	mf_fpcr	$f10
Packit 6c4009
Packit 6c4009
	_ITOFT2	X, $f0, 0, Y, $f1, 8
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
	cvtqt	$f0, $f0
Packit 6c4009
	cvtqt	$f1, $f1
Packit 6c4009
	divt/c	$f0, $f1, $f0
Packit 6c4009
	unop
Packit 6c4009
Packit 6c4009
	/* Check to see if X fit in the double as an exact value.  */
Packit 6c4009
	sll	X, (64-53), AT
Packit 6c4009
	sra	AT, (64-53), AT
Packit 6c4009
	cmpeq	X, AT, AT
Packit 6c4009
	beq	AT, $x_big
Packit 6c4009
Packit 6c4009
	/* If we get here, we're expecting exact results from the division.
Packit 6c4009
	   Do nothing else besides convert and clean up.  */
Packit 6c4009
	cvttq/c	$f0, $f0
Packit 6c4009
	excb
Packit 6c4009
	mt_fpcr	$f10
Packit 6c4009
	_FTOIT	$f0, $0, 0
Packit 6c4009
Packit 6c4009
$egress:
Packit 6c4009
	mulq	$0, Y, $1
Packit 6c4009
	subq	X, $1, $1
Packit 6c4009
Packit 6c4009
	stq	$0, 0($16)
Packit 6c4009
	stq	$1, 8($16)
Packit 6c4009
	mov	$16, $0
Packit 6c4009
Packit 6c4009
#if FRAME > 0
Packit 6c4009
	lda	sp, FRAME(sp)
Packit 6c4009
#endif
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
$x_big:
Packit 6c4009
	/* If we get here, X is large enough that we don't expect exact
Packit 6c4009
	   results, and neither X nor Y got mis-translated for the fp
Packit 6c4009
	   division.  Our task is to take the fp result, figure out how
Packit 6c4009
	   far it's off from the correct result and compute a fixup.  */
Packit 6c4009
Packit 6c4009
#define Q	v0		/* quotient */
Packit 6c4009
#define R	t0		/* remainder */
Packit 6c4009
#define SY	t1		/* scaled Y */
Packit 6c4009
#define S	t2		/* scalar */
Packit 6c4009
#define QY	t3		/* Q*Y */
Packit 6c4009
Packit 6c4009
	/* The fixup code below can only handle unsigned values.  */
Packit 6c4009
	or	X, Y, AT
Packit 6c4009
	mov	$31, t5
Packit 6c4009
	blt	AT, $fix_sign_in
Packit 6c4009
$fix_sign_in_ret1:
Packit 6c4009
	cvttq/c	$f0, $f0
Packit 6c4009
Packit 6c4009
	_FTOIT	$f0, Q, 8
Packit 6c4009
$fix_sign_in_ret2:
Packit 6c4009
	mulq	Q, Y, QY
Packit 6c4009
	excb
Packit 6c4009
	mt_fpcr	$f10
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
	subq	QY, X, R
Packit 6c4009
	mov	Y, SY
Packit 6c4009
	mov	1, S
Packit 6c4009
	bgt	R, $q_high
Packit 6c4009
Packit 6c4009
$q_high_ret:
Packit 6c4009
	subq	X, QY, R
Packit 6c4009
	mov	Y, SY
Packit 6c4009
	mov	1, S
Packit 6c4009
	bgt	R, $q_low
Packit 6c4009
Packit 6c4009
$q_low_ret:
Packit 6c4009
	negq	Q, t4
Packit 6c4009
	cmovlbs	t5, t4, Q
Packit 6c4009
	br	$egress
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
	/* The quotient that we computed was too large.  We need to reduce
Packit 6c4009
	   it by S such that Y*S >= R.  Obviously the closer we get to the
Packit 6c4009
	   correct value the better, but overshooting high is ok, as we'll
Packit 6c4009
	   fix that up later.  */
Packit 6c4009
0:
Packit 6c4009
	addq	SY, SY, SY
Packit 6c4009
	addq	S, S, S
Packit 6c4009
$q_high:
Packit 6c4009
	cmpult	SY, R, AT
Packit 6c4009
	bne	AT, 0b
Packit 6c4009
Packit 6c4009
	subq	Q, S, Q
Packit 6c4009
	unop
Packit 6c4009
	subq	QY, SY, QY
Packit 6c4009
	br	$q_high_ret
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
	/* The quotient that we computed was too small.  Divide Y by the
Packit 6c4009
	   current remainder (R) and add that to the existing quotient (Q).
Packit 6c4009
	   The expectation, of course, is that R is much smaller than X.  */
Packit 6c4009
	/* Begin with a shift-up loop.  Compute S such that Y*S >= R.  We
Packit 6c4009
	   already have a copy of Y in SY and the value 1 in S.  */
Packit 6c4009
0:
Packit 6c4009
	addq	SY, SY, SY
Packit 6c4009
	addq	S, S, S
Packit 6c4009
$q_low:
Packit 6c4009
	cmpult	SY, R, AT
Packit 6c4009
	bne	AT, 0b
Packit 6c4009
Packit 6c4009
	/* Shift-down and subtract loop.  Each iteration compares our scaled
Packit 6c4009
	   Y (SY) with the remainder (R); if SY <= R then X is divisible by
Packit 6c4009
	   Y's scalar (S) so add it to the quotient (Q).  */
Packit 6c4009
2:	addq	Q, S, t3
Packit 6c4009
	srl	S, 1, S
Packit 6c4009
	cmpule	SY, R, AT
Packit 6c4009
	subq	R, SY, t4
Packit 6c4009
Packit 6c4009
	cmovne	AT, t3, Q
Packit 6c4009
	cmovne	AT, t4, R
Packit 6c4009
	srl	SY, 1, SY
Packit 6c4009
	bne	S, 2b
Packit 6c4009
Packit 6c4009
	br	$q_low_ret
Packit 6c4009
Packit 6c4009
	.align	4
Packit 6c4009
$fix_sign_in:
Packit 6c4009
	/* If we got here, then X|Y is negative.  Need to adjust everything
Packit 6c4009
	   such that we're doing unsigned division in the fixup loop.  */
Packit 6c4009
	/* T5 is true if result should be negative.  */
Packit 6c4009
	xor	X, Y, AT
Packit 6c4009
	cmplt	AT, 0, t5
Packit 6c4009
	cmplt	X, 0, AT
Packit 6c4009
	negq	X, t0
Packit 6c4009
Packit 6c4009
	cmovne	AT, t0, X
Packit 6c4009
	cmplt	Y, 0, AT
Packit 6c4009
	negq	Y, t0
Packit 6c4009
Packit 6c4009
	cmovne	AT, t0, Y
Packit 6c4009
	blbc	t5, $fix_sign_in_ret1
Packit 6c4009
Packit 6c4009
	cvttq/c	$f0, $f0
Packit 6c4009
	_FTOIT	$f0, Q, 8
Packit 6c4009
	.align	3
Packit 6c4009
	negq	Q, Q
Packit 6c4009
	br	$fix_sign_in_ret2
Packit 6c4009
Packit 6c4009
$divbyzero:
Packit 6c4009
	mov	a0, v0
Packit 6c4009
	lda	a0, GEN_INTDIV
Packit 6c4009
	call_pal PAL_gentrap
Packit 6c4009
	stq	zero, 0(v0)
Packit 6c4009
	stq	zero, 8(v0)
Packit 6c4009
Packit 6c4009
#if FRAME > 0
Packit 6c4009
	lda	sp, FRAME(sp)
Packit 6c4009
#endif
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	.end	ldiv
Packit 6c4009
Packit 6c4009
weak_alias (ldiv, lldiv)
Packit 6c4009
weak_alias (ldiv, imaxdiv)