X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FSupport%2FEndian.h;h=bc93c9a66eef9a221a13ae534782c409ae06554e;hb=40288f72380d2951cd2d4034922c2c515acb6cfd;hp=f62eab0702b4508a1a7678472ce9e44c566e6baf;hpb=1f6efa3996dd1929fbc129203ce5009b620e6969;p=oota-llvm.git diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index f62eab0702b..bc93c9a66ee 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -14,129 +14,218 @@ #ifndef LLVM_SUPPORT_ENDIAN_H #define LLVM_SUPPORT_ENDIAN_H -#include "llvm/Config/config.h" +#include "llvm/Support/AlignOf.h" #include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" -#include "llvm/Support/type_traits.h" namespace llvm { namespace support { +enum endianness {big, little, native}; -enum endianness {big, little}; -enum alignment {unaligned, aligned}; +// These are named values for common alignments. +enum {aligned = 0, unaligned = 1}; namespace detail { + /// \brief ::value is either alignment, or alignof(T) if alignment is 0. + template + struct PickAlignment { + enum {value = alignment == 0 ? AlignOf::Alignment : alignment}; + }; +} // end namespace detail -template -struct alignment_access_helper; +namespace endian { +/// Swap the bytes of value to match the given endianness. +template +inline value_type byte_swap(value_type value) { + if (endian != native && sys::IsBigEndianHost != (endian == big)) + sys::swapByteOrder(value); + return value; +} -template -struct alignment_access_helper -{ - value_type val; -}; +/// Read a value of a particular endianness from memory. +template +inline value_type read(const void *memory) { + value_type ret; -// Provides unaligned loads and stores. -#pragma pack(push) -#pragma pack(1) -template -struct alignment_access_helper -{ - value_type val; -}; -#pragma pack(pop) + memcpy(&ret, + LLVM_ASSUME_ALIGNED(memory, + (detail::PickAlignment::value)), + sizeof(value_type)); + return byte_swap(ret); +} -} // end namespace detail +/// Read a value of a particular endianness from a buffer, and increment the +/// buffer past that value. +template +inline value_type readNext(const CharT *&memory) { + value_type ret = read(memory); + memory += sizeof(value_type); + return ret; +} -namespace endian { - template - static value_type read_le(const void *memory) { - value_type t = - reinterpret_cast *>(memory)->val; - if (sys::isBigEndianHost()) - return sys::SwapByteOrder(t); - return t; - } +/// Write a value to memory with a particular endianness. +template +inline void write(void *memory, value_type value) { + value = byte_swap(value); + memcpy(LLVM_ASSUME_ALIGNED(memory, + (detail::PickAlignment::value)), + &value, + sizeof(value_type)); +} - template - static void write_le(void *memory, value_type value) { - if (sys::isBigEndianHost()) - value = sys::SwapByteOrder(value); - reinterpret_cast *> - (memory)->val = value; - } +template +using make_unsigned_t = typename std::make_unsigned::type; + +/// Read a value of a particular endianness from memory, for a location +/// that starts at the given bit offset within the first byte. +template +inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + return read(memory); + else { + // Read two values and compose the result from them. + value_type val[2]; + memcpy(&val[0], + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment::value)), + sizeof(value_type) * 2); + val[0] = byte_swap(val[0]); + val[1] = byte_swap(val[1]); + + // Shift bits from the lower value into place. + make_unsigned_t lowerVal = val[0] >> startBit; + // Mask off upper bits after right shift in case of signed type. + make_unsigned_t numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + lowerVal &= ((make_unsigned_t)1 << numBitsFirstVal) - 1; - template - static value_type read_be(const void *memory) { - value_type t = - reinterpret_cast *>(memory)->val; - if (sys::isLittleEndianHost()) - return sys::SwapByteOrder(t); - return t; + // Get the bits from the upper value. + make_unsigned_t upperVal = + val[1] & (((make_unsigned_t)1 << startBit) - 1); + // Shift them in to place. + upperVal <<= numBitsFirstVal; + + return lowerVal | upperVal; } +} - template - static void write_be(void *memory, value_type value) { - if (sys::isLittleEndianHost()) - value = sys::SwapByteOrder(value); - reinterpret_cast *> - (memory)->val = value; +/// Write a value to memory with a particular endianness, for a location +/// that starts at the given bit offset within the first byte. +template +inline void writeAtBitAlignment(void *memory, value_type value, + uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + write(memory, value); + else { + // Read two values and shift the result into them. + value_type val[2]; + memcpy(&val[0], + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment::value)), + sizeof(value_type) * 2); + val[0] = byte_swap(val[0]); + val[1] = byte_swap(val[1]); + + // Mask off any existing bits in the upper part of the lower value that + // we want to replace. + val[0] &= ((make_unsigned_t)1 << startBit) - 1; + make_unsigned_t numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + make_unsigned_t lowerVal = value; + if (startBit > 0) { + // Mask off the upper bits in the new value that are not going to go into + // the lower value. This avoids a left shift of a negative value, which + // is undefined behavior. + lowerVal &= (((make_unsigned_t)1 << numBitsFirstVal) - 1); + // Now shift the new bits into place + lowerVal <<= startBit; + } + val[0] |= lowerVal; + + // Mask off any existing bits in the lower part of the upper value that + // we want to replace. + val[1] &= ~(((make_unsigned_t)1 << startBit) - 1); + // Next shift the bits that go into the upper value into position. + make_unsigned_t upperVal = value >> numBitsFirstVal; + // Mask off upper bits after right shift in case of signed type. + upperVal &= ((make_unsigned_t)1 << startBit) - 1; + val[1] |= upperVal; + + // Finally, rewrite values. + val[0] = byte_swap(val[0]); + val[1] = byte_swap(val[1]); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment::value)), + &val[0], sizeof(value_type) * 2); } } +} // end namespace endian namespace detail { - template -class packed_endian_specific_integral; - -template -class packed_endian_specific_integral { -public: + std::size_t alignment> +struct packed_endian_specific_integral { operator value_type() const { - return endian::read_le(Value); + return endian::read( + (const void*)Value.buffer); } -private: - uint8_t Value[sizeof(value_type)]; -}; -template -class packed_endian_specific_integral { -public: - operator value_type() const { - return endian::read_be(Value); + void operator=(value_type newValue) { + endian::write( + (void*)Value.buffer, newValue); } -private: - uint8_t Value[sizeof(value_type)]; -}; -template -class packed_endian_specific_integral { -public: - operator value_type() const { - return endian::read_le(&Value); + packed_endian_specific_integral &operator+=(value_type newValue) { + *this = *this + newValue; + return *this; } -private: - value_type Value; -}; -template -class packed_endian_specific_integral { -public: - operator value_type() const { - return endian::read_be(&Value); + packed_endian_specific_integral &operator-=(value_type newValue) { + *this = *this - newValue; + return *this; + } + + packed_endian_specific_integral &operator|=(value_type newValue) { + *this = *this | newValue; + return *this; } + + packed_endian_specific_integral &operator&=(value_type newValue) { + *this = *this & newValue; + return *this; + } + private: - value_type Value; + AlignedCharArray::value, + sizeof(value_type)> Value; + +public: + struct ref { + explicit ref(void *Ptr) : Ptr(Ptr) {} + + operator value_type() const { + return endian::read(Ptr); + } + + void operator=(value_type NewValue) { + endian::write(Ptr, NewValue); + } + + private: + void *Ptr; + }; }; } // end namespace detail -typedef detail::packed_endian_specific_integral - ulittle8_t; typedef detail::packed_endian_specific_integral ulittle16_t; typedef detail::packed_endian_specific_integral @@ -144,8 +233,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral ulittle64_t; -typedef detail::packed_endian_specific_integral - little8_t; typedef detail::packed_endian_specific_integral little16_t; typedef detail::packed_endian_specific_integral @@ -153,8 +240,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral little64_t; -typedef detail::packed_endian_specific_integral - aligned_ulittle8_t; typedef detail::packed_endian_specific_integral aligned_ulittle16_t; typedef detail::packed_endian_specific_integral @@ -162,8 +247,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral aligned_ulittle64_t; -typedef detail::packed_endian_specific_integral - aligned_little8_t; typedef detail::packed_endian_specific_integral aligned_little16_t; typedef detail::packed_endian_specific_integral @@ -171,8 +254,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral aligned_little64_t; -typedef detail::packed_endian_specific_integral - ubig8_t; typedef detail::packed_endian_specific_integral ubig16_t; typedef detail::packed_endian_specific_integral @@ -180,8 +261,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral ubig64_t; -typedef detail::packed_endian_specific_integral - big8_t; typedef detail::packed_endian_specific_integral big16_t; typedef detail::packed_endian_specific_integral @@ -189,8 +268,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral big64_t; -typedef detail::packed_endian_specific_integral - aligned_ubig8_t; typedef detail::packed_endian_specific_integral aligned_ubig16_t; typedef detail::packed_endian_specific_integral @@ -198,8 +275,6 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral aligned_ubig64_t; -typedef detail::packed_endian_specific_integral - aligned_big8_t; typedef detail::packed_endian_specific_integral aligned_big16_t; typedef detail::packed_endian_specific_integral @@ -207,7 +282,64 @@ typedef detail::packed_endian_specific_integral typedef detail::packed_endian_specific_integral aligned_big64_t; -} // end namespace llvm +typedef detail::packed_endian_specific_integral + unaligned_uint16_t; +typedef detail::packed_endian_specific_integral + unaligned_uint32_t; +typedef detail::packed_endian_specific_integral + unaligned_uint64_t; + +typedef detail::packed_endian_specific_integral + unaligned_int16_t; +typedef detail::packed_endian_specific_integral + unaligned_int32_t; +typedef detail::packed_endian_specific_integral + unaligned_int64_t; + +namespace endian { +template inline T read(const void *P) { + return *(const detail::packed_endian_specific_integral *)P; +} + +template inline uint16_t read16(const void *P) { + return read(P); +} +template inline uint32_t read32(const void *P) { + return read(P); +} +template inline uint64_t read64(const void *P) { + return read(P); +} + +inline uint16_t read16le(const void *P) { return read16(P); } +inline uint32_t read32le(const void *P) { return read32(P); } +inline uint64_t read64le(const void *P) { return read64(P); } +inline uint16_t read16be(const void *P) { return read16(P); } +inline uint32_t read32be(const void *P) { return read32(P); } +inline uint64_t read64be(const void *P) { return read64(P); } + +template inline void write(void *P, T V) { + *(detail::packed_endian_specific_integral *)P = V; +} + +template inline void write16(void *P, uint16_t V) { + write(P, V); +} +template inline void write32(void *P, uint32_t V) { + write(P, V); +} +template inline void write64(void *P, uint64_t V) { + write(P, V); +} + +inline void write16le(void *P, uint16_t V) { write16(P, V); } +inline void write32le(void *P, uint32_t V) { write32(P, V); } +inline void write64le(void *P, uint64_t V) { write64(P, V); } +inline void write16be(void *P, uint16_t V) { write16(P, V); } +inline void write32be(void *P, uint32_t V) { write32(P, V); } +inline void write64be(void *P, uint64_t V) { write64(P, V); } +} // end namespace endian } // end namespace support +} // end namespace llvm #endif