Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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