/*
   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                    |
   |                                                                        |
   |                                Décalages                               |
   |                                                                        |
   +------------------------------------------------------------------------+ */

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

#include "macros-s.h"

             /* +-------------------------------------+
                |  c <- a >> compte, la >= compte/HW  |
                +-------------------------------------+ */

/* void xn(shr)(naturel a, longueur la, longueur compte, naturel c) */
#ifdef have_sn_shr
ENTER(sn_shr)

        movl   a,%esi
        movl   arg4,%edi           /* c      */
        movl   arg3,%eax           /* compte */
        movl   $32,%ecx
        xorl   %edx,%edx           /* sépare en mots et bits */
        divl   %ecx
        movl   %edx,%ecx
        movl   la,%edx
        leal   (%esi,%edx,4),%esi  /* pointe sur le a fin de a */
        subl   %eax,%edx           /* edx <- longueur restante */
        leal   (%edi,%edx,4),%edi  /* pointe sur la fin de c   */
        negl   %edx
        jecxz  .Lsn_shr_copy

        /* compte non divisible par 32 : recopie en décalant */
        movl   (%esi,%edx,4),%ebx
        jmp    .Lsn_shr_dec_loop1
        .align 4
.Lsn_shr_dec_loop:
        movl   (%esi,%edx,4),%eax
        shrdl  %cl,%eax,%ebx
        movl   %ebx,-4(%edi,%edx,4)
        movl   %eax,%ebx
.Lsn_shr_dec_loop1:
        incl   %edx
        jne    .Lsn_shr_dec_loop
        shrl   %cl,%ebx
        movl   %ebx,-4(%edi) 
        RETURN

        /* compte divisible par 32, recopie la partie haute de a dans c */
        .align 4
.Lsn_shr_copy:
        movl   (%esi,%edx,4),%eax
        movl   %eax,(%edi,%edx,4)
        incl   %edx
        jne    .Lsn_shr_copy

EXIT(sn_shr) 
#endif

                     /* +--------------------+
                        |  c <- a << compte  |
                        +--------------------+ */

/* void xn(shl)(naturel a, longueur la, longueur compte, naturel c) */
#ifdef have_sn_shl
ENTER(sn_shl)

        movl   a,%esi
        movl   arg4,%edi           /* c      */
        movl   arg3,%eax           /* compte */
        movl   $32,%ecx
        xorl   %edx,%edx           /* sépare en mots et bits */
        divl   %ecx
        movl   %edx,%ecx
        movl   la,%edx
        leal   (%edi,%eax,4),%edi
        pushl  %eax
        xorl   %ebx,%ebx
        jecxz  .Lsn_shl_copy

        /* compte non divisible par 32, recopie a dans c en décalant */
        testl  %edx,%edx
        jz     .Lsn_shl_dec_done
        .align 4
.Lsn_shl_dec_loop:
        movl   -4(%esi,%edx,4),%eax
        shldl  %cl,%eax,%ebx
        movl   %ebx,(%edi,%edx,4)
        movl   %eax,%ebx
        decl   %edx
        jne    .Lsn_shl_dec_loop  
        shll   %cl,%ebx
.Lsn_shl_dec_done:       
        movl   %ebx,(%edi)
        jmp    .Lsn_shl_fill_0

        /* compte divisible par 32, recopie a dans la partie haute de c */
.Lsn_shl_copy:
        movl   %ebx,(%edi,%edx,4)
        movl   %edx,%ecx
        jecxz  .Lsn_shl_fill_0
        .align 4
.Lsn_shl_copy_loop:
        movl   -4(%esi,%ecx,4),%eax
        movl   %eax,-4(%edi,%ecx,4)
        loop   .Lsn_shl_copy_loop

        /* complète c par des zéros */
.Lsn_shl_fill_0:
        popl   %ecx
        jecxz  .Lsn_shl_exit
        movl   arg4,%edi
        xorl   %eax,%eax
        .align 4
.Lsn_shl_fill_0_loop:
        movl   %eax,-4(%edi,%ecx,4)
        loop   .Lsn_shl_fill_0_loop

EXIT(sn_shl)
#endif

             /* +------------------------------------+
                |  c <- a << compte ou a >> -compte  |
                +------------------------------------+ */

/* void xz(shift)(entier *a, longueur compte, entier *c) */
#ifdef have_sz_shift
ENTER(sz_shift)

        movl   za,%esi
        movl   zc,%edi
        movl   arg2,%eax
        movl   (%esi),%edx
        andl   $LONG_m,%edx
        leal   4(%esi),%esi
        leal   4(%edi),%edi
        testl  %eax,%eax
        js     .Lsz_shift_right

        /* décalage à gauche */
        pushl  %edi
        pushl  %eax
        pushl  %edx
        pushl  %esi
        movl   $5,%ecx
        shrl   %cl,%eax
        incl   %eax
        addl   %eax,%edx
        movl   %edx,%ebx
        call   sn_shl
        jmp    .Lsz_shift_fixlen

        /* décalage à droite */
.Lsz_shift_right:
        negl   %eax
        pushl  %edi
        pushl  %eax
        pushl  %edx
        pushl  %esi
        movl   $5,%ecx
        shrl   %cl,%eax
        subl   %eax,%edx
        jbe    .Lsz_shift_nul
        movl   %edx,%ebx
        call   sn_shr

        /* corrige la longueur de c */
.Lsz_shift_fixlen:
        testl  $-1,-4(%edi,%ebx,4)
        jnz    .Lsz_shift_cok
        decl   %ebx
        jne    .Lsz_shift_fixlen
.Lsz_shift_nul:
        movl   $0,-4(%edi)
        RETURN

.Lsz_shift_cok:
        testl  $-1,-4(%esi)
        jns    .Lsz_shift_cpos
        orl    $SIGN_m,%ebx
.Lsz_shift_cpos:
        movl   %ebx,-4(%edi)

EXIT(sz_shift)
#endif

