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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H 10 #define LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H 11 12 #include "common.h" 13 #include "src/__support/macros/config.h" 14 15 #include <stdint.h> 16 17 namespace LIBC_NAMESPACE_DECL { 18 19 // We rely on compiler preprocessor defines to allow for cross compilation. 20 #if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \ 21 !defined(__ORDER_BIG_ENDIAN__) 22 #error "Missing preprocessor definitions for endianness detection." 23 #endif 24 25 namespace internal { 26 27 // Converts uint8_t, uint16_t, uint32_t, uint64_t to its big or little endian 28 // counterpart. 29 // We use explicit template specialization: 30 // - to prevent accidental integer promotion. 31 // - to prevent fallback in (unlikely) case of middle-endianness. 32 33 template <unsigned ORDER> struct Endian { 34 static constexpr const bool IS_LITTLE = ORDER == __ORDER_LITTLE_ENDIAN__; 35 static constexpr const bool IS_BIG = ORDER == __ORDER_BIG_ENDIAN__; 36 template <typename T> LIBC_INLINE static T to_big_endian(T value); 37 template <typename T> LIBC_INLINE static T to_little_endian(T value); 38 }; 39 40 // Little Endian specializations 41 template <> 42 template <> 43 LIBC_INLINE uint8_t 44 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) { 45 return v; 46 } 47 template <> 48 template <> 49 LIBC_INLINE uint8_t 50 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) { 51 return v; 52 } 53 template <> 54 template <> 55 LIBC_INLINE uint16_t 56 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) { 57 return __builtin_bswap16(v); 58 } 59 template <> 60 template <> 61 LIBC_INLINE uint16_t 62 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) { 63 return v; 64 } 65 template <> 66 template <> 67 LIBC_INLINE uint32_t 68 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) { 69 return __builtin_bswap32(v); 70 } 71 template <> 72 template <> 73 LIBC_INLINE uint32_t 74 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) { 75 return v; 76 } 77 template <> 78 template <> 79 LIBC_INLINE uint64_t 80 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) { 81 return __builtin_bswap64(v); 82 } 83 template <> 84 template <> 85 LIBC_INLINE uint64_t 86 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) { 87 return v; 88 } 89 90 // Big Endian specializations 91 template <> 92 template <> 93 LIBC_INLINE uint8_t 94 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) { 95 return v; 96 } 97 template <> 98 template <> 99 LIBC_INLINE uint8_t 100 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) { 101 return v; 102 } 103 template <> 104 template <> 105 LIBC_INLINE uint16_t 106 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) { 107 return v; 108 } 109 template <> 110 template <> 111 LIBC_INLINE uint16_t 112 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) { 113 return __builtin_bswap16(v); 114 } 115 template <> 116 template <> 117 LIBC_INLINE uint32_t 118 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) { 119 return v; 120 } 121 template <> 122 template <> 123 LIBC_INLINE uint32_t 124 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) { 125 return __builtin_bswap32(v); 126 } 127 template <> 128 template <> 129 LIBC_INLINE uint64_t 130 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) { 131 return v; 132 } 133 template <> 134 template <> 135 LIBC_INLINE uint64_t 136 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) { 137 return __builtin_bswap64(v); 138 } 139 140 } // namespace internal 141 142 using Endian = internal::Endian<__BYTE_ORDER__>; 143 144 } // namespace LIBC_NAMESPACE_DECL 145 146 #endif // LLVM_LIBC_SRC___SUPPORT_ENDIAN_INTERNAL_H 147