1 //===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file declares generic functions to read and write endian specific data.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_SUPPORT_ENDIAN_H
14 #define LLVM_SUPPORT_ENDIAN_H
16 #include "llvm/Support/AlignOf.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/Host.h"
19 #include "llvm/Support/SwapByteOrder.h"
24 #include <type_traits>
29 enum endianness
{big
, little
, native
};
31 // These are named values for common alignments.
32 enum {aligned
= 0, unaligned
= 1};
36 /// ::value is either alignment, or alignof(T) if alignment is 0.
37 template<class T
, int alignment
>
38 struct PickAlignment
{
39 enum { value
= alignment
== 0 ? alignof(T
) : alignment
};
42 } // end namespace detail
46 constexpr endianness
system_endianness() {
47 return sys::IsBigEndianHost
? big
: little
;
50 template <typename value_type
>
51 inline value_type
byte_swap(value_type value
, endianness endian
) {
52 if ((endian
!= native
) && (endian
!= system_endianness()))
53 sys::swapByteOrder(value
);
57 /// Swap the bytes of value to match the given endianness.
58 template<typename value_type
, endianness endian
>
59 inline value_type
byte_swap(value_type value
) {
60 return byte_swap(value
, endian
);
63 /// Read a value of a particular endianness from memory.
64 template <typename value_type
, std::size_t alignment
>
65 inline value_type
read(const void *memory
, endianness endian
) {
70 memory
, (detail::PickAlignment
<value_type
, alignment
>::value
)),
72 return byte_swap
<value_type
>(ret
, endian
);
75 template<typename value_type
,
77 std::size_t alignment
>
78 inline value_type
read(const void *memory
) {
79 return read
<value_type
, alignment
>(memory
, endian
);
82 /// Read a value of a particular endianness from a buffer, and increment the
83 /// buffer past that value.
84 template <typename value_type
, std::size_t alignment
, typename CharT
>
85 inline value_type
readNext(const CharT
*&memory
, endianness endian
) {
86 value_type ret
= read
<value_type
, alignment
>(memory
, endian
);
87 memory
+= sizeof(value_type
);
91 template<typename value_type
, endianness endian
, std::size_t alignment
,
93 inline value_type
readNext(const CharT
*&memory
) {
94 return readNext
<value_type
, alignment
, CharT
>(memory
, endian
);
97 /// Write a value to memory with a particular endianness.
98 template <typename value_type
, std::size_t alignment
>
99 inline void write(void *memory
, value_type value
, endianness endian
) {
100 value
= byte_swap
<value_type
>(value
, endian
);
101 memcpy(LLVM_ASSUME_ALIGNED(
102 memory
, (detail::PickAlignment
<value_type
, alignment
>::value
)),
103 &value
, sizeof(value_type
));
106 template<typename value_type
,
108 std::size_t alignment
>
109 inline void write(void *memory
, value_type value
) {
110 write
<value_type
, alignment
>(memory
, value
, endian
);
113 template <typename value_type
>
114 using make_unsigned_t
= typename
std::make_unsigned
<value_type
>::type
;
116 /// Read a value of a particular endianness from memory, for a location
117 /// that starts at the given bit offset within the first byte.
118 template <typename value_type
, endianness endian
, std::size_t alignment
>
119 inline value_type
readAtBitAlignment(const void *memory
, uint64_t startBit
) {
120 assert(startBit
< 8);
122 return read
<value_type
, endian
, alignment
>(memory
);
124 // Read two values and compose the result from them.
128 memory
, (detail::PickAlignment
<value_type
, alignment
>::value
)),
129 sizeof(value_type
) * 2);
130 val
[0] = byte_swap
<value_type
, endian
>(val
[0]);
131 val
[1] = byte_swap
<value_type
, endian
>(val
[1]);
133 // Shift bits from the lower value into place.
134 make_unsigned_t
<value_type
> lowerVal
= val
[0] >> startBit
;
135 // Mask off upper bits after right shift in case of signed type.
136 make_unsigned_t
<value_type
> numBitsFirstVal
=
137 (sizeof(value_type
) * 8) - startBit
;
138 lowerVal
&= ((make_unsigned_t
<value_type
>)1 << numBitsFirstVal
) - 1;
140 // Get the bits from the upper value.
141 make_unsigned_t
<value_type
> upperVal
=
142 val
[1] & (((make_unsigned_t
<value_type
>)1 << startBit
) - 1);
143 // Shift them in to place.
144 upperVal
<<= numBitsFirstVal
;
146 return lowerVal
| upperVal
;
150 /// Write a value to memory with a particular endianness, for a location
151 /// that starts at the given bit offset within the first byte.
152 template <typename value_type
, endianness endian
, std::size_t alignment
>
153 inline void writeAtBitAlignment(void *memory
, value_type value
,
155 assert(startBit
< 8);
157 write
<value_type
, endian
, alignment
>(memory
, value
);
159 // Read two values and shift the result into them.
163 memory
, (detail::PickAlignment
<value_type
, alignment
>::value
)),
164 sizeof(value_type
) * 2);
165 val
[0] = byte_swap
<value_type
, endian
>(val
[0]);
166 val
[1] = byte_swap
<value_type
, endian
>(val
[1]);
168 // Mask off any existing bits in the upper part of the lower value that
169 // we want to replace.
170 val
[0] &= ((make_unsigned_t
<value_type
>)1 << startBit
) - 1;
171 make_unsigned_t
<value_type
> numBitsFirstVal
=
172 (sizeof(value_type
) * 8) - startBit
;
173 make_unsigned_t
<value_type
> lowerVal
= value
;
175 // Mask off the upper bits in the new value that are not going to go into
176 // the lower value. This avoids a left shift of a negative value, which
177 // is undefined behavior.
178 lowerVal
&= (((make_unsigned_t
<value_type
>)1 << numBitsFirstVal
) - 1);
179 // Now shift the new bits into place
180 lowerVal
<<= startBit
;
184 // Mask off any existing bits in the lower part of the upper value that
185 // we want to replace.
186 val
[1] &= ~(((make_unsigned_t
<value_type
>)1 << startBit
) - 1);
187 // Next shift the bits that go into the upper value into position.
188 make_unsigned_t
<value_type
> upperVal
= value
>> numBitsFirstVal
;
189 // Mask off upper bits after right shift in case of signed type.
190 upperVal
&= ((make_unsigned_t
<value_type
>)1 << startBit
) - 1;
193 // Finally, rewrite values.
194 val
[0] = byte_swap
<value_type
, endian
>(val
[0]);
195 val
[1] = byte_swap
<value_type
, endian
>(val
[1]);
196 memcpy(LLVM_ASSUME_ALIGNED(
197 memory
, (detail::PickAlignment
<value_type
, alignment
>::value
)),
198 &val
[0], sizeof(value_type
) * 2);
202 } // end namespace endian
206 template<typename value_type
,
208 std::size_t alignment
>
209 struct packed_endian_specific_integral
{
210 packed_endian_specific_integral() = default;
212 explicit packed_endian_specific_integral(value_type val
) { *this = val
; }
214 operator value_type() const {
215 return endian::read
<value_type
, endian
, alignment
>(
216 (const void*)Value
.buffer
);
219 void operator=(value_type newValue
) {
220 endian::write
<value_type
, endian
, alignment
>(
221 (void*)Value
.buffer
, newValue
);
224 packed_endian_specific_integral
&operator+=(value_type newValue
) {
225 *this = *this + newValue
;
229 packed_endian_specific_integral
&operator-=(value_type newValue
) {
230 *this = *this - newValue
;
234 packed_endian_specific_integral
&operator|=(value_type newValue
) {
235 *this = *this | newValue
;
239 packed_endian_specific_integral
&operator&=(value_type newValue
) {
240 *this = *this & newValue
;
245 AlignedCharArray
<PickAlignment
<value_type
, alignment
>::value
,
246 sizeof(value_type
)> Value
;
250 explicit ref(void *Ptr
) : Ptr(Ptr
) {}
252 operator value_type() const {
253 return endian::read
<value_type
, endian
, alignment
>(Ptr
);
256 void operator=(value_type NewValue
) {
257 endian::write
<value_type
, endian
, alignment
>(Ptr
, NewValue
);
265 } // end namespace detail
268 detail::packed_endian_specific_integral
<uint16_t, little
, unaligned
>;
270 detail::packed_endian_specific_integral
<uint32_t, little
, unaligned
>;
272 detail::packed_endian_specific_integral
<uint64_t, little
, unaligned
>;
275 detail::packed_endian_specific_integral
<int16_t, little
, unaligned
>;
277 detail::packed_endian_specific_integral
<int32_t, little
, unaligned
>;
279 detail::packed_endian_specific_integral
<int64_t, little
, unaligned
>;
281 using aligned_ulittle16_t
=
282 detail::packed_endian_specific_integral
<uint16_t, little
, aligned
>;
283 using aligned_ulittle32_t
=
284 detail::packed_endian_specific_integral
<uint32_t, little
, aligned
>;
285 using aligned_ulittle64_t
=
286 detail::packed_endian_specific_integral
<uint64_t, little
, aligned
>;
288 using aligned_little16_t
=
289 detail::packed_endian_specific_integral
<int16_t, little
, aligned
>;
290 using aligned_little32_t
=
291 detail::packed_endian_specific_integral
<int32_t, little
, aligned
>;
292 using aligned_little64_t
=
293 detail::packed_endian_specific_integral
<int64_t, little
, aligned
>;
296 detail::packed_endian_specific_integral
<uint16_t, big
, unaligned
>;
298 detail::packed_endian_specific_integral
<uint32_t, big
, unaligned
>;
300 detail::packed_endian_specific_integral
<uint64_t, big
, unaligned
>;
303 detail::packed_endian_specific_integral
<int16_t, big
, unaligned
>;
305 detail::packed_endian_specific_integral
<int32_t, big
, unaligned
>;
307 detail::packed_endian_specific_integral
<int64_t, big
, unaligned
>;
309 using aligned_ubig16_t
=
310 detail::packed_endian_specific_integral
<uint16_t, big
, aligned
>;
311 using aligned_ubig32_t
=
312 detail::packed_endian_specific_integral
<uint32_t, big
, aligned
>;
313 using aligned_ubig64_t
=
314 detail::packed_endian_specific_integral
<uint64_t, big
, aligned
>;
316 using aligned_big16_t
=
317 detail::packed_endian_specific_integral
<int16_t, big
, aligned
>;
318 using aligned_big32_t
=
319 detail::packed_endian_specific_integral
<int32_t, big
, aligned
>;
320 using aligned_big64_t
=
321 detail::packed_endian_specific_integral
<int64_t, big
, aligned
>;
323 using unaligned_uint16_t
=
324 detail::packed_endian_specific_integral
<uint16_t, native
, unaligned
>;
325 using unaligned_uint32_t
=
326 detail::packed_endian_specific_integral
<uint32_t, native
, unaligned
>;
327 using unaligned_uint64_t
=
328 detail::packed_endian_specific_integral
<uint64_t, native
, unaligned
>;
330 using unaligned_int16_t
=
331 detail::packed_endian_specific_integral
<int16_t, native
, unaligned
>;
332 using unaligned_int32_t
=
333 detail::packed_endian_specific_integral
<int32_t, native
, unaligned
>;
334 using unaligned_int64_t
=
335 detail::packed_endian_specific_integral
<int64_t, native
, unaligned
>;
339 template <typename T
> inline T
read(const void *P
, endianness E
) {
340 return read
<T
, unaligned
>(P
, E
);
343 template <typename T
, endianness E
> inline T
read(const void *P
) {
344 return *(const detail::packed_endian_specific_integral
<T
, E
, unaligned
> *)P
;
347 inline uint16_t read16(const void *P
, endianness E
) {
348 return read
<uint16_t>(P
, E
);
350 inline uint32_t read32(const void *P
, endianness E
) {
351 return read
<uint32_t>(P
, E
);
353 inline uint64_t read64(const void *P
, endianness E
) {
354 return read
<uint64_t>(P
, E
);
357 template <endianness E
> inline uint16_t read16(const void *P
) {
358 return read
<uint16_t, E
>(P
);
360 template <endianness E
> inline uint32_t read32(const void *P
) {
361 return read
<uint32_t, E
>(P
);
363 template <endianness E
> inline uint64_t read64(const void *P
) {
364 return read
<uint64_t, E
>(P
);
367 inline uint16_t read16le(const void *P
) { return read16
<little
>(P
); }
368 inline uint32_t read32le(const void *P
) { return read32
<little
>(P
); }
369 inline uint64_t read64le(const void *P
) { return read64
<little
>(P
); }
370 inline uint16_t read16be(const void *P
) { return read16
<big
>(P
); }
371 inline uint32_t read32be(const void *P
) { return read32
<big
>(P
); }
372 inline uint64_t read64be(const void *P
) { return read64
<big
>(P
); }
374 template <typename T
> inline void write(void *P
, T V
, endianness E
) {
375 write
<T
, unaligned
>(P
, V
, E
);
378 template <typename T
, endianness E
> inline void write(void *P
, T V
) {
379 *(detail::packed_endian_specific_integral
<T
, E
, unaligned
> *)P
= V
;
382 inline void write16(void *P
, uint16_t V
, endianness E
) {
383 write
<uint16_t>(P
, V
, E
);
385 inline void write32(void *P
, uint32_t V
, endianness E
) {
386 write
<uint32_t>(P
, V
, E
);
388 inline void write64(void *P
, uint64_t V
, endianness E
) {
389 write
<uint64_t>(P
, V
, E
);
392 template <endianness E
> inline void write16(void *P
, uint16_t V
) {
393 write
<uint16_t, E
>(P
, V
);
395 template <endianness E
> inline void write32(void *P
, uint32_t V
) {
396 write
<uint32_t, E
>(P
, V
);
398 template <endianness E
> inline void write64(void *P
, uint64_t V
) {
399 write
<uint64_t, E
>(P
, V
);
402 inline void write16le(void *P
, uint16_t V
) { write16
<little
>(P
, V
); }
403 inline void write32le(void *P
, uint32_t V
) { write32
<little
>(P
, V
); }
404 inline void write64le(void *P
, uint64_t V
) { write64
<little
>(P
, V
); }
405 inline void write16be(void *P
, uint16_t V
) { write16
<big
>(P
, V
); }
406 inline void write32be(void *P
, uint32_t V
) { write32
<big
>(P
, V
); }
407 inline void write64be(void *P
, uint64_t V
) { write64
<big
>(P
, V
); }
409 } // end namespace endian
411 } // end namespace support
412 } // end namespace llvm
414 #endif // LLVM_SUPPORT_ENDIAN_H