/*	Public domain	*/

/*
 * Byte swapping functions
 */

/*
 * Swap 16-bit
 */
#if defined(__GNUC__) && defined(__i386__) && !(__GNUC__ == 2 && __GNUC_MINOR__ == 95)
# ifdef AG_INLINE_HEADER
static __inline__ Uint16
AG_Swap16(Uint16 x)
# else
Uint16
ag_swap16(Uint16 x)
# endif
{
	__asm__("xchgb %b0,%h0" :
	        "=q" (x) :
		"0" (x));
	return (x);
}
#elif (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)
# ifdef AG_INLINE_HEADER
static __inline__ Uint16
AG_Swap16(Uint16 x)
# else
Uint16
ag_swap16(Uint16 x)
# endif
{
	__asm__("xchgb %b0,%h0" :
	        "=Q" (x) :
		"0" (x));
	return (x);
}
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__powerpc__) || defined(__ppc__)) && (!defined(__powerpc64__) && !defined(__ppc64__))
# ifdef AG_INLINE_HEADER
static __inline__ Uint16
AG_Swap16(Uint16 x)
# else
Uint16
ag_swap16(Uint16 x)
# endif
{
	Uint32 rv;
	__asm__("rlwimi %0,%2,8,16,23" :
	        "=&r" (rv) :
		"0" (x >> 8), "r" (x));
	return (Uint16) (rv);
}
#else
# ifdef AG_INLINE_HEADER
static __inline__ Uint16 _Const_Attribute
AG_Swap16(Uint16 x)
# else
Uint16
ag_swap16(Uint16 x)
# endif
{
	return ((x << 8) | (x >> 8));
}
#endif

/*
 * Swap 32-bit
 */
#if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
# ifdef AG_INLINE_HEADER
static __inline__ Uint32
AG_Swap32(Uint32 x)
# else
Uint32
ag_swap32(Uint32 x)
# endif
{
	__asm__("bswap %0" :
	        "=r" (x) :
		"0" (x));
	return (x);
}
#elif (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)
# ifdef AG_INLINE_HEADER
static __inline__ Uint32
AG_Swap32(Uint32 x)
# else
Uint32
ag_swap32(Uint32 x)
# endif
{
	__asm__("bswapl %0" :
	        "=r" (x) :
		"0" (x));
	return (x);
}
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__powerpc__) || defined(__ppc__)) && (!defined(__powerpc64__) && !defined(__ppc64__))
# ifdef AG_INLINE_HEADER
static __inline__ Uint32
AG_Swap32(Uint32 x)
# else
Uint32
ag_swap32(Uint32 x)
# endif
{
	Uint32 rv;
	__asm__("rlwimi %0,%2,24,16,23" :
	        "=&r" (rv) :
		"0" (x>>24), "r" (x));
	__asm__("rlwimi %0,%2,8,8,15" :
	        "=&r" (rv) :
		"0" (rv), "r" (x));
	__asm__("rlwimi %0,%2,24,0,7" :
	        "=&r" (rv) :
		"0" (rv), "r" (x));
	return (rv);
}
#else
# ifdef AG_INLINE_HEADER
static __inline__ Uint32 _Const_Attribute
AG_Swap32(Uint32 x)
# else
Uint32
ag_swap32(Uint32 x)
# endif
{
	return ((x << 24) |
	       ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | 
	        (x >> 24));
}
#endif

/*
 * Swap 64-bit
 */
#ifdef AG_HAVE_64BIT

# if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
# ifdef AG_INLINE_HEADER
static __inline__ Uint64
AG_Swap64(Uint64 x)
# else
Uint64
ag_swap64(Uint64 x)
# endif
{
	union { 
		struct { Uint32 a, b; } s;
		Uint64 u;
	} v;
	v.u = x;
	__asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1" :
	        "=r" (v.s.a), "=r" (v.s.b) :
		"0" (v.s.a), "1" (v.s.b)); 
	return (v.u);
}
# elif (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)
#  ifdef AG_INLINE_HEADER
static __inline__ Uint64
AG_Swap64(Uint64 x)
#  else
Uint64
ag_swap64(Uint64 x)
#  endif
{
	__asm__("bswapq %0" :
	        "=r" (x) :
		"0" (x));
	return (x);
}
# else /* !((__GNUC__ || __clang__) && __x86_64__) */
#  ifdef AG_INLINE_HEADER
static __inline__ Uint64 _Const_Attribute
AG_Swap64(Uint64 x)
#  else
Uint64
ag_swap64(Uint64 x)
#  endif
{
	Uint32 high, low;

	low = (Uint32)(x & 0xFFFFFFFF);
	x >>= 32;
	high = (Uint32)(x & 0xFFFFFFFF);
	x = AG_Swap32(low);
	x <<= 32;
	x |= AG_Swap32(high);
	return (x);
}
# endif /* !((__GNUC__ || __clang__) && __x86_64__) */

#endif /* AG_HAVE_64BIT */
