X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FSupport%2FEndian.h;h=bc93c9a66eef9a221a13ae534782c409ae06554e;hb=HEAD;hp=c98e2dc66cc16671aba39c973e571844c2d89796;hpb=523579e0758bfa5781b63eabdc079a3ff074c36a;p=oota-llvm.git diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index c98e2dc66cc..bc93c9a66ee 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -14,144 +14,218 @@ #ifndef LLVM_SUPPORT_ENDIAN_H #define LLVM_SUPPORT_ENDIAN_H -#include "llvm/Config/config.h" -#include "llvm/System/SwapByteOrder.h" -#include "llvm/Support/type_traits.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.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}; -template -static typename enable_if_c::type -SwapByteOrderIfDifferent(value_type value) { - // Target endianess is the same as the host. Just pass the value through. +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 + +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 -static typename enable_if_c::type -SwapByteOrderIfDifferent(value_type value) { - return sys::SwapByteOrder(value); +/// Read a value of a particular endianness from memory. +template +inline value_type read(const void *memory) { + value_type ret; + + memcpy(&ret, + LLVM_ASSUME_ALIGNED(memory, + (detail::PickAlignment::value)), + sizeof(value_type)); + return byte_swap(ret); } -namespace detail { - -template -struct alignment_access_helper; - -template -struct alignment_access_helper -{ - value_type val; -}; - -// Provides unaligned loads and stores. -#pragma pack(push) -#pragma pack(1) -template -struct alignment_access_helper -{ - value_type val; -}; -#pragma pack(pop) - -} // 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; +} -#if defined(LLVM_IS_HOST_BIG_ENDIAN) \ - || defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__) -static const endianness host_endianness = big; -#else -static const endianness host_endianness = little; -#endif +/// 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)); +} -struct endian { - template - static value_type read_le(const void *memory) { - return SwapByteOrderIfDifferent( - reinterpret_cast *>(memory)->val); +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; + + // 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_le(void *memory, value_type value) { - reinterpret_cast *> - (memory)->val = - SwapByteOrderIfDifferent< value_type - , host_endianness - , little>(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 - template - static value_type read_be(const void *memory) { - return SwapByteOrderIfDifferent( - reinterpret_cast *>(memory)->val); +namespace detail { +template +struct packed_endian_specific_integral { + operator value_type() const { + return endian::read( + (const void*)Value.buffer); } - template - static void write_be(void *memory, value_type value) { - reinterpret_cast *>(memory)->val = - SwapByteOrderIfDifferent< value_type - , host_endianness - , big>(value); + void operator=(value_type newValue) { + endian::write( + (void*)Value.buffer, newValue); } -}; - -namespace detail { -template -class packed_endian_specific_integral; + packed_endian_specific_integral &operator+=(value_type newValue) { + *this = *this + newValue; + return *this; + } -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: - uint8_t Value[sizeof(value_type)]; -}; -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; } -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; -}; + AlignedCharArray::value, + sizeof(value_type)> Value; -template -class packed_endian_specific_integral { public: - operator value_type() const { - return endian::read_be(&Value); - } -private: - value_type Value; + 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 @@ -159,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 @@ -168,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 @@ -177,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 @@ -186,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 @@ -195,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 @@ -204,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 @@ -213,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 @@ -222,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