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