From 4066443d897cfbaddbe4ae25de92e5850d63e347 Mon Sep 17 00:00:00 2001 From: Beman Date: Thu, 16 May 2013 10:40:18 -0400 Subject: [PATCH] Rework intrinsic.hpp to handle GCC and Clang __builtin_bswap* if available. Add test program. --- include/boost/endian/detail/intrinsic.hpp | 55 ++++++++++++++++------- test/converter_test.cpp | 2 + test/intrinsic_test.cpp | 24 ++++++++++ 3 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 test/intrinsic_test.cpp diff --git a/include/boost/endian/detail/intrinsic.hpp b/include/boost/endian/detail/intrinsic.hpp index a1a83cf..c98aec0 100644 --- a/include/boost/endian/detail/intrinsic.hpp +++ b/include/boost/endian/detail/intrinsic.hpp @@ -1,27 +1,52 @@ -// Copyright (C) 2012 David Stone -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt -// -// See http://www.boost.org/libs/endian/ for documentation. +// endian/detail/intrinsic.hpp -------------------------------------------------------// + +// Copyright (C) 2012 David Stone +// Copyright Beman Dawes 2013 + +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_ENDIAN_INTRINSIC_HPP #define BOOST_ENDIAN_INTRINSIC_HPP -#if ((defined __GNUC__ && !defined(__MINGW32__)) || defined __clang__) - #include - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2 bswap_16 - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4 bswap_32 - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8 bswap_64 +#ifndef __has_builtin // Optional of course + #define __has_builtin(x) 0 // Compatibility with non-clang compilers +#endif + +#if (defined(__clang__) && __has_builtin(__builtin_bswap16)) \ + || (defined(__GNUC__ ) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) +# define BOOST_ENDIAN_INTRINSIC_MSG "__builtin_bswap16, etc." + +// prior to 4.8, gcc did not provide __builtin_bswap16 on some platforms so we emulate it +// see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52624 +# if defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x) __builtin_bswap16(x) +# else +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x) __builtin_bswap32((x) << 16) +# endif + +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x) __builtin_bswap32(x) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x) __builtin_bswap64(x) + +#elif ((defined __GNUC__ && !defined(__MINGW32__)) || defined(__clang__)) +# define BOOST_ENDIAN_INTRINSIC_MSG "__builtin_bswap_16, etc." +# include +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x) bswap_16(x) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x) bswap_32(x) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x) bswap_64(x) #elif defined _MSC_VER // Microsoft documents these as being compatible since Windows 95 and specificly // lists runtime library support since Visual Studio 2003 (aka 7.1). - #include - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2 _byteswap_ushort - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4 _byteswap_ulong - #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8 _byteswap_uint64 +# define BOOST_ENDIAN_INTRINSIC_MSG "_byteswap_ushort, etc." +# include +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x) _byteswap_ushort(x) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x) _byteswap_ulong(x) +# define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x) _byteswap_uint64(x) #else - #define BOOST_ENDIAN_NO_INTRINSICS +# define BOOST_ENDIAN_NO_INTRINSICS +# define BOOST_ENDIAN_INTRINSIC_MSG "no byte swap intrinsics" #endif #endif // BOOST_ENDIAN_INTRINSIC_HPP diff --git a/test/converter_test.cpp b/test/converter_test.cpp index b920e04..76e9bb7 100644 --- a/test/converter_test.cpp +++ b/test/converter_test.cpp @@ -239,6 +239,8 @@ namespace int cpp_main(int, char * []) { + cout << "byte swap intrinsics: " BOOST_ENDIAN_INTRINSIC_MSG << endl; + //std::cerr << std::hex; cout << "int16_t" << endl; diff --git a/test/intrinsic_test.cpp b/test/intrinsic_test.cpp new file mode 100644 index 0000000..90a32fb --- /dev/null +++ b/test/intrinsic_test.cpp @@ -0,0 +1,24 @@ +// Copyright Beman Dawes 2013 + +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include "intrinsic.hpp" +#include +#include +#include + +int main() +{ + std::cout << "BOOST_ENDIAN_INTRINSIC_MSG: " BOOST_ENDIAN_INTRINSIC_MSG << std::endl; + +#ifndef BOOST_ENDIAN_NO_INTRINSICS + uint16_t x2 = 0x1122U; + assert(BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x2) == 0x2211U); + uint32_t x4 = 0x11223344UL; + assert(BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x4) == 0x44332211UL); + uint64_t x8 = 0x1122334455667788U; + assert(BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x8) == 0x8877665544332211ULL); +#endif + return 0; +}