LCOV - code coverage report
Current view: top level - include/llvm/Support - Endian.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 35 59 59.3 %
Date: 2018-10-20 13:21:21 Functions: 1 8 12.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13