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