/*
 *  first0.h
 *
 *  Define the macro LOOKUP_FIRSTBLANK, which returns the location of
 *  the first zero bit in a given (32 bit) unsigned int.
 *  
 *
 *  Created by Michael Feiri on Wed Jan 16 2002.
 *  Copyright (c) 2001 Michael Feiri. All rights reserved.
 *
 */

#if defined(__PPC__) || defined(__ppc__) || defined(ASM_PPC) || defined (__POWERPC__)/* CouNT Leading Zeros Word */
  #if defined(__GNUC__)
    static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int i)
    { i = ~i; __asm__ ("cntlzw %0,%0" : "=r" (i) : "0" (i)); return ++i; }
  #elif (__MWERKS__) || (__MRC__)
    #define LOOKUP_FIRSTBLANK(x) (__cntlzw(~((unsigned int)(x)))+1)
  #else
    #error "Please check this (define OGR_TEST_FIRSTBLANK to test)"
  #endif
#elif defined(ASM_ALPHA) && defined(__GNUC__)
  #error "Please check this (define OGR_TEST_FIRSTBLANK to test)"
  static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int i)
  { i = ~i; __asm__ ("cntlzw %0,%0" : "=r"(i) : "0" (i)); return i+1; }
#elif defined(ASM_X86) && defined(__GNUC__) || \
      defined(__386__) && defined(__WATCOMC__) || \
      defined(__INTEL__) && defined(__MWERKS__) || \
      defined(__ICC)
  /* If we were to cover the whole range of 0x00000000 ... 0xffffffff
     we would need ...
     static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int input)
     {
        register unsigned int result;
        __asm__("notl %1\n\t"     \
                "movl $33,%0\n\t" \
                "bsrl %1,%1\n\t"  \
                "jz   0f\n\t"     \
                "subl %1,%0\n\t"  \
                "decl %0\n\t"     \
                "0:"              \
                :"=r"(result), "=r"(input) : "1"(input) : "cc" );
        return result;
     }
     but since the function is only executed for (comp0 < 0xfffffffe),
     we can optimize it to...
  */
  #if defined(__GNUC__)
    static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int input)
    {
       register unsigned int result;
       __asm__("notl %1\n\t"     \
               "movl $32,%0\n\t" \
               "bsrl %1,%1\n\t"  \
               "subl %1,%0\n\t"  \
               :"=r"(result), "=r"(input) : "1"(input) : "cc" );
       return result;
    }
  #elif defined(__WATCOMC__)
    int LOOKUP_FIRSTBLANK(unsigned int);
    #pragma aux LOOKUP_FIRSTBLANK =  \
                      "not  eax"     \
                      "mov  edx,20h" \
                      "bsr  eax,eax" \
                      "sub  edx,eax" \
            value [edx] parm [eax] modify exact [eax edx] nomemory;
  #else /* if defined(__ICC) */
    static inline int LOOKUP_FIRSTBLANK(register unsigned int i)
    {
      _asm mov eax,i
      _asm not eax
      _asm mov edx,20h
      _asm bsr eax,eax
      _asm sub edx,eax
      _asm mov i,edx
      return i;
    }
  #endif
#elif defined(ASM_68K) && defined(__GNUC__) /* Bit field find first one set (020+) */
  static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int i)
  { i = ~i; __asm__ ("bfffo %0,0,0,%0" : "=d" (i) : "0" (i)); return ++i; }
#else
  
  static const char ogr_first_blank_8bit[256] = {
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 9
  };
  #if defined(ASM_ARM) && defined(__GNUC__)
    static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int input)
    {
      register int temp, result;
      __asm__ ("mov     %0,#0\n\t"             \
               "cmp     %1,#0xffff0000\n\t"    \
               "movcs   %1,%1,lsl#16\n\t"      \
               "addcs   %0,%0,#16\n\t"         \
               "cmp     %1,#0xff000000\n\t"    \
               "movcs   %1,%1,lsl#8\n\t"       \
               "ldrb    %1,[%3,%1,lsr#24]\n\t" \
               "addcs   %0,%0,#8\n\t"          \
               "add     %0,%0,%1"              \
               :"=r" (result), "=r" (temp) : "1" (input), "r" ((unsigned int)ogr_first_blank_8bit));
      return result;
    }
  #elif defined(ASM_68K) && defined(__GNUC__)
    static __inline__ int LOOKUP_FIRSTBLANK(register unsigned int input)
    {
      register int result;
      __asm__ ("   cmp.l   #0xffff0000,%1\n"
               "   bcs.b   0f\n"
               "   moveq   #16,%0\n"
               "   bra.b   1f\n"
               "0: swap    %1\n"
               "   moveq   #0,%0\n"
               "1: cmp.w   #0xff00,%1\n"
               "   bcs.b   2f\n"
               "   lsl.w   #8,%1\n"
               "   addq    #8,%0\n"
               "2: lsr.w   #8,%1\n"
               "   add.b   0(%3,%1.w),%0"
               :"=d" (result), "=d" (input) : "1" (input), "a" (ogr_first_blank_8bit));
      return result;
    }
  #else /* C code, no asm */
  static __inline int LOOKUP_FIRSTBLANK(register unsigned int input)
  {
    register int result = 0;
    if (input >= 0xffff0000) {
      input <<= 16;
      result += 16;
    }
    if (input >= 0xff000000) {
      input <<= 8;
      result += 8;
    }
    result += ogr_first_blank_8bit[input>>24];
    return result;
  }
  #endif
#endif
