/*                                              -*- mode:C++; fill-column:100 -*-
  SFBMath.h - Misc bit twiddling and mathy routines, just in case
  Copyright (C) 2009 The Regents of the University of New Mexico.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
*/

#ifndef SFBMATH_H
#define SFBMATH_H

#include "SFBTypes.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef HOST_MODE

/**
 * The straight-C recursive 'SIMD-Within-A-Register' (SWAR) leading zero count algorithm, e.g. from http://aggregate.org/MAGIC.
 */
#define COUNT_LEADING_ZEROS(u32InputVal, u32OutputCount)              \
 do {                                                                 \
  (u32InputVal) |= (u32InputVal)>>1;                                  \
  (u32InputVal) |= (u32InputVal)>>2;                                  \
  (u32InputVal) |= (u32InputVal)>>2;                                  \
  (u32InputVal) |= (u32InputVal)>>4;                                  \
  (u32InputVal) |= (u32InputVal)>>8;                                  \
  (u32InputVal) |= (u32InputVal)>>16;                                 \
  (u32OutputCount) = 32-countOnes(u32InputVal);                       \
 } while (0)

#else

/**
 * An ARM assembly implementation of leading zero count (since the ARM7TDMI architecture lacks the
 * CLZ instruction), e.g., from http://www.sciencezero.org/index.php?title=ARM:_Count_leading_zeros
 */
#define COUNT_LEADING_ZEROS(u32InputVal, u32OutputCount)              \
 /* 16 cycle leading zero count algorithm */                          \
  __asm__ __volatile__ ("movs	%[count],%[val],lsr #16\n\t"          \
                        "mov	%[count],#0\n\t"                      \
                        "addeq	%[count],%[count],#16\n\t"            \
                        "moveqs	%[val],%[val],lsl #16\n\t"            \
                        "addeq	%[count],%[count],#1\n\t"             \
                        "tst	%[val],#0xff000000\n\t"               \
                        "addeq	%[count],%[count],#8\n\t"             \
                        "moveq	%[val],%[val],lsl #8\n\t"             \
                        "tst	%[val],#0xf0000000\n\t"               \
                        "addeq	%[count],%[count],#4\n\t"             \
                        "moveq	%[val],%[val],lsl #4\n\t"             \
                        "tst	%[val],#0xc0000000\n\t"               \
                        "addeq	%[count],%[count],#2\n\t"             \
                        "moveq	%[val],%[val],lsl #2\n\t"             \
                        "tst	%[val],#0x80000000\n\t"               \
                        "addeq	%[count],%[count],#1"                 \
                        : [count] "=r" (u32OutputCount),              \
                          [val] "+r" (u32InputVal)                    \
                        : )
#endif

extern int countLeadingZeros(u32 x) ;

extern int countOnes(u32 x) ;

extern int countTrailingZeros(int x) ;

#ifdef __cplusplus
}
#endif


#endif /* SFBMATH_H */

