184 lines · c
1//===-- Endianness support --------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H10#define LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H11 12#include "hdr/stdint_proxy.h"13#include "src/__support/common.h"14#include "src/__support/macros/config.h"15 16namespace LIBC_NAMESPACE_DECL {17 18// We rely on compiler preprocessor defines to allow for cross compilation.19#ifdef LIBC_COMPILER_IS_MSVC20#define __BYTE_ORDER__ 021#define __ORDER_LITTLE_ENDIAN__ 022#define __ORDER_BIG_ENDIAN__ 123#else // !LIBC_COMPILER_IS_MSVC24#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \25 !defined(__ORDER_BIG_ENDIAN__)26#error "Missing preprocessor definitions for endianness detection."27#endif28#endif // LIBC_COMPILER_IS_MSVC29 30namespace internal {31 32template <typename T> LIBC_INLINE T byte_swap(T value);33 34template <> LIBC_INLINE uint16_t byte_swap<uint16_t>(uint16_t value) {35#if __has_builtin(__builtin_bswap16)36 return __builtin_bswap16(value);37#else38 return (value << 8) | (value >> 8);39#endif // __builtin_bswap1640}41 42template <> LIBC_INLINE uint32_t byte_swap<uint32_t>(uint32_t value) {43#if __has_builtin(__builtin_bswap32)44 return __builtin_bswap32(value);45#else46 return byte_swap<uint16_t>(static_cast<uint16_t>(value >> 16)) ||47 (static_cast<uint32_t>(48 byte_swap<uint16_t>(static_cast<uint16_t>(value)))49 << 16);50#endif // __builtin_bswap6451}52 53template <> LIBC_INLINE uint64_t byte_swap<uint64_t>(uint64_t value) {54#if __has_builtin(__builtin_bswap64)55 return __builtin_bswap64(value);56#else57 return byte_swap<uint32_t>(static_cast<uint32_t>(value >> 32)) ||58 (static_cast<uint64_t>(59 byte_swap<uint32_t>(static_cast<uint32_t>(value)))60 << 32);61#endif // __builtin_bswap6462}63 64// Converts uint8_t, uint16_t, uint32_t, uint64_t to its big or little endian65// counterpart.66// We use explicit template specialization:67// - to prevent accidental integer promotion.68// - to prevent fallback in (unlikely) case of middle-endianness.69 70template <unsigned ORDER> struct Endian {71 static constexpr const bool IS_LITTLE = ORDER == __ORDER_LITTLE_ENDIAN__;72 static constexpr const bool IS_BIG = ORDER == __ORDER_BIG_ENDIAN__;73 template <typename T> LIBC_INLINE static T to_big_endian(T value);74 template <typename T> LIBC_INLINE static T to_little_endian(T value);75};76 77// Little Endian specializations78template <>79template <>80LIBC_INLINE uint8_t81Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) {82 return v;83}84template <>85template <>86LIBC_INLINE uint8_t87Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) {88 return v;89}90template <>91template <>92LIBC_INLINE uint16_t93Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) {94 return byte_swap<uint16_t>(v);95}96template <>97template <>98LIBC_INLINE uint16_t99Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) {100 return v;101}102template <>103template <>104LIBC_INLINE uint32_t105Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) {106 return byte_swap<uint32_t>(v);107}108template <>109template <>110LIBC_INLINE uint32_t111Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) {112 return v;113}114template <>115template <>116LIBC_INLINE uint64_t117Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) {118 return byte_swap<uint64_t>(v);119}120template <>121template <>122LIBC_INLINE uint64_t123Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) {124 return v;125}126 127// Big Endian specializations128template <>129template <>130LIBC_INLINE uint8_t131Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) {132 return v;133}134template <>135template <>136LIBC_INLINE uint8_t137Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) {138 return v;139}140template <>141template <>142LIBC_INLINE uint16_t143Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) {144 return v;145}146template <>147template <>148LIBC_INLINE uint16_t149Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) {150 return byte_swap<uint16_t>(v);151}152template <>153template <>154LIBC_INLINE uint32_t155Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) {156 return v;157}158template <>159template <>160LIBC_INLINE uint32_t161Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) {162 return byte_swap<uint32_t>(v);163}164template <>165template <>166LIBC_INLINE uint64_t167Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) {168 return v;169}170template <>171template <>172LIBC_INLINE uint64_t173Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) {174 return byte_swap<uint64_t>(v);175}176 177} // namespace internal178 179using Endian = internal::Endian<__BYTE_ORDER__>;180 181} // namespace LIBC_NAMESPACE_DECL182 183#endif // LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H184