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 |