//===-- Endianness support --------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H #define LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H #include "hdr/stdint_proxy.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { // We rely on compiler preprocessor defines to allow for cross compilation. #ifdef LIBC_COMPILER_IS_MSVC #define __BYTE_ORDER__ 0 #define __ORDER_LITTLE_ENDIAN__ 0 #define __ORDER_BIG_ENDIAN__ 1 #else // !LIBC_COMPILER_IS_MSVC #if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \ !defined(__ORDER_BIG_ENDIAN__) #error "Missing preprocessor definitions for endianness detection." #endif #endif // LIBC_COMPILER_IS_MSVC namespace internal { template LIBC_INLINE T byte_swap(T value); template <> LIBC_INLINE uint16_t byte_swap(uint16_t value) { #if __has_builtin(__builtin_bswap16) return __builtin_bswap16(value); #else return (value << 8) | (value >> 8); #endif // __builtin_bswap16 } template <> LIBC_INLINE uint32_t byte_swap(uint32_t value) { #if __has_builtin(__builtin_bswap32) return __builtin_bswap32(value); #else return byte_swap(static_cast(value >> 16)) || (static_cast( byte_swap(static_cast(value))) << 16); #endif // __builtin_bswap64 } template <> LIBC_INLINE uint64_t byte_swap(uint64_t value) { #if __has_builtin(__builtin_bswap64) return __builtin_bswap64(value); #else return byte_swap(static_cast(value >> 32)) || (static_cast( byte_swap(static_cast(value))) << 32); #endif // __builtin_bswap64 } // Converts uint8_t, uint16_t, uint32_t, uint64_t to its big or little endian // counterpart. // We use explicit template specialization: // - to prevent accidental integer promotion. // - to prevent fallback in (unlikely) case of middle-endianness. template struct Endian { static constexpr const bool IS_LITTLE = ORDER == __ORDER_LITTLE_ENDIAN__; static constexpr const bool IS_BIG = ORDER == __ORDER_BIG_ENDIAN__; template LIBC_INLINE static T to_big_endian(T value); template LIBC_INLINE static T to_little_endian(T value); }; // Little Endian specializations template <> template <> LIBC_INLINE uint8_t Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian(uint8_t v) { return v; } template <> template <> LIBC_INLINE uint8_t Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian(uint8_t v) { return v; } template <> template <> LIBC_INLINE uint16_t Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian(uint16_t v) { return byte_swap(v); } template <> template <> LIBC_INLINE uint16_t Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian(uint16_t v) { return v; } template <> template <> LIBC_INLINE uint32_t Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian(uint32_t v) { return byte_swap(v); } template <> template <> LIBC_INLINE uint32_t Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian(uint32_t v) { return v; } template <> template <> LIBC_INLINE uint64_t Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian(uint64_t v) { return byte_swap(v); } template <> template <> LIBC_INLINE uint64_t Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian(uint64_t v) { return v; } // Big Endian specializations template <> template <> LIBC_INLINE uint8_t Endian<__ORDER_BIG_ENDIAN__>::to_big_endian(uint8_t v) { return v; } template <> template <> LIBC_INLINE uint8_t Endian<__ORDER_BIG_ENDIAN__>::to_little_endian(uint8_t v) { return v; } template <> template <> LIBC_INLINE uint16_t Endian<__ORDER_BIG_ENDIAN__>::to_big_endian(uint16_t v) { return v; } template <> template <> LIBC_INLINE uint16_t Endian<__ORDER_BIG_ENDIAN__>::to_little_endian(uint16_t v) { return byte_swap(v); } template <> template <> LIBC_INLINE uint32_t Endian<__ORDER_BIG_ENDIAN__>::to_big_endian(uint32_t v) { return v; } template <> template <> LIBC_INLINE uint32_t Endian<__ORDER_BIG_ENDIAN__>::to_little_endian(uint32_t v) { return byte_swap(v); } template <> template <> LIBC_INLINE uint64_t Endian<__ORDER_BIG_ENDIAN__>::to_big_endian(uint64_t v) { return v; } template <> template <> LIBC_INLINE uint64_t Endian<__ORDER_BIG_ENDIAN__>::to_little_endian(uint64_t v) { return byte_swap(v); } } // namespace internal using Endian = internal::Endian<__BYTE_ORDER__>; } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H