Endian.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file declares generic functions to read and write endian specific data.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_SUPPORT_ENDIAN_H
  18. #define LLVM_SUPPORT_ENDIAN_H
  19. #include "llvm/Support/Compiler.h"
  20. #include "llvm/Support/SwapByteOrder.h"
  21. #include <cassert>
  22. #include <cstddef>
  23. #include <cstdint>
  24. #include <cstring>
  25. #include <type_traits>
  26. namespace llvm {
  27. namespace support {
  28. enum endianness {big, little, native};
  29. // These are named values for common alignments.
  30. enum {aligned = 0, unaligned = 1};
  31. namespace detail {
  32. /// ::value is either alignment, or alignof(T) if alignment is 0.
  33. template<class T, int alignment>
  34. struct PickAlignment {
  35. enum { value = alignment == 0 ? alignof(T) : alignment };
  36. };
  37. } // end namespace detail
  38. namespace endian {
  39. constexpr endianness system_endianness() {
  40. return sys::IsBigEndianHost ? big : little;
  41. }
  42. template <typename value_type>
  43. inline value_type byte_swap(value_type value, endianness endian) {
  44. if ((endian != native) && (endian != system_endianness()))
  45. sys::swapByteOrder(value);
  46. return value;
  47. }
  48. /// Swap the bytes of value to match the given endianness.
  49. template<typename value_type, endianness endian>
  50. inline value_type byte_swap(value_type value) {
  51. return byte_swap(value, endian);
  52. }
  53. /// Read a value of a particular endianness from memory.
  54. template <typename value_type, std::size_t alignment>
  55. inline value_type read(const void *memory, endianness endian) {
  56. value_type ret;
  57. memcpy(&ret,
  58. LLVM_ASSUME_ALIGNED(
  59. memory, (detail::PickAlignment<value_type, alignment>::value)),
  60. sizeof(value_type));
  61. return byte_swap<value_type>(ret, endian);
  62. }
  63. template<typename value_type,
  64. endianness endian,
  65. std::size_t alignment>
  66. inline value_type read(const void *memory) {
  67. return read<value_type, alignment>(memory, endian);
  68. }
  69. /// Read a value of a particular endianness from a buffer, and increment the
  70. /// buffer past that value.
  71. template <typename value_type, std::size_t alignment, typename CharT>
  72. inline value_type readNext(const CharT *&memory, endianness endian) {
  73. value_type ret = read<value_type, alignment>(memory, endian);
  74. memory += sizeof(value_type);
  75. return ret;
  76. }
  77. template<typename value_type, endianness endian, std::size_t alignment,
  78. typename CharT>
  79. inline value_type readNext(const CharT *&memory) {
  80. return readNext<value_type, alignment, CharT>(memory, endian);
  81. }
  82. /// Write a value to memory with a particular endianness.
  83. template <typename value_type, std::size_t alignment>
  84. inline void write(void *memory, value_type value, endianness endian) {
  85. value = byte_swap<value_type>(value, endian);
  86. memcpy(LLVM_ASSUME_ALIGNED(
  87. memory, (detail::PickAlignment<value_type, alignment>::value)),
  88. &value, sizeof(value_type));
  89. }
  90. template<typename value_type,
  91. endianness endian,
  92. std::size_t alignment>
  93. inline void write(void *memory, value_type value) {
  94. write<value_type, alignment>(memory, value, endian);
  95. }
  96. template <typename value_type>
  97. using make_unsigned_t = std::make_unsigned_t<value_type>;
  98. /// Read a value of a particular endianness from memory, for a location
  99. /// that starts at the given bit offset within the first byte.
  100. template <typename value_type, endianness endian, std::size_t alignment>
  101. inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
  102. assert(startBit < 8);
  103. if (startBit == 0)
  104. return read<value_type, endian, alignment>(memory);
  105. else {
  106. // Read two values and compose the result from them.
  107. value_type val[2];
  108. memcpy(&val[0],
  109. LLVM_ASSUME_ALIGNED(
  110. memory, (detail::PickAlignment<value_type, alignment>::value)),
  111. sizeof(value_type) * 2);
  112. val[0] = byte_swap<value_type, endian>(val[0]);
  113. val[1] = byte_swap<value_type, endian>(val[1]);
  114. // Shift bits from the lower value into place.
  115. make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
  116. // Mask off upper bits after right shift in case of signed type.
  117. make_unsigned_t<value_type> numBitsFirstVal =
  118. (sizeof(value_type) * 8) - startBit;
  119. lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
  120. // Get the bits from the upper value.
  121. make_unsigned_t<value_type> upperVal =
  122. val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
  123. // Shift them in to place.
  124. upperVal <<= numBitsFirstVal;
  125. return lowerVal | upperVal;
  126. }
  127. }
  128. /// Write a value to memory with a particular endianness, for a location
  129. /// that starts at the given bit offset within the first byte.
  130. template <typename value_type, endianness endian, std::size_t alignment>
  131. inline void writeAtBitAlignment(void *memory, value_type value,
  132. uint64_t startBit) {
  133. assert(startBit < 8);
  134. if (startBit == 0)
  135. write<value_type, endian, alignment>(memory, value);
  136. else {
  137. // Read two values and shift the result into them.
  138. value_type val[2];
  139. memcpy(&val[0],
  140. LLVM_ASSUME_ALIGNED(
  141. memory, (detail::PickAlignment<value_type, alignment>::value)),
  142. sizeof(value_type) * 2);
  143. val[0] = byte_swap<value_type, endian>(val[0]);
  144. val[1] = byte_swap<value_type, endian>(val[1]);
  145. // Mask off any existing bits in the upper part of the lower value that
  146. // we want to replace.
  147. val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
  148. make_unsigned_t<value_type> numBitsFirstVal =
  149. (sizeof(value_type) * 8) - startBit;
  150. make_unsigned_t<value_type> lowerVal = value;
  151. if (startBit > 0) {
  152. // Mask off the upper bits in the new value that are not going to go into
  153. // the lower value. This avoids a left shift of a negative value, which
  154. // is undefined behavior.
  155. lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
  156. // Now shift the new bits into place
  157. lowerVal <<= startBit;
  158. }
  159. val[0] |= lowerVal;
  160. // Mask off any existing bits in the lower part of the upper value that
  161. // we want to replace.
  162. val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
  163. // Next shift the bits that go into the upper value into position.
  164. make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
  165. // Mask off upper bits after right shift in case of signed type.
  166. upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
  167. val[1] |= upperVal;
  168. // Finally, rewrite values.
  169. val[0] = byte_swap<value_type, endian>(val[0]);
  170. val[1] = byte_swap<value_type, endian>(val[1]);
  171. memcpy(LLVM_ASSUME_ALIGNED(
  172. memory, (detail::PickAlignment<value_type, alignment>::value)),
  173. &val[0], sizeof(value_type) * 2);
  174. }
  175. }
  176. } // end namespace endian
  177. namespace detail {
  178. template <typename ValueType, endianness Endian, std::size_t Alignment,
  179. std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
  180. struct packed_endian_specific_integral {
  181. using value_type = ValueType;
  182. static constexpr endianness endian = Endian;
  183. static constexpr std::size_t alignment = Alignment;
  184. packed_endian_specific_integral() = default;
  185. explicit packed_endian_specific_integral(value_type val) { *this = val; }
  186. operator value_type() const {
  187. return endian::read<value_type, endian, alignment>(
  188. (const void*)Value.buffer);
  189. }
  190. void operator=(value_type newValue) {
  191. endian::write<value_type, endian, alignment>(
  192. (void*)Value.buffer, newValue);
  193. }
  194. packed_endian_specific_integral &operator+=(value_type newValue) {
  195. *this = *this + newValue;
  196. return *this;
  197. }
  198. packed_endian_specific_integral &operator-=(value_type newValue) {
  199. *this = *this - newValue;
  200. return *this;
  201. }
  202. packed_endian_specific_integral &operator|=(value_type newValue) {
  203. *this = *this | newValue;
  204. return *this;
  205. }
  206. packed_endian_specific_integral &operator&=(value_type newValue) {
  207. *this = *this & newValue;
  208. return *this;
  209. }
  210. private:
  211. struct {
  212. alignas(ALIGN) char buffer[sizeof(value_type)];
  213. } Value;
  214. public:
  215. struct ref {
  216. explicit ref(void *Ptr) : Ptr(Ptr) {}
  217. operator value_type() const {
  218. return endian::read<value_type, endian, alignment>(Ptr);
  219. }
  220. void operator=(value_type NewValue) {
  221. endian::write<value_type, endian, alignment>(Ptr, NewValue);
  222. }
  223. private:
  224. void *Ptr;
  225. };
  226. };
  227. } // end namespace detail
  228. using ulittle16_t =
  229. detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
  230. using ulittle32_t =
  231. detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
  232. using ulittle64_t =
  233. detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
  234. using little16_t =
  235. detail::packed_endian_specific_integral<int16_t, little, unaligned>;
  236. using little32_t =
  237. detail::packed_endian_specific_integral<int32_t, little, unaligned>;
  238. using little64_t =
  239. detail::packed_endian_specific_integral<int64_t, little, unaligned>;
  240. using aligned_ulittle16_t =
  241. detail::packed_endian_specific_integral<uint16_t, little, aligned>;
  242. using aligned_ulittle32_t =
  243. detail::packed_endian_specific_integral<uint32_t, little, aligned>;
  244. using aligned_ulittle64_t =
  245. detail::packed_endian_specific_integral<uint64_t, little, aligned>;
  246. using aligned_little16_t =
  247. detail::packed_endian_specific_integral<int16_t, little, aligned>;
  248. using aligned_little32_t =
  249. detail::packed_endian_specific_integral<int32_t, little, aligned>;
  250. using aligned_little64_t =
  251. detail::packed_endian_specific_integral<int64_t, little, aligned>;
  252. using ubig16_t =
  253. detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
  254. using ubig32_t =
  255. detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
  256. using ubig64_t =
  257. detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
  258. using big16_t =
  259. detail::packed_endian_specific_integral<int16_t, big, unaligned>;
  260. using big32_t =
  261. detail::packed_endian_specific_integral<int32_t, big, unaligned>;
  262. using big64_t =
  263. detail::packed_endian_specific_integral<int64_t, big, unaligned>;
  264. using aligned_ubig16_t =
  265. detail::packed_endian_specific_integral<uint16_t, big, aligned>;
  266. using aligned_ubig32_t =
  267. detail::packed_endian_specific_integral<uint32_t, big, aligned>;
  268. using aligned_ubig64_t =
  269. detail::packed_endian_specific_integral<uint64_t, big, aligned>;
  270. using aligned_big16_t =
  271. detail::packed_endian_specific_integral<int16_t, big, aligned>;
  272. using aligned_big32_t =
  273. detail::packed_endian_specific_integral<int32_t, big, aligned>;
  274. using aligned_big64_t =
  275. detail::packed_endian_specific_integral<int64_t, big, aligned>;
  276. using unaligned_uint16_t =
  277. detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
  278. using unaligned_uint32_t =
  279. detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
  280. using unaligned_uint64_t =
  281. detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
  282. using unaligned_int16_t =
  283. detail::packed_endian_specific_integral<int16_t, native, unaligned>;
  284. using unaligned_int32_t =
  285. detail::packed_endian_specific_integral<int32_t, native, unaligned>;
  286. using unaligned_int64_t =
  287. detail::packed_endian_specific_integral<int64_t, native, unaligned>;
  288. template <typename T>
  289. using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
  290. template <typename T>
  291. using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
  292. template <typename T>
  293. using aligned_little_t =
  294. detail::packed_endian_specific_integral<T, little, aligned>;
  295. template <typename T>
  296. using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
  297. namespace endian {
  298. template <typename T> inline T read(const void *P, endianness E) {
  299. return read<T, unaligned>(P, E);
  300. }
  301. template <typename T, endianness E> inline T read(const void *P) {
  302. return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
  303. }
  304. inline uint16_t read16(const void *P, endianness E) {
  305. return read<uint16_t>(P, E);
  306. }
  307. inline uint32_t read32(const void *P, endianness E) {
  308. return read<uint32_t>(P, E);
  309. }
  310. inline uint64_t read64(const void *P, endianness E) {
  311. return read<uint64_t>(P, E);
  312. }
  313. template <endianness E> inline uint16_t read16(const void *P) {
  314. return read<uint16_t, E>(P);
  315. }
  316. template <endianness E> inline uint32_t read32(const void *P) {
  317. return read<uint32_t, E>(P);
  318. }
  319. template <endianness E> inline uint64_t read64(const void *P) {
  320. return read<uint64_t, E>(P);
  321. }
  322. inline uint16_t read16le(const void *P) { return read16<little>(P); }
  323. inline uint32_t read32le(const void *P) { return read32<little>(P); }
  324. inline uint64_t read64le(const void *P) { return read64<little>(P); }
  325. inline uint16_t read16be(const void *P) { return read16<big>(P); }
  326. inline uint32_t read32be(const void *P) { return read32<big>(P); }
  327. inline uint64_t read64be(const void *P) { return read64<big>(P); }
  328. template <typename T> inline void write(void *P, T V, endianness E) {
  329. write<T, unaligned>(P, V, E);
  330. }
  331. template <typename T, endianness E> inline void write(void *P, T V) {
  332. *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
  333. }
  334. inline void write16(void *P, uint16_t V, endianness E) {
  335. write<uint16_t>(P, V, E);
  336. }
  337. inline void write32(void *P, uint32_t V, endianness E) {
  338. write<uint32_t>(P, V, E);
  339. }
  340. inline void write64(void *P, uint64_t V, endianness E) {
  341. write<uint64_t>(P, V, E);
  342. }
  343. template <endianness E> inline void write16(void *P, uint16_t V) {
  344. write<uint16_t, E>(P, V);
  345. }
  346. template <endianness E> inline void write32(void *P, uint32_t V) {
  347. write<uint32_t, E>(P, V);
  348. }
  349. template <endianness E> inline void write64(void *P, uint64_t V) {
  350. write<uint64_t, E>(P, V);
  351. }
  352. inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
  353. inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
  354. inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
  355. inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
  356. inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
  357. inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
  358. } // end namespace endian
  359. } // end namespace support
  360. } // end namespace llvm
  361. #endif // LLVM_SUPPORT_ENDIAN_H
  362. #ifdef __GNUC__
  363. #pragma GCC diagnostic pop
  364. #endif