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