diff options
-rw-r--r-- | common/endian.h | 101 |
1 files changed, 53 insertions, 48 deletions
diff --git a/common/endian.h b/common/endian.h index 9a6c0cd42c..9f10b63053 100644 --- a/common/endian.h +++ b/common/endian.h @@ -71,64 +71,36 @@ ((uint16)((((a) >> 8) & 0x00FF) | \ (((a) << 8) & 0xFF00) )) -#ifdef HAVE_INT64 + + /** - * Swap the bytes in a 64 bit word in order to convert LE encoded data to BE + * Swap the bytes in a 16 bit word in order to convert LE encoded data to BE * and vice versa. */ -// machine/compiler-specific variants come first, fallback last +// compilerspecific variants come first, fallback last // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does) -// -// TODO: Fix this #if statement. It isn't changed from 32 bit. Is there a 64 bit swap instruction? #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)) - FORCEINLINE uint32 SWAP_BYTES_32(const uint32 a) { + FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) { if (__builtin_constant_p(a)) { - return SWAP_CONSTANT_32(a); + return SWAP_CONSTANT_16(a); } else { - uint32 result; -# if defined(__psp__) - // use special allegrex instruction - __asm__ ("wsbw %0,%1" : "=r" (result) : "r" (a)); -# else - __asm__ ("wsbh %0,%1\n" - "rotr %0,%0,16" : "=r" (result) : "r" (a)); -# endif + uint16 result; + __asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a)); return result; } } - -// Test for GCC >= 4.3.0 as this version added the bswap builtin -#elif GCC_ATLEAST(4, 3) - - FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { - return __builtin_bswap64(a); - } - -#elif defined(_MSC_VER) - - FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { - return _byteswap_uint64(a); - } - -// generic fallback #else - inline uint64 SWAP_BYTES_64(uint64 a) { - uint32 low = (uint32)a, high = (uint32)(a >> 32); - uint16 lowLow = (uint16)low, lowHigh = (uint16)(low >> 16), - highLow = (uint16)high, highHigh = (uint16)(high >> 16); - - return ((uint64)(((uint32)(uint16)((lowLow >> 8) | (lowLow << 8)) << 16) | - (uint16)((lowHigh >> 8) | (lowHigh << 8))) << 32) | - (((uint32)(uint16)((highLow >> 8) | (highLow << 8)) << 16) | - (uint16)((highHigh >> 8) | (highHigh << 8))); + inline uint16 SWAP_BYTES_16(const uint16 a) { + return (a >> 8) | (a << 8); } #endif -#endif // HAVE_INT64 + + /** * Swap the bytes in a 32 bit word in order to convert LE encoded data to BE * and vice versa. @@ -178,32 +150,65 @@ } #endif +#ifdef HAVE_INT64 /** - * Swap the bytes in a 16 bit word in order to convert LE encoded data to BE + * Swap the bytes in a 64 bit word in order to convert LE encoded data to BE * and vice versa. */ -// compilerspecific variants come first, fallback last +// machine/compiler-specific variants come first, fallback last // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does) +// +// TODO: Fix this #if statement. It isn't changed from 32 bit. Is there a 64 bit swap instruction? #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)) - FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) { + FORCEINLINE uint32 SWAP_BYTES_32(const uint32 a) { if (__builtin_constant_p(a)) { - return SWAP_CONSTANT_16(a); + return SWAP_CONSTANT_32(a); } else { - uint16 result; - __asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a)); + uint32 result; +# if defined(__psp__) + // use special allegrex instruction + __asm__ ("wsbw %0,%1" : "=r" (result) : "r" (a)); +# else + __asm__ ("wsbh %0,%1\n" + "rotr %0,%0,16" : "=r" (result) : "r" (a)); +# endif return result; } } + +// Test for GCC >= 4.3.0 as this version added the bswap builtin +#elif GCC_ATLEAST(4, 3) + + FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { + return __builtin_bswap64(a); + } + +#elif defined(_MSC_VER) + + FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { + return _byteswap_uint64(a); + } + +// generic fallback #else - inline uint16 SWAP_BYTES_16(const uint16 a) { - return (a >> 8) | (a << 8); + inline uint64 SWAP_BYTES_64(uint64 a) { + uint32 low = (uint32)a, high = (uint32)(a >> 32); + uint16 lowLow = (uint16)low, lowHigh = (uint16)(low >> 16), + highLow = (uint16)high, highHigh = (uint16)(high >> 16); + + return ((uint64)(((uint32)(uint16)((lowLow >> 8) | (lowLow << 8)) << 16) | + (uint16)((lowHigh >> 8) | (lowHigh << 8))) << 32) | + (((uint32)(uint16)((highLow >> 8) | (highLow << 8)) << 16) | + (uint16)((highHigh >> 8) | (highHigh << 8))); } #endif +#endif // HAVE_INT64 + /** * A wrapper macro used around four character constants, like 'DATA', to |