• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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