| /* |
| * Copyright (c) 2023, Google and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code 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 General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_UTILITIES_BYTESWAP_HPP |
| #define SHARE_UTILITIES_BYTESWAP_HPP |
| |
| #include "metaprogramming/enableIf.hpp" |
| #include "utilities/globalDefinitions.hpp" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <type_traits> |
| |
| template <typename T, size_t N = sizeof(T)> |
| struct ByteswapImpl; |
| |
| // T byteswap<T>(T) |
| // |
| // Reverses the bytes for the value of the integer type T. Partially compatible with std::byteswap |
| // introduced in C++23. |
| template <typename T, ENABLE_IF(std::is_integral<T>::value)> |
| inline T byteswap(T x) { |
| using U = std::make_unsigned_t<T>; |
| return static_cast<T>(ByteswapImpl<U>{}(static_cast<U>(x))); |
| } |
| |
| // We support 8-bit integer types to be compatible with C++23's std::byteswap. |
| template <typename T> |
| struct ByteswapImpl<T, 1> { |
| inline constexpr T operator()(T x) const { |
| return x; |
| } |
| }; |
| |
| /***************************************************************************** |
| * Fallback |
| *****************************************************************************/ |
| |
| template <typename T, size_t N = sizeof(T)> |
| struct ByteswapFallbackImpl; |
| |
| template <typename T> |
| struct ByteswapFallbackImpl<T, 2> { |
| inline constexpr uint16_t operator()(uint16_t x) const { |
| return (((x & UINT16_C(0x00ff)) << 8) | ((x & UINT16_C(0xff00)) >> 8)); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapFallbackImpl<T, 4> { |
| inline constexpr uint32_t operator()(uint32_t x) const { |
| return (((x & UINT32_C(0x000000ff)) << 24) | ((x & UINT32_C(0x0000ff00)) << 8) | |
| ((x & UINT32_C(0x00ff0000)) >> 8) | ((x & UINT32_C(0xff000000)) >> 24)); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapFallbackImpl<T, 8> { |
| inline constexpr uint64_t operator()(uint64_t x) const { |
| return (((x & UINT64_C(0x00000000000000ff)) << 56) | ((x & UINT64_C(0x000000000000ff00)) << 40) | |
| ((x & UINT64_C(0x0000000000ff0000)) << 24) | ((x & UINT64_C(0x00000000ff000000)) << 8) | |
| ((x & UINT64_C(0x000000ff00000000)) >> 8) | ((x & UINT64_C(0x0000ff0000000000)) >> 24) | |
| ((x & UINT64_C(0x00ff000000000000)) >> 40) | ((x & UINT64_C(0xff00000000000000)) >> 56)); |
| } |
| }; |
| |
| /***************************************************************************** |
| * GCC and compatible (including Clang) |
| *****************************************************************************/ |
| #if defined(TARGET_COMPILER_gcc) || defined(TARGET_COMPILER_xlc) |
| |
| #if defined(__clang__) || defined(ASSERT) |
| |
| // Unlike GCC, Clang is willing to inline the generic implementation of __builtin_bswap when |
| // architecture support is unavailable in -O2. This ensures we avoid the function call to libgcc. |
| // Clang is able to recognize the fallback implementation as byteswapping, but not on every |
| // architecture unlike GCC. This suggests the optimization pass for GCC that recognizes byteswapping |
| // is architecture agnostic, while for Clang it is not. |
| |
| template <typename T> |
| struct ByteswapImpl<T, 2> { |
| inline constexpr uint16_t operator()(uint16_t x) const { |
| return __builtin_bswap16(x); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapImpl<T, 4> { |
| inline constexpr uint32_t operator()(uint32_t x) const { |
| return __builtin_bswap32(x); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapImpl<T, 8> { |
| inline constexpr uint64_t operator()(uint64_t x) const { |
| return __builtin_bswap64(x); |
| } |
| }; |
| |
| #else |
| |
| // We do not use __builtin_bswap and friends for GCC in release builds. Unfortunately on |
| // architectures that do not have a byteswap instruction (i.e. RISC-V), GCC emits a function call to |
| // libgcc regardless of optimization options, even when the generic implementation is, for example, |
| // less than 20 instructions. GCC is however able to recognize the fallback as byteswapping |
| // regardless of architecture and appropriately replaces the code in -O2 with the appropriate |
| // architecture-specific byteswap instruction, if available. If it is not available, GCC emits the |
| // exact same implementation that underpins its __builtin_bswap in libgcc as there is really only |
| // one way to implement it, as we have in fallback. |
| |
| template <typename T, size_t N> |
| struct ByteswapImpl : public ByteswapFallbackImpl<T, N> {}; |
| |
| #endif |
| |
| /***************************************************************************** |
| * Microsoft Visual Studio |
| *****************************************************************************/ |
| #elif defined(TARGET_COMPILER_visCPP) |
| |
| #include <cstdlib> |
| |
| #pragma intrinsic(_byteswap_ushort) |
| #pragma intrinsic(_byteswap_ulong) |
| #pragma intrinsic(_byteswap_uint64) |
| |
| template <typename T> |
| struct ByteswapImpl<T, 2> { |
| inline unsigned short operator()(unsigned short x) const { |
| return _byteswap_ushort(x); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapImpl<T, 4> { |
| inline unsigned long operator()(unsigned long x) const { |
| return _byteswap_ulong(x); |
| } |
| }; |
| |
| template <typename T> |
| struct ByteswapImpl<T, 8> { |
| inline unsigned __int64 operator()(unsigned __int64 x) const { |
| return _byteswap_uint64(x); |
| } |
| }; |
| |
| /***************************************************************************** |
| * Unknown toolchain |
| *****************************************************************************/ |
| #else |
| |
| #error Unknown toolchain. |
| |
| #endif |
| |
| #endif // SHARE_UTILITIES_BYTESWAP_HPP |