/*
   This file is part of Numerix.  Numerix 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 of the License, or (at your option) any later version.

   This program 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; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA 
*/

/* +------------------------------------------------------------------------+
   |                                                                        |
   |                      Entiers de longueur arbitraire                    |
   |                                                                        |
   |                             Division                                   |
   |                                                                        |
   +------------------------------------------------------------------------+ */

/* M. Quercia, 01/08/2001 */

#include "macros-s.h"

         /* +---------------------------------------------+
            |  c <- a div b, retourne a mod b, b non nul  |
            +---------------------------------------------+ */

/* ndouble xn(quo_2)(naturel a, longueur la, ndouble b, naturel c) */
#ifdef have_sn_quo_2
ENTER(sn_quo_2)
#undef  b0
#undef  b1
#define b0     arg3
#define b1     arg4

/* variables locales */
#undef  loc_b0
#undef  loc_b1
#undef  u0
#undef  u1
#undef  compte
#undef  stack_size
#define loc_b0   -16(%ebp)
#define loc_b1   -20(%ebp)
#define u0       -24(%ebp)
#define u1       -28(%ebp)
#define compte   -32(%ebp)
#define stack_size 20

        movl   a,%esi
        movl   la,%ecx
        movl   c,%edi
        movl   b1,%eax
        testl  %eax,%eax
        jnz    .Lsn_quo_2_two_digits

        /* division à un chiffre */
        xorl   %edx,%edx
        movl   b0,%ebx
        jecxz  .Lsn_quo_2_one_done

        .align 4
.Lsn_quo_2_one_loop:
        movl   -4(%esi,%ecx,4),%eax
        divl   %ebx
        movl   %eax,-4(%edi,%ecx,4)
        loop   .Lsn_quo_2_one_loop
.Lsn_quo_2_one_done:
        movl   %edx,%eax
        xorl   %edx,%edx
        RETURN

        /* évacue les petits quotients */
.Lsn_quo_2_two_digits:
        xorl   %edx,%edx
        decl   %ecx
        js     .Lsn_quo_2_two_a_nul
        jnz    .Lsn_quo_2_two_big_a
        movl   (%esi),%eax
        movl   %edx,(%edi)
        RETURN
.Lsn_quo_2_two_a_nul:    
        movl   %edx,%eax
        RETURN
.Lsn_quo_2_two_big_a:

        /* décale b pour avoir b1 >= BASE/2 */
        subl   $stack_size,%esp
        movl   %ecx,compte
        leal   (%esi,%ecx,4),%esi   /* pointe sur la fin de a */
        leal   (%edi,%ecx,4),%edi   /* pointe sur la fin de c */
        movl   b0,%ebx
        bsr    %eax,%ecx
        negl   %ecx
        addl   $31,%ecx 
        shldl  %cl,%ebx,%eax
        shll   %cl,%ebx
        movl   %eax,loc_b1
        movl   %ebx,loc_b0

        /* décale et divise les chiffres de a */
        xorl   %edx,%edx
        movl   (%esi),%eax
        movl   %edx,(%edi)
        leal   -4(%esi),%esi
        movl   (%esi),%ebx
        shldl  %cl,%eax,%edx
        shldl  %cl,%ebx,%eax

        .align 4
.Lsn_quo_2_two_loop:
        leal   -4(%edi),%edi
        cmpl   loc_b1,%edx
        je     .Lsn_quo_2_two_big_q
        divl   loc_b1           /* q <- u/b1 */
        jmp    .Lsn_quo_2_two_small_u

.Lsn_quo_2_two_big_q:
        addl   %eax,%edx
        movl   $-1,%eax         /* q <- base-1 */
        jnc    .Lsn_quo_2_two_small_u

        leal   -4(%esi),%esi    /* reste >= base^2, q est bon */
        movl   %eax,(%edi)
        movl   %ebx,%eax
        movl   compte,%ebx
        decl   %ebx
        movl   %ebx,compte
        pushf                   /* sauve test fin de boucle */
        jz     .Lsn_quo_2_two_next_digit
        movl   (%esi),%ebx
.Lsn_quo_2_two_next_digit:
        addl   loc_b0,%eax
        adcl   $0,%edx
        subl   loc_b0,%edx
        jmp    .Lsn_quo_2_two_cont

.Lsn_quo_2_two_small_u:
        movl   %eax,(%edi)
        leal   -4(%esi),%esi
        movl   %ebx,%eax
        movl   compte,%ebx
        decl   %ebx
        movl   %ebx,compte
        pushf                   /* sauve test fin de boucle */
        jz     .Lsn_quo_2_two_next_digit1
        movl   (%esi),%ebx
.Lsn_quo_2_two_next_digit1:

        shldl  %cl,%ebx,%eax    /* u <- (u mod b1) << HW + ch.suivant */
        movl   %edx,u1
        movl   %eax,u0

        movl   loc_b0,%eax      /* v <- q*b0 */
        mull   (%edi)
        subl   u0,%eax          /* u >= v ?  */
        sbbl   u1,%edx
        jb     .Lsn_quo_2_two_q_ok
        ja     .Lsn_quo_2_two_q_ajust
        testl  %eax,%eax
        jz     .Lsn_quo_2_two_q_ok

.Lsn_quo_2_two_q_ajust:
        decl   (%edi)          /* alors décrémente q */
        subl   loc_b0,%eax
        sbbl   loc_b1,%edx
        jb     .Lsn_quo_2_two_q_ok
        ja     .Lsn_quo_2_two_q_ajust
        testl  %eax,%eax
        jnz    .Lsn_quo_2_two_q_ajust

.Lsn_quo_2_two_q_ok:
        negl   %eax            /* u <- u - v */
        adcl   $0,%edx
        negl   %edx
.Lsn_quo_2_two_cont:
        popf                   /* récupère test fin de boucle */
        jnz    .Lsn_quo_2_two_loop

        shrdl  %cl,%edx,%eax   /* décale le reste final */
        shrl   %cl,%edx

EXIT(sn_quo_2)
#endif

                        /* +---------------+
                           |  idem dans Z  |
                           +---------------+ */

/* zdouble xz(quo_2)(entier *a, zdouble b, entier *c) */
#ifdef have_sz_quo_2
ENTER(sz_quo_2)

        /* aiguillage selon la longueur de b */
        movl   za,%esi
        movl   arg2,%eax
        movl   arg3,%edx
        movl   arg4,%ebx
        movl   (%esi),%ecx
        testl  %edx,%edx
        jns    .Lsz_quo_2_bpos
        xorl   $SIGN_m,%ecx
        negl   %eax
        adcl   $0,%edx
        negl   %edx
.Lsz_quo_2_bpos:
        jne    .Lsz_quo_2_b2

        /* division à un chiffre */
        movl   %ecx,(%ebx)
        andl   $LONG_m,%ecx
        jecxz  .Lsz_quo_2_anul
        movl   %eax,%edi

        .align 4                  /* divise chaque chiffre de a */
.Lsz_quo_2_one_loop:
        movl   (%esi,%ecx,4),%eax
        divl   %edi
        movl   %eax,(%ebx,%ecx,4)
        loop   .Lsz_quo_2_one_loop

        testl  $-1,(%ebx)         /* si le quotient est négatif */
        jns    .Lsz_quo_2_one_finish
        testl  %edx,%edx          /* et le reste est non nul */
        jz     .Lsz_quo_2_one_finish
        subl   %edi,%edx          /* alors |r| <- b-|r| */
        negl   %edx
.Lsz_quo_2_one_inc_q:
        incl   %ecx
        incl   (%ebx,%ecx,4)      /* et |q| <- |q|+1 */
        jz     .Lsz_quo_2_one_inc_q

.Lsz_quo_2_one_finish:
        movl   (%ebx),%ecx        /* ajuste la longueur de q */
        andl   $LONG_m,%ecx
        testl  $-1,(%ebx,%ecx,4)
        jnz    .Lsz_quo_2_one_q_ok
        decl   (%ebx)
.Lsz_quo_2_one_q_ok:

        movl   %edx,%eax         /* reste <- sgn(b)*reste */
        xorl   %edx,%edx
        testl  $-1,arg3
        jns    .Lsz_quo_2_one_r_ok
        negl   %eax
        adcl   $0,%edx
        negl   %edx
.Lsz_quo_2_one_r_ok:
        RETURN

        /* cas a = 0 */
.Lsz_quo_2_anul:
        movl   %ecx,(%ebx)
        movl   %ecx,%eax
        movl   %ecx,%edx
        RETURN

        /* division à deux chiffres */
.Lsz_quo_2_b2:
        movl   %ecx,(%ebx)        /* longueur et signe quotient */
        andl   $LONG_m,%ecx
        jecxz  .Lsz_quo_2_anul
        leal   4(%ebx),%ebx       /* effectue la division dans N */
        pushl  %ebx
        pushl  %edx
        pushl  %eax
        pushl  %ecx
        leal   4(%esi),%esi
        pushl  %esi
        call   sn_quo_2

        movl   -4(%ebx),%esi
        testl  %esi,%esi          /* si le quotient est négatif */
        jns    .Lsz_quo_2_two_finish
        testl  %edx,%edx          /* et le reste est non nul */
        jnz    .Lsz_quo_2_two_chgr
        testl  %eax,%eax
        jz     .Lsz_quo_2_two_finish

.Lsz_quo_2_two_chgr:
        movl   %eax,%ecx          /* alors |r| <- b-|r| */
        movl   8(%esp),%eax
        subl   %ecx,%eax
        movl   %edx,%ecx
        movl   12(%esp),%edx
        sbbl   %ecx,%edx

        xorl   %ecx,%ecx
.Lsz_quo_2_two_inc_q:
        incl   %ecx
        incl   (%ebx,%ecx,4)      /* et |q| <- |q|+1 */
        jz     .Lsz_quo_2_two_inc_q

.Lsz_quo_2_two_finish:
        movl   4(%esp),%ecx       /* ajuste la longueur de q */
        testl  $-1,-8(%ebx,%ecx,4)
        jnz    .Lsz_quo_2_two_q_ok
        decl   %esi
.Lsz_quo_2_two_q_ok:
        decl   %esi
        movl   %esi,-4(%ebx)

        testl  $-1,arg3           /* signe du reste */
        jns    .Lsz_quo_2_exit
        negl   %eax
        adcl   $0,%edx
        negl   %edx

EXIT(sz_quo_2)
#endif

/* +---------------------------------------------------------------------------+
   |  c <- a div b, d <- a mod b, lb >= 3, b[lb-1] non nul, algorithme en n^2  |
   +---------------------------------------------------------------------------+ */

/* void xn(quo_n2) (naturel a, longueur la, naturel b, longueur lb, naturel c, naturel d) */
#ifdef have_sn_quo_n2
ENTER(sn_quo_n2)

        /* Algorithme 4.3.1-D de Knuth avec décalage virtuel */

/* variables locales */
#undef  b0
#undef  b1
#undef  q
#undef  u1
#undef  compte
#undef  shift_count
#undef  stack_size
#define b0          -16(%ebp)
#define b1          -20(%ebp)
#define q           -24(%ebp)
#define u1          -28(%ebp)
#define compte      -32(%ebp)
#define shift_count -36(%ebp)
#define stack_size 24

        /* d <- a */
.Lsn_quo_n2_aux_entry:
        movl   a,%edi
        movl   d,%esi
        movl   la,%ecx
        movl   %ecx,%edx
        jecxz  .Lsn_quo_n2_copy_done
        cmpl   %esi,%edi
        je     .Lsn_quo_n2_copy_done
        .align 4
.Lsn_quo_n2_copy:
        movl   -4(%edi,%ecx,4),%eax
        movl   %eax,-4(%esi,%ecx,4)
        loop   .Lsn_quo_n2_copy
.Lsn_quo_n2_copy_done:
        leal   (%esi,%edx,4),%esi

        /* si a < b, complète par des zéros et c'est fini */
        movl   lb,%ecx
        subl   %ecx,%edx
        jnb    .Lsn_quo_n2_big_a
        xorl   %eax,%eax
        .align 4
.Lsn_quo_n2_fill_0:
        movl   %eax,(%esi)
        leal   4(%esi),%esi
        incl   %edx
        jne    .Lsn_quo_n2_fill_0
        movl   c,%ebx
        movl   $0,(%ebx)
        RETURN

.Lsn_quo_n2_big_a:
        /* si le chiffre de tête de d est plus grand que celui de b */
        /* alors prolonge d d'un zéro                               */
        movl   b,%edi
        leal   (%edi,%ecx,4),%edi
        movl   -4(%esi),%eax
        cmpl   -4(%edi),%eax
        jb     .Lsn_quo_n2_a_head_ok
        movl   $0,(%esi)
        leal   4(%esi),%esi
        incl   %edx
        jmp    .Lsn_quo_n2_D1

        /* chiffre de tête de c <- 0 */
.Lsn_quo_n2_a_head_ok:
        movl   c,%ebx
        movl   $0,(%ebx,%edx,4)
        testl  %edx,%edx        /* si la = lb la division est terminée */
        jz     .Lsn_quo_n2_exit

        /* D1. Normaliser pour avoir b[lb-1] >= BASE/2 */
.Lsn_quo_n2_D1:
        subl   $stack_size,%esp 
        movl   -8(%edi),%ebx
        movl   -4(%edi),%eax
        bsr    %eax,%ecx
        negl   %ecx
        addl   $31,%ecx
        shldl  %cl,%ebx,%eax
        movl   %eax,b1
        movl   -12(%edi),%eax
        shldl  %cl,%eax,%ebx
        movl   %ebx,b0
        movl   %ecx,shift_count

        /* D2. Boucler sur les chiffres de d */
        .align 4
.Lsn_quo_n2_loop:
        movl   %edx,compte

        /* Décale les quatre chiffres de tête de a et divise par b1:b0 */
        leal   -4(%esi),%esi
        movl   (%esi),%edx       /* edx <- a[la-lb]   */
        movl   -4(%esi),%ebx     /* ebx <- a[la-lb-1] */
        movl   -8(%esi),%eax     /* eax <- a[la-lb-2] */
        movl   shift_count,%ecx
        shldl  %cl,%ebx,%edx     /* décale edx        */
        shldl  %cl,%eax,%ebx     /* décale ebx        */
        movl   %ebx,u1
        movl   -12(%esi),%ebx    /* ebx <- a[la-lb-3] */
        shldl  %cl,%ebx,%eax     /* décale eax        */
        movl   %eax,%ebx         /* edx:eax:ebx <- u2:u1:u0 */
        movl   u1,%eax

        cmpl   %edx,b1           /* si u2 < b1 ... */
        je     .Lsn_quo_n2_big_q
        divl   b1                /* alors q <- u2:u1 div b1 */
        movl   %eax,q            /* et  edx <- u2:u1 mod b1 */
        jmp    .Lsn_quo_n2_small_u
.Lsn_quo_n2_big_q:
        addl   %eax,%edx        /* sinon q <- base-1 */
        movl   $-1,q            /* et edx <- u2+u1   */
        jc     .Lsn_quo_n2_q_ok  /* si >= base alors q est bon */
.Lsn_quo_n2_small_u:
        movl   %edx,%ecx        /* compare u1:u0 à q*b0 */
        movl   b0,%eax
        mull   q
        subl   %eax,%ebx
        sbbl   %edx,%ecx
        jnb    .Lsn_quo_n2_q_ok  /* si >= alors q est bon */
        decl   q                /* sinon décrémente q    */
        addl   b0,%ebx          /* et met à jour u       */
        adcl   b1,%ecx
        jc     .Lsn_quo_n2_q_ok     /* encore trop grand ?   */
        decl   q                /* alors on redécrémente */
.Lsn_quo_n2_q_ok:        

        /* D4. d <- d - qb */
        movl   lb,%ecx
        negl   %ecx
        xorl   %ebx,%ebx
        .align 4
.Lsn_quo_n2_sub_qb:
        movl   (%edi,%ecx,4),%eax
        mull   q
        addl   %ebx,%eax
        adcl   $0,%edx
        subl   %eax,(%esi,%ecx,4)
        adcl   $0,%edx
        movl   %edx,%ebx
        incl   %ecx
        jne    .Lsn_quo_n2_sub_qb
        cmpl   %ebx,(%esi)
        je     .Lsn_quo_n2_store_q

        /* D5-D6. si d < qb ajoute b */
        decl   q
        movl   lb,%ecx
        negl   %ecx
        clc
        .align 4
.Lsn_quo_n2_add_b:
        movl   (%edi,%ecx,4),%eax
        adcl   %eax,(%esi,%ecx,4)
        incl   %ecx
        jne    .Lsn_quo_n2_add_b


        /* range le quotient et passe au chiffre suivant */
.Lsn_quo_n2_store_q:
        movl   c,%ebx
        movl   compte,%edx
        movl   q,%eax
        decl   %edx
        movl   %eax,(%ebx,%edx,4)
        jne    .Lsn_quo_n2_loop

EXIT(sn_quo_n2)
#endif


	           /* +--------------------------+
                      |  Division en n^2 dans Z  |
                      +--------------------------+ */

#ifdef have_sz_quo_n2
/* c <- a div b, d <- a mod b */
/* longueur(c) >= la-lb, longueur(d) >= max(la+2,lb) */
/* void xz(quo_n2)(entier *a, entier *b, entier *c, entier *d) */
ENTER(sz_quo_n2)

/* variables locales */
#undef  chead
#undef  loc_d 
#undef  loc_c
#undef  loc_lb
#undef  loc_b 
#undef  loc_la
#undef  loc_a 
#undef  stack_size
#define chead     -16(%ebp)
#define loc_d     -20(%ebp)
#define loc_c     -24(%ebp)
#define loc_lb    -28(%ebp)
#define loc_b     -32(%ebp)
#define loc_la    -36(%ebp)
#define loc_a     -40(%ebp)
#define stack_size 28

        /* sépare les signes et les longueurs */
        movl   za,%esi
        movl   zb,%edi
        movl   (%esi),%edx
        movl   %edx,%eax
        movl   (%edi),%ecx
        xorl   %ecx,%eax
        andl   $LONG_m,%ecx
        andl   $LONG_m,%edx
        jnz    .Lsz_quo_n2_a_nonull

        movl   zc,%ebx
        movl   %edx,(%ebx)      /* si a = 0 alors c = d = 0 */
        movl   zd,%esi
	testl  %esi,%esi
	jz     .Lsz_quo_n2_nod0
        movl   %edx,(%esi)
.Lsz_quo_n2_nod0:
        RETURN

.Lsz_quo_n2_a_nonull:
        cmpl   %ecx,%edx       /* si la < lb ne fait pas la division */
        jae    .Lsz_quo_n2_a_big
        testl  %eax,%eax
        js     .Lsz_quo_n2_nodiv_neg

        movl   (%edi),%eax    /* ab > 0 => q = 0,  r = a */
        movl   zc,%ebx
        movl   $0,(%ebx)
        movl   zd,%edi
	testl  %edi,%edi
	jz     .Lsz_quo_n2_nod1
        andl   $SIGN_m,%eax
        movl   %edx,%ecx
        orl    %eax,%edx
        cmpl   %esi,%edi
        jz     .Lsz_quo_n2_copy_done
        .align 4
.Lsz_quo_l_copy_loop:
        movl   (%esi,%ecx,4),%eax
        movl   %eax,(%edi,%ecx,4)
        loop   .Lsz_quo_l_copy_loop
.Lsz_quo_n2_copy_done:
        movl   %edx,(%edi)
.Lsz_quo_n2_nod1:	
        RETURN

.Lsz_quo_n2_nodiv_neg:
        movl   zd,%ebx             /* ab < 0 => q = -1, r = a - b */
	testl  %ebx,%ebx
	jz     .Lsz_quo_n2_nod2
        subl   %edx,%ecx
        leal   4(%esi,%edx,4),%esi
        leal   4(%edi,%edx,4),%edi
        leal   4(%ebx,%edx,4),%ebx
        negl   %edx
        clc

        .align 4           
.Lsz_quo_n2_sub_b:
        movl   (%edi,%edx,4),%eax  /* soustrait les chiffres communs */
        sbbl   (%esi,%edx,4),%eax
        movl   %eax,(%ebx,%edx,4)
        incl   %edx
        jne    .Lsz_quo_n2_sub_b

        leal   (%edi,%ecx,4),%edi  /* copie la fin de b */
        leal   (%ebx,%ecx,4),%ebx
        pushf
        negl   %ecx
        popf
        .align 4
.Lsz_quo_n2_ret_b:
        movl   (%edi,%ecx,4),%eax
        sbbl   %edx,%eax
        movl   %eax,(%ebx,%ecx,4)
        incl   %ecx
        jne    .Lsz_quo_n2_ret_b

        movl   zb,%edi             /* ajuste la longueur de r */
        movl   zd,%esi
        movl   (%edi),%edx
        movl   %edx,%ecx
        andl   $LONG_m,%ecx
        jmp    .Lsz_quo_n2_nodiv_test_r1
        .align 4
.Lsz_quo_n2_nodiv_test_r:
        decl   %ecx
        decl   %edx
        movl   (%esi,%ecx,4),%eax
.Lsz_quo_n2_nodiv_test_r1:
        testl  %eax,%eax
        jz     .Lsz_quo_n2_nodiv_test_r
        movl   %edx,(%esi)
	
.Lsz_quo_n2_nod2:
        movl   zc,%ebx           /* q <- -1 */
        movl   $SIGN_m+1,(%ebx)
        movl   $1,4(%ebx)
        RETURN  

        /* aiguillage selon la longueur de b */
.Lsz_quo_n2_a_big:
        movl   zc,%ebx
        cmpl   $2,%ecx
        jb     .Lsz_quo_n2_b1
        je     .Lsz_quo_n2_b2
        jmp    .Lsz_quo_n2_big_b

.Lsz_quo_n2_b1:
        /* division à un chiffre */
        xorl   $1,%eax            /* longueur et signe quotient */
        pushl  %edx
        pushl  %eax
        movl   %edx,%ecx
        xorl   %edx,%edx
        movl   4(%edi),%edi

        .align 4                  /* divise chaque chiffre de a */
.Lsz_quo_n2_one_loop:
        movl   (%esi,%ecx,4),%eax
        divl   %edi
        movl   %eax,(%ebx,%ecx,4)
        loop   .Lsz_quo_n2_one_loop

        popl   %eax
        testl  %eax,%eax          /* si le quotient est négatif */
        jns    .Lsz_quo_n2_one_finish
        testl  %edx,%edx          /* et le reste est non nul */
        jz     .Lsz_quo_n2_one_finish
        subl   %edi,%edx          /* alors |r| <- b-|r| */
        negl   %edx
.Lsz_quo_n2_one_inc_q:
        incl   %ecx
        incl   (%ebx,%ecx,4)      /* et |q| <- |q|+1 */
        jz     .Lsz_quo_n2_one_inc_q

.Lsz_quo_n2_one_finish:
        popl   %ecx               /* ajuste la longueur de q */
        testl  $-1,(%ebx,%ecx,4)
        jnz    .Lsz_quo_n2_one_q_ok
        decl   %eax
.Lsz_quo_n2_one_q_ok:
        movl   zb,%edi
        movl   (%edi),%ecx
        movl   %eax,(%ebx)

        movl   zd,%esi            /* range le reste */
	testl  %esi,%esi
	jz     .Lsz_quo_n2_nod3
        testl  %edx,%edx
        jz     .Lsz_quo_n2_one_r0
        movl   %edx,4(%esi)
        movl   %ecx,(%esi)
.Lsz_quo_n2_nod3:	
        RETURN
.Lsz_quo_n2_one_r0:
        movl   %edx,(%esi)
        RETURN

        /* division à deux chiffres */
.Lsz_quo_n2_b2:
        xorl   $2,%eax            /* longueur et signe quotient */
        pushl  %eax
        leal   4(%ebx),%eax       /* effectue la division dans N */
        pushl  %eax
        pushl  8(%edi)
        pushl  4(%edi)
        pushl  %edx
        leal   4(%esi),%esi
        pushl  %esi
        call   sn_quo_2

        movl   20(%esp),%esi
        testl  %esi,%esi          /* si le quotient est négatif */
        jns    .Lsz_quo_n2_two_finish
        testl  %edx,%edx          /* et le reste est non nul */
        jnz    .Lsz_quo_n2_two_chgr
        testl  %eax,%eax
        jz     .Lsz_quo_n2_two_finish

.Lsz_quo_n2_two_chgr:
        movl   %eax,%ecx          /* alors |r| <- b-|r| */
        movl   8(%esp),%eax
        subl   %ecx,%eax
        movl   %edx,%ecx
        movl   12(%esp),%edx
        sbbl   %ecx,%edx

        xorl   %ecx,%ecx
.Lsz_quo_n2_two_inc_q:
        incl   %ecx
        incl   (%ebx,%ecx,4)      /* et |q| <- |q|+1 */
        jz     .Lsz_quo_n2_two_inc_q

.Lsz_quo_n2_two_finish:
        movl   4(%esp),%ecx       /* ajuste la longueur de q */
        testl  $-1,-4(%ebx,%ecx,4)
        jnz    .Lsz_quo_n2_two_q_ok
        decl   %esi
.Lsz_quo_n2_two_q_ok:
        decl   %esi
        movl   (%edi),%ecx
        movl   %esi,(%ebx)

        movl   zd,%esi            /* range le reste */
	testl  %esi,%esi
	jz     .Lsz_quo_n2_nod4
        movl   %eax,4(%esi)
        movl   %edx,8(%esi)
        testl  %edx,%edx
        jnz    .Lsz_quo_n2_two_r_ok
        decl   %ecx
        testl  %eax,%eax
        jnz    .Lsz_quo_n2_two_r_ok
        decl   %ecx
.Lsz_quo_n2_two_r_ok:
        movl   %ecx,(%esi)
.Lsz_quo_n2_nod4:	
        RETURN

        /* division à trois chiffres ou plus */
.Lsz_quo_n2_big_b:

        /* prépare les arguments pour sn_quo_n2 */
        subl   $stack_size,%esp
        andl   $SIGN_m,%eax
        orl    %edx,%eax
        subl   %ecx,%eax
        incl   %eax
        movl   %eax,chead
        andl   $LONG_m,%eax
        movl   %ecx,loc_lb
        movl   %edx,loc_la
        leal   4(%esi),%esi
        movl   %esi,loc_a
        movl   zd,%esi
        leal   4(%edi),%edi
        leal   4(%ebx),%ebx
	movl   %edi,loc_b
	movl   %ebx,loc_c

	/* si d == NULL, réserve de la place dans la pile */
	testl  %esi,%esi
	jnz    .Lsz_quo_n2_dok
	movl   %edx,%eax
	negl   %eax
	leal   -12(%esp,%eax,4),%esp
	movl   %esp,%esi
.Lsz_quo_n2_dok:
	leal   4(%esi),%esi
	movl   %esi,loc_d

	/* sauvegarde b s'il va être écrasé */
	cmpl   %edi,%ebx
	je     .Lsz_quo_n2_copy_b
	cmpl   %edi,%esi
	jne    .Lsz_quo_n2_bok

	.align 4
.Lsz_quo_n2_copy_b:
	pushl  -4(%edi,%ecx,4)
	loop   .Lsz_quo_n2_copy_b
	movl   %esp,%edi
	movl   loc_lb,%ecx
.Lsz_quo_n2_bok:
	
        /* division dans N */
	pushl  %esi
	pushl  %ebx
	pushl  %ecx
	pushl  %edi
	pushl  %edx
	pushl  loc_a
	call   sn_quo_n2

        /* correction si ab < 0 et r <> 0 */
.Lsz_quo_n2_corr:
        movl   chead,%eax
        testl  %eax,%eax
        jns    .Lsz_quo_n2_nocorr
        movl   loc_lb,%ecx
        movl   %ecx,%edx
        .align 4
.Lsz_quo_n2_test_r:
        testl  $-1,-4(%esi,%ecx,4)
        jnz    .Lsz_quo_n2_docorr
        loop   .Lsz_quo_n2_test_r
        jmp    .Lsz_quo_n2_nocorr

        /* r <- b - r */
.Lsz_quo_n2_docorr:
        leal   (%esi,%edx,4),%esi
        leal   (%edi,%edx,4),%edi
        negl   %edx
        clc
        .align 4
.Lsz_quo_n2_sub_r:
        movl   (%edi,%edx,4),%ecx
        sbbl   (%esi,%edx,4),%ecx
        movl   %ecx,(%esi,%edx,4)
        incl   %edx
        jne    .Lsz_quo_n2_sub_r
        movl   loc_d,%esi

        /* q <- q + 1 */
.Lsz_quo_n2_incq:
        incl   %edx
        incl   -4(%ebx,%edx,4)
        jz     .Lsz_quo_n2_incq

.Lsz_quo_n2_nocorr:
        /* ajuste la longueur de q */
        movl   %eax,%ecx
        andl   $LONG_m,%ecx
        testl  $-1,-4(%ebx,%ecx,4)
        jnz    .Lsz_quo_n2_qok
        decl   %eax
.Lsz_quo_n2_qok:
        movl   zb,%edi
        movl   (%edi),%edi
        movl   %eax,-4(%ebx)

        /* ajuste la longueur de r */
        movl   %edi,%ecx
        andl   $LONG_m,%ecx
        .align 4
.Lsz_quo_n2_test_r1:
        testl  $-1,-4(%esi,%ecx,4)
        jnz    .Lsz_quo_n2_rok
        decl   %edi
        loop   .Lsz_quo_n2_test_r1
.Lsz_quo_n2_rok:
        movl   %edi,-4(%esi)

EXIT(sz_quo_n2)
#endif
	

         /* +---------------------------------------------+
            |  c <- max(a div b, BASE^lc-1), a <- a - bc  |
            |      retourne un majorant de lg(a)          |
            +---------------------------------------------+ */

#ifdef have_sn_hquo
/* longueur xn(hquo)(naturel a, longueur la, naturel b, longueur lb, naturel c, longueur lc) */
ENTER(sn_hquo)

/* variables locales */
#undef l
#undef i
#undef q
#undef loc_c
#undef stack_size
#define l     -16(%ebp)
#define i     -20(%ebp)
#define q     -24(%ebp)
#define loc_c -28(%ebp)
#define stack_size 16

	/* saute les zéros de tête et teste si a >= b*BASE^lc */
	movl   a,%esi
	movl   b,%edi
	movl   la,%edx
	movl   %edx,%ecx
	subl   lb,%ecx
	subl   arg6,%ecx
	js     .Lsn_hquo_smalla
	jz     .Lsn_hquo_testa1

	.align 4
.Lsn_hquo_testa:
        cmpl   $0,-4(%esi,%edx,4)
	jne    .Lsn_hquo_biga
	decl   %edx
	loop   .Lsn_hquo_testa

.Lsn_hquo_testa1:
	movl   %edx,%ebx
	movl   lb,%ecx
	.align 4
.Lsn_hquo_testa2:
        movl   -4(%esi,%ebx,4),%eax
	cmpl   -4(%edi,%ecx,4),%eax
	jb     .Lsn_hquo_smalla
	jne    .Lsn_hquo_biga
	decl   %ebx
	loop   .Lsn_hquo_testa2

	/* si a est trop grand tronque le quotient */
.Lsn_hquo_biga:
	xorl   %edx,%edx
	movl   lb,%ecx
	.align 4
.Lsn_hquo_badd:
	movl   (%edi,%edx,4),%eax
	adcl   %eax,(%esi,%edx,4)
	incl   %edx
	loop   .Lsn_hquo_badd
	jnc    .Lsn_hquo_badd2
	.align 4
.Lsn_hquo_badd1:
	adcl   $0,(%esi,%edx,4)
	incl   %edx
	jc     .Lsn_hquo_badd1
.Lsn_hquo_badd2:
	movl   arg6,%edx
	leal   (%esi,%edx,4),%esi
	xorl   %edx,%edx
	movl   lb,%ecx
	.align 4
.Lsn_hquo_bsub:
	movl   (%edi,%edx,4),%eax
	sbbl   %eax,(%esi,%edx,4)
	incl   %edx
	loop   .Lsn_hquo_bsub
	jnb    .Lsn_hquo_bsub2
	.align 4
.Lsn_hquo_bsub1:
	sbbl   $0,(%esi,%edx,4)
	incl   %edx
	jb     .Lsn_hquo_bsub1
.Lsn_hquo_bsub2:

	movl   $-1,%eax
	movl   c,%edi
	movl   arg6,%ecx
	.align 4
.Lsn_hquo_bifll:
	movl   %eax,-4(%edi,%ecx,4)
	loop   .Lsn_hquo_bifll
	jmp    .Lsn_hquo_finish

	/* a < b*BASE^lc : effectue la division */   
.Lsn_hquo_smalla:
	subl   $stack_size,%esp
	movl   lb,%ecx
	leal   (%edi,%ecx,4),%edi   /* edi -> fin de b */
	movl   c,%ebx
	movl   arg6,%eax
	movl   %eax,i               /* i <- lc         */
	decl   %eax
	leal   (%ebx,%eax,4),%ebx   /* ebx -> c[lc-1] */
	leal   (%esi,%eax,4),%esi
	leal   (%esi,%ecx,4),%esi   /* esi -> a[lb+lc-1] */
	subl   %eax,%edx            /* l <- la - lc + 1  */
	.align 4

.Lsn_hquo_loop:
	/* si l < lb, quotient = 0 */
	movl   %edx,l               
	movl   %ebx,loc_c
	subl   lb,%edx
	jz     .Lsn_hquo_al
	jg     .Lsn_hquo_ah
	movl   $0,%eax
	jmp    .Lsn_hquo_next_i1

	/* divise les trois chiffres de tête de a par b1:b0 */
.Lsn_hquo_ah:
	movl   (%esi),%edx
.Lsn_hquo_al:
	movl   -4(%esi),%eax
	movl   -8(%esi),%ecx  /* edx:eax:ecx = a2:a1:a0 */
	movl   -4(%edi),%ebx

	cmpl   %ebx,%edx      /* divise edx:eax par b1  */
	jb     .Lsn_hquo_small_q
	addl   %eax,%edx
	movl   $-1,%eax       /* si débordement, q=base-1 */
	jnc    .Lsn_hquo_all
	movl   %eax,q
	jmp    .Lsn_hquo_qok
	.align 4
.Lsn_hquo_small_q:
	divl   %ebx
.Lsn_hquo_all:
	movl   %eax,q
	movl   %edx,%ebx     /* ebx:ecx = a2:a1:a0 - q*b1:0 */
	mull   -8(%edi)      /* retranche q*b0 */
	subl   %eax,%ecx
	sbbl   %edx,%ebx
	jnb    .Lsn_hquo_qok
	decl   q             /* si <0, diminue q et ajoute b1:b0 */
	addl   -8(%edi),%ecx
	adcl   -4(%edi),%ebx
	jc     .Lsn_hquo_qok
	decl   q             /* toujours <0, rediminue q */
.Lsn_hquo_qok:

	/* a <- a - q*b */
	movl   lb,%ecx
	negl   %ecx
	xorl   %edx,%edx
	.align 4
.Lsn_hquo_sub_qb:
	movl   %edx,%ebx
	movl   (%edi,%ecx,4),%eax
	mull   q
	addl   %ebx,%eax
	adcl   $0,%edx
	subl   %eax,(%esi,%ecx,4)
	adcl   $0,%edx
	incl   %ecx
	jne    .Lsn_hquo_sub_qb
	subl   %edx,(%esi)
	jnb    .Lsn_hquo_next_i

	/* si <0, décrémente q et ajoute b */
	decl   q
	movl   lb,%ecx
	negl   %ecx
	clc
	.align 4
.Lsn_hquo_add_b:
	movl   (%edi,%ecx,4),%eax
	adcl   %eax,(%esi,%ecx,4)
	incl   %ecx
	jne    .Lsn_hquo_add_b
	adcl   $0,(%esi)

	/* range le quotient et passe au chiffre suivant */
.Lsn_hquo_next_i:
	movl   q,%eax
.Lsn_hquo_next_i1:
	movl   loc_c,%ebx
	movl   %eax,(%ebx)
	leal   -4(%ebx),%ebx
	leal   -4(%esi),%esi
	movl   l,%edx
	incl   %edx
	decl   i
	jne    .Lsn_hquo_loop

	/* longueur du reste */
.Lsn_hquo_finish:
	movl   a,%esi
	movl   la,%ecx
.Lsn_hquo_look_a:
	cmpl   $0,-4(%esi,%ecx,4)
	jne    .Lsn_hquo_aok
	loop   .Lsn_hquo_look_a
.Lsn_hquo_anul:
	movl   $0,%ecx
.Lsn_hquo_aok:
	movl   %ecx,%eax
	
EXIT(sn_hquo)
#endif

