diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/llvm12/include/llvm/Support/Endian.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/llvm12/include/llvm/Support/Endian.h')
-rw-r--r-- | contrib/libs/llvm12/include/llvm/Support/Endian.h | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/include/llvm/Support/Endian.h b/contrib/libs/llvm12/include/llvm/Support/Endian.h new file mode 100644 index 0000000000..6f0e54a227 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Support/Endian.h @@ -0,0 +1,438 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares generic functions to read and write endian specific data. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ENDIAN_H +#define LLVM_SUPPORT_ENDIAN_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/SwapByteOrder.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <type_traits> + +namespace llvm { +namespace support { + +enum endianness {big, little, native}; + +// These are named values for common alignments. +enum {aligned = 0, unaligned = 1}; + +namespace detail { + +/// ::value is either alignment, or alignof(T) if alignment is 0. +template<class T, int alignment> +struct PickAlignment { + enum { value = alignment == 0 ? alignof(T) : alignment }; +}; + +} // end namespace detail + +namespace endian { + +constexpr endianness system_endianness() { + return sys::IsBigEndianHost ? big : little; +} + +template <typename value_type> +inline value_type byte_swap(value_type value, endianness endian) { + if ((endian != native) && (endian != system_endianness())) + sys::swapByteOrder(value); + return value; +} + +/// Swap the bytes of value to match the given endianness. +template<typename value_type, endianness endian> +inline value_type byte_swap(value_type value) { + return byte_swap(value, endian); +} + +/// Read a value of a particular endianness from memory. +template <typename value_type, std::size_t alignment> +inline value_type read(const void *memory, endianness endian) { + value_type ret; + + memcpy(&ret, + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + sizeof(value_type)); + return byte_swap<value_type>(ret, endian); +} + +template<typename value_type, + endianness endian, + std::size_t alignment> +inline value_type read(const void *memory) { + return read<value_type, alignment>(memory, endian); +} + +/// Read a value of a particular endianness from a buffer, and increment the +/// buffer past that value. +template <typename value_type, std::size_t alignment, typename CharT> +inline value_type readNext(const CharT *&memory, endianness endian) { + value_type ret = read<value_type, alignment>(memory, endian); + memory += sizeof(value_type); + return ret; +} + +template<typename value_type, endianness endian, std::size_t alignment, + typename CharT> +inline value_type readNext(const CharT *&memory) { + return readNext<value_type, alignment, CharT>(memory, endian); +} + +/// Write a value to memory with a particular endianness. +template <typename value_type, std::size_t alignment> +inline void write(void *memory, value_type value, endianness endian) { + value = byte_swap<value_type>(value, endian); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + &value, sizeof(value_type)); +} + +template<typename value_type, + endianness endian, + std::size_t alignment> +inline void write(void *memory, value_type value) { + write<value_type, alignment>(memory, value, endian); +} + +template <typename value_type> +using make_unsigned_t = std::make_unsigned_t<value_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 <typename value_type, endianness endian, std::size_t alignment> +inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + return read<value_type, endian, alignment>(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_type, alignment>::value)), + sizeof(value_type) * 2); + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(val[1]); + + // Shift bits from the lower value into place. + make_unsigned_t<value_type> lowerVal = val[0] >> startBit; + // Mask off upper bits after right shift in case of signed type. + make_unsigned_t<value_type> numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1; + + // Get the bits from the upper value. + make_unsigned_t<value_type> upperVal = + val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1); + // Shift them in to place. + upperVal <<= numBitsFirstVal; + + return lowerVal | upperVal; + } +} + +/// Write a value to memory with a particular endianness, for a location +/// that starts at the given bit offset within the first byte. +template <typename value_type, endianness endian, std::size_t alignment> +inline void writeAtBitAlignment(void *memory, value_type value, + uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + write<value_type, endian, alignment>(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_type, alignment>::value)), + sizeof(value_type) * 2); + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(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<value_type>)1 << startBit) - 1; + make_unsigned_t<value_type> numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + make_unsigned_t<value_type> 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<value_type>)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<value_type>)1 << startBit) - 1); + // Next shift the bits that go into the upper value into position. + make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal; + // Mask off upper bits after right shift in case of signed type. + upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1; + val[1] |= upperVal; + + // Finally, rewrite values. + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(val[1]); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + &val[0], sizeof(value_type) * 2); + } +} + +} // end namespace endian + +namespace detail { + +template <typename ValueType, endianness Endian, std::size_t Alignment, + std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value> +struct packed_endian_specific_integral { + using value_type = ValueType; + static constexpr endianness endian = Endian; + static constexpr std::size_t alignment = Alignment; + + packed_endian_specific_integral() = default; + + explicit packed_endian_specific_integral(value_type val) { *this = val; } + + operator value_type() const { + return endian::read<value_type, endian, alignment>( + (const void*)Value.buffer); + } + + void operator=(value_type newValue) { + endian::write<value_type, endian, alignment>( + (void*)Value.buffer, newValue); + } + + 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; + } + + packed_endian_specific_integral &operator&=(value_type newValue) { + *this = *this & newValue; + return *this; + } + +private: + struct { + alignas(ALIGN) char buffer[sizeof(value_type)]; + } Value; + +public: + struct ref { + explicit ref(void *Ptr) : Ptr(Ptr) {} + + operator value_type() const { + return endian::read<value_type, endian, alignment>(Ptr); + } + + void operator=(value_type NewValue) { + endian::write<value_type, endian, alignment>(Ptr, NewValue); + } + + private: + void *Ptr; + }; +}; + +} // end namespace detail + +using ulittle16_t = + detail::packed_endian_specific_integral<uint16_t, little, unaligned>; +using ulittle32_t = + detail::packed_endian_specific_integral<uint32_t, little, unaligned>; +using ulittle64_t = + detail::packed_endian_specific_integral<uint64_t, little, unaligned>; + +using little16_t = + detail::packed_endian_specific_integral<int16_t, little, unaligned>; +using little32_t = + detail::packed_endian_specific_integral<int32_t, little, unaligned>; +using little64_t = + detail::packed_endian_specific_integral<int64_t, little, unaligned>; + +using aligned_ulittle16_t = + detail::packed_endian_specific_integral<uint16_t, little, aligned>; +using aligned_ulittle32_t = + detail::packed_endian_specific_integral<uint32_t, little, aligned>; +using aligned_ulittle64_t = + detail::packed_endian_specific_integral<uint64_t, little, aligned>; + +using aligned_little16_t = + detail::packed_endian_specific_integral<int16_t, little, aligned>; +using aligned_little32_t = + detail::packed_endian_specific_integral<int32_t, little, aligned>; +using aligned_little64_t = + detail::packed_endian_specific_integral<int64_t, little, aligned>; + +using ubig16_t = + detail::packed_endian_specific_integral<uint16_t, big, unaligned>; +using ubig32_t = + detail::packed_endian_specific_integral<uint32_t, big, unaligned>; +using ubig64_t = + detail::packed_endian_specific_integral<uint64_t, big, unaligned>; + +using big16_t = + detail::packed_endian_specific_integral<int16_t, big, unaligned>; +using big32_t = + detail::packed_endian_specific_integral<int32_t, big, unaligned>; +using big64_t = + detail::packed_endian_specific_integral<int64_t, big, unaligned>; + +using aligned_ubig16_t = + detail::packed_endian_specific_integral<uint16_t, big, aligned>; +using aligned_ubig32_t = + detail::packed_endian_specific_integral<uint32_t, big, aligned>; +using aligned_ubig64_t = + detail::packed_endian_specific_integral<uint64_t, big, aligned>; + +using aligned_big16_t = + detail::packed_endian_specific_integral<int16_t, big, aligned>; +using aligned_big32_t = + detail::packed_endian_specific_integral<int32_t, big, aligned>; +using aligned_big64_t = + detail::packed_endian_specific_integral<int64_t, big, aligned>; + +using unaligned_uint16_t = + detail::packed_endian_specific_integral<uint16_t, native, unaligned>; +using unaligned_uint32_t = + detail::packed_endian_specific_integral<uint32_t, native, unaligned>; +using unaligned_uint64_t = + detail::packed_endian_specific_integral<uint64_t, native, unaligned>; + +using unaligned_int16_t = + detail::packed_endian_specific_integral<int16_t, native, unaligned>; +using unaligned_int32_t = + detail::packed_endian_specific_integral<int32_t, native, unaligned>; +using unaligned_int64_t = + detail::packed_endian_specific_integral<int64_t, native, unaligned>; + +template <typename T> +using little_t = detail::packed_endian_specific_integral<T, little, unaligned>; +template <typename T> +using big_t = detail::packed_endian_specific_integral<T, big, unaligned>; + +template <typename T> +using aligned_little_t = + detail::packed_endian_specific_integral<T, little, aligned>; +template <typename T> +using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>; + +namespace endian { + +template <typename T> inline T read(const void *P, endianness E) { + return read<T, unaligned>(P, E); +} + +template <typename T, endianness E> inline T read(const void *P) { + return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P; +} + +inline uint16_t read16(const void *P, endianness E) { + return read<uint16_t>(P, E); +} +inline uint32_t read32(const void *P, endianness E) { + return read<uint32_t>(P, E); +} +inline uint64_t read64(const void *P, endianness E) { + return read<uint64_t>(P, E); +} + +template <endianness E> inline uint16_t read16(const void *P) { + return read<uint16_t, E>(P); +} +template <endianness E> inline uint32_t read32(const void *P) { + return read<uint32_t, E>(P); +} +template <endianness E> inline uint64_t read64(const void *P) { + return read<uint64_t, E>(P); +} + +inline uint16_t read16le(const void *P) { return read16<little>(P); } +inline uint32_t read32le(const void *P) { return read32<little>(P); } +inline uint64_t read64le(const void *P) { return read64<little>(P); } +inline uint16_t read16be(const void *P) { return read16<big>(P); } +inline uint32_t read32be(const void *P) { return read32<big>(P); } +inline uint64_t read64be(const void *P) { return read64<big>(P); } + +template <typename T> inline void write(void *P, T V, endianness E) { + write<T, unaligned>(P, V, E); +} + +template <typename T, endianness E> inline void write(void *P, T V) { + *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V; +} + +inline void write16(void *P, uint16_t V, endianness E) { + write<uint16_t>(P, V, E); +} +inline void write32(void *P, uint32_t V, endianness E) { + write<uint32_t>(P, V, E); +} +inline void write64(void *P, uint64_t V, endianness E) { + write<uint64_t>(P, V, E); +} + +template <endianness E> inline void write16(void *P, uint16_t V) { + write<uint16_t, E>(P, V); +} +template <endianness E> inline void write32(void *P, uint32_t V) { + write<uint32_t, E>(P, V); +} +template <endianness E> inline void write64(void *P, uint64_t V) { + write<uint64_t, E>(P, V); +} + +inline void write16le(void *P, uint16_t V) { write16<little>(P, V); } +inline void write32le(void *P, uint32_t V) { write32<little>(P, V); } +inline void write64le(void *P, uint64_t V) { write64<little>(P, V); } +inline void write16be(void *P, uint16_t V) { write16<big>(P, V); } +inline void write32be(void *P, uint32_t V) { write32<big>(P, V); } +inline void write64be(void *P, uint64_t V) { write64<big>(P, V); } + +} // end namespace endian + +} // end namespace support +} // end namespace llvm + +#endif // LLVM_SUPPORT_ENDIAN_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |