/* Assembly support functions for libgcc1.
 *
 *   Copyright (C) 1997 Free Software Foundation, Inc.
 *   Contributed by Cygnus Support
 * 
 * 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
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 * 
 * In addition to the permissions in the GNU General Public License, the
 * Free Software Foundation gives you unlimited permission to link the
 * compiled version of this file into combinations with other programs,
 * and to distribute those combinations without any restriction coming
 * from the use of this file.  (The General Public License restrictions
 * do apply in other respects; for example, they cover modification of
 * the file, and distribution when not linked into a combine
 * executable.)
 * 
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 */


#ifdef L_udivsi3

/* For division, we use the following algorithm:
 *
 *	unsigned
 *	__divsi3 (unsigned a, unsigned b)
 *	{
 *	  unsigned al = a;
 *	  unsigned ah = 0;
 *	  unsigned tmpf;
 *	  int i;
 *
 *	  for (i = 32; i > 0; i--)
 *	    {
 *	      ah = (ah << 1) | (al >> 31);
 *	      tmpf = (ah >= b) ? 1 : 0;
 *	      ah -= ((tmpf) ? b : 0);
 *	      al = (al << 1) | tmpf;
 *	    }
 *
 *	  return al;	// for __udivsi3
 *	  return ah;	// for __umodsi3
 *	}
 */

	.file	"_udivsi3"
	.text
	.globl	__umodsi3
	.globl	__udivsi3
	.type	__umodsi3,@function
	.type	__udivsi3,@function
	.stabs	"libgcc1.asm",100,0,0,__umodsi3
	.stabs	"int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0
	.stabs	"__umodsi3:F(0,1)",36,0,1,__umodsi3
	.stabs	"a:P(0,1)",64,0,1,2
	.stabs	"b:P(0,1)",64,0,1,3

__umodsi3:
	bra.s .Lmerge		|| orfg	f1,f1,1		; indicate this is __umodsi3
.Lumod:
	.size	__umodsi3,.Lumod-__umodsi3
	.stabs	"",36,0,0,.Lumod-__umodsi3

	.stabs	"__udivsi3:F(0,1)",36,0,1,__udivsi3
	.stabs	"a:P(0,1)",64,0,1,2
	.stabs	"b:P(0,1)",64,0,1,3
__udivsi3:
	andfg	f1,f1,0		|| nop			; indicate this is __udivsi3

.Lmerge:
	; r2 = al
	; r3 = b
	; r4 = ah
	; r5 = loop counter
	; f0 = tmpf
	; f1 = 1 if this is mod, 0 if this is div
	or	 r4,r0,0	|| sub	 r5,r0,-32	; ah = 0, loop = 32

.Lloop:
	src	 r4,r2,-1	|| sub	 r5,r5,1	; ah = (ah << 1) | (al >> 31); decrement loop count
	cmpuge	 f0,r4,r3	|| sra	 r2,r2,-1	; f0 = (ah >= b); al <<= 1
	sub/tx	 r4,r4,r3	|| or/tx r2,r2,1	; ah -= (tmpf) ? b : 0; al |= tmpf
	bratnz.s r5,.Lloop	|| nop			; loop back if not done
	jmp	 link           || or/xt r2,r0,r4	; if mod, update register, then return to user
.Ludiv:
	.size	 __udivsi3,.Ludiv-__udivsi3
	.stabs	"",36,0,0,.Ludiv-__udivsi3

#endif /* L_udivsi3 */


#ifdef L_divsi3

/* For division, we use the following algorithm:
 *
 *	unsigned
 *	__divsi3 (unsigned a, unsigned b)
 *	{
 *	  unsigned al = __builtin_abs (a);
 *	  unsigned b2 = __builtin_abs (b);
 *	  unsigned ah = 0;
 *	  unsigned tmpf;
 *	  int i;
 *
 *	  for (i = 32; i > 0; i--)
 *	    {
 *	      ah = (ah << 1) | (al >> 31);
 *	      tmpf = (ah >= b2) ? 1 : 0;
 *	      ah -= ((tmpf) ? b2 : 0);
 *	      al = (al << 1) | tmpf;
 *	    }
 *
 *	  if (a < 0)
 *	    ah = -ah, al = -al;
 *
 *	  if (b < 0)
 *	    al = -al;
 *
 *	  return al;	// for __divsi3
 *	  return ah;	// for __modsi3
 *	}
 */

	.file	"_divsi3"
	.text
	.globl	__modsi3
	.globl	__divsi3
	.type	__modsi3,@function
	.type	__divsi3,@function
	.stabs	"libgcc1.asm",100,0,0,__modsi3
	.stabs	"int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0
	.stabs	"__modsi3:F(0,1)",36,0,1,__modsi3
	.stabs	"a:P(0,1)",64,0,1,2
	.stabs	"b:P(0,1)",64,0,1,3

__modsi3:
	bra.s .Lmerge		|| orfg	f1,f1,1		; indicate this is __modsi3
.Lmod:
	.size	__modsi3,.Lmod-__modsi3
	.stabs	"",36,0,0,.Lmod-__modsi3

	.stabs	"__divsi3:F(0,1)",36,0,1,__divsi3
	.stabs	"a:P(0,1)",64,0,1,2
	.stabs	"b:P(0,1)",64,0,1,3
__divsi3:
	andfg	f1,f1,0		|| nop			; indicate this is __divsi3

.Lmerge:
	; r2 = al
	; r3 = b2
	; r4 = ah
	; r5 = loop counter
	; r6 = a
	; r7 = b
	; f0 = tmpf
	; f1 = 1 if this is mod, 0 if this is div
	or	 r6,r0,r2	|| or	  r7,r0,r3	; copy original inputs
	abs	 r2,r2		|| abs	  r3,r3		; make both postive
	or	 r4,r0,0	|| sub	 r5,r0,-32	; ah = 0, loop = 32

.Lloop:
	src	 r4,r2,-1	|| sub	  r5,r5,1	; ah = (ah << 1) | (al >> 31); decrement loop count
	cmpuge	 f0,r4,r3	|| sra	  r2,r2,-1	; f0 = (ah >= b); al <<= 1
	sub/tx	 r4,r4,r3	|| or/tx  r2,r2,1	; ah -= (tmpf) ? b : 0; al |= tmpf
	bratnz.s r5,.Lloop	|| nop			; loop back if not done
	cmplt    f0,r6,0	|| nop			; f0 = (a < 0)

	sub/tx	 r2,r0,r2	|| sub/tx r4,r0,r4	; negate both al, ah if (a < 0)
	cmplt	 f0,r7,0	-> sub/tx r2,r0,r2	; negate al if (b < 0)
	jmp	 link		|| or/xt  r2,r0,r4	; update result if mod; return to user
.Ldiv:
	.size	 __divsi3,.Ldiv-__divsi3
	.stabs	"",36,0,0,.Ldiv-__divsi3

#endif /* L_divsi3 */
