/*
   fichier def64 : Définit les opérations à utiliser
       pour manipuler des données 64 bits avec GCC 3.x
   créé par Yann GUIDON le 16 mai 2006
   version 23 février : ajout de U64_SHLi/SHRi

   exemple de compilation :
     gcc -Os -W -Wall -momit-leaf-frame-pointer -march=pentium3 nomdufichier.c
*/

#ifndef ___DEF64_H___
#include "machine.h"

#define PTR_CAST (long)

#if defined (__MMX__)
  #define U64_XOR(x,y)   __builtin_ia32_pxor(x,y)
  #define U64_OR(x,y)    __builtin_ia32_por(x,y)
  #define U64_AND(x,y)   __builtin_ia32_pand(x,y)
  #define U64_ANDN(x,y)  __builtin_ia32_pandn(x,y)

/* 3 cas particuliers pour le décalage : */

/* - Si y est un registre MMX : tout baigne */
  #define U64_SHR(x,y)   __builtin_ia32_psrlq(x,y)
  #define U64_SHL(x,y)   __builtin_ia32_psllq(x,y)

/* - Si y est un entier constant : il faut ruser */
  #define U64_SHRi(x,y) ({       \
   unsigned tmp=y;               \
   __builtin_ia32_psrlq(x,tmp); })
  #define U64_SHLi(x,y) ({       \
   unsigned tmp=y;               \
   __builtin_ia32_psllq(x,tmp); })

/* - Si y est un registre normal : la tuile
Comme movd est indisponible
dans les intrinsèques, il faut les définir.
*/

/* /!\ output : x, input : y */
#define U64_MOVD(x,y)           \
   __asm__ __volatile__ ( "\t"  \
     "movd %1, %0\n\t"          \
   : "=X" (x)                   \
   : "r" (y) );

#define U64_SHLr(x, y) ({\
   U64 r;                \
   U64_MOVD(r,y);        \
   U64_SHL(x,r);        })

#define U64_SHRr(x, y) ({\
   U64 r;                \
   U64_MOVD(r,y);        \
   U64_SHR(x,r);        })

#else
  #define U64_XOR(x,y)   (x ^ y)
  #define U64_OR(x,y)    (x | y)
  #define U64_AND(x,y)   (x & y)
  #define U64_ANDN(x,y)  (~x & y)
  #define U64_SHR(x,y)   (x >> y)
  #define U64_SHL(x,y)   (x << y)
  #define U64_SHRi(x,y)  U64_SHR(x,y)
  #define U64_SHLi(x,y)  U64_SHL(x,y)   
  #define U64_SHRr(x,y)  U64_SHR(x,y)
  #define U64_SHLr(x,y)  U64_SHL(x,y)   
#endif

/* adaptation des sens de décalage */

#ifndef WORDS_BIGENDIAN
  #define LOCAL_SHL(x,y)   U64_SHL(x,y)
  #define LOCAL_SHR(x,y)   U64_SHR(x,y)
  #define LOCAL_SHLi(x,y)  U64_SHLi(x,y)
  #define LOCAL_SHRi(x,y)  U64_SHRi(x,y)
  #define LOCAL_SHLr(x,y)  U64_SHLr(x,y)
  #define LOCAL_SHRr(x,y)  U64_SHRr(x,y)
  #define CONVERT_LE64(x)  (x)
#else
  #define LOCAL_SHL(x,y)   U64_SHR(x,y)
  #define LOCAL_SHR(x,y)   U64_SHL(x,y)
  #define LOCAL_SHLi(x,y)  U64_SHRi(x,y)
  #define LOCAL_SHRi(x,y)  U64_SHLi(x,y)
  #define LOCAL_SHLr(x,y)  U64_SHRr(x,y)
  #define LOCAL_SHRr(x,y)  U64_SHLr(x,y)
  #define CONVERT_LE64(x) \
({ /* honteusement pompé du /usr/include/linux/byteorder/swab.h de Faré */ \
  U64 __x = (x); \
  ((U64)( \
    (U64)(((U64)(__x) & (U64)0x00000000000000ffULL) << 56) |   \
    (U64)(((U64)(__x) & (U64)0x000000000000ff00ULL) << 40) |   \
    (U64)(((U64)(__x) & (U64)0x0000000000ff0000ULL) << 24) |   \
    (U64)(((U64)(__x) & (U64)0x00000000ff000000ULL) <<  8) |   \
    (U64)(((U64)(__x) & (U64)0x000000ff00000000ULL) >>  8) |   \
    (U64)(((U64)(__x) & (U64)0x0000ff0000000000ULL) >> 24) |   \
    (U64)(((U64)(__x) & (U64)0x00ff000000000000ULL) >> 40) |   \
    (U64)(((U64)(__x) & (U64)0xff00000000000000ULL) >> 56) )); \
})
#endif

#endif /* ___DEF64_H___ */
