File indexing completed on 2026-05-10 08:44:29
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_SUPPORT_ENDIAN_H
0014 #define LLVM_SUPPORT_ENDIAN_H
0015
0016 #include "llvm/ADT/bit.h"
0017 #include "llvm/Support/Compiler.h"
0018 #include "llvm/Support/SwapByteOrder.h"
0019 #include <cassert>
0020 #include <cstddef>
0021 #include <cstdint>
0022 #include <cstring>
0023 #include <type_traits>
0024
0025 namespace llvm {
0026 namespace support {
0027
0028
0029 enum {aligned = 0, unaligned = 1};
0030
0031 namespace detail {
0032
0033
0034 template<class T, int alignment>
0035 struct PickAlignment {
0036 enum { value = alignment == 0 ? alignof(T) : alignment };
0037 };
0038
0039 }
0040
0041 namespace endian {
0042
0043 template <typename value_type>
0044 [[nodiscard]] inline value_type byte_swap(value_type value, endianness endian) {
0045 if (endian != llvm::endianness::native)
0046 sys::swapByteOrder(value);
0047 return value;
0048 }
0049
0050
0051 template <typename value_type, endianness endian>
0052 [[nodiscard]] inline value_type byte_swap(value_type value) {
0053 return byte_swap(value, endian);
0054 }
0055
0056
0057 template <typename value_type, std::size_t alignment = unaligned>
0058 [[nodiscard]] inline value_type read(const void *memory, endianness endian) {
0059 value_type ret;
0060
0061 memcpy(static_cast<void *>(&ret),
0062 LLVM_ASSUME_ALIGNED(
0063 memory, (detail::PickAlignment<value_type, alignment>::value)),
0064 sizeof(value_type));
0065 return byte_swap<value_type>(ret, endian);
0066 }
0067
0068 template <typename value_type, endianness endian, std::size_t alignment>
0069 [[nodiscard]] inline value_type read(const void *memory) {
0070 return read<value_type, alignment>(memory, endian);
0071 }
0072
0073
0074
0075 template <typename value_type, std::size_t alignment = unaligned,
0076 typename CharT>
0077 [[nodiscard]] inline value_type readNext(const CharT *&memory,
0078 endianness endian) {
0079 value_type ret = read<value_type, alignment>(memory, endian);
0080 memory += sizeof(value_type);
0081 return ret;
0082 }
0083
0084 template <typename value_type, endianness endian,
0085 std::size_t alignment = unaligned, typename CharT>
0086 [[nodiscard]] inline value_type readNext(const CharT *&memory) {
0087 return readNext<value_type, alignment, CharT>(memory, endian);
0088 }
0089
0090
0091 template <typename value_type, std::size_t alignment = unaligned>
0092 inline void write(void *memory, value_type value, endianness endian) {
0093 value = byte_swap<value_type>(value, endian);
0094 memcpy(LLVM_ASSUME_ALIGNED(
0095 memory, (detail::PickAlignment<value_type, alignment>::value)),
0096 &value, sizeof(value_type));
0097 }
0098
0099 template<typename value_type,
0100 endianness endian,
0101 std::size_t alignment>
0102 inline void write(void *memory, value_type value) {
0103 write<value_type, alignment>(memory, value, endian);
0104 }
0105
0106
0107
0108 template <typename value_type, std::size_t alignment = unaligned,
0109 typename CharT>
0110 inline void writeNext(CharT *&memory, value_type value, endianness endian) {
0111 write(memory, value, endian);
0112 memory += sizeof(value_type);
0113 }
0114
0115 template <typename value_type, endianness endian,
0116 std::size_t alignment = unaligned, typename CharT>
0117 inline void writeNext(CharT *&memory, value_type value) {
0118 writeNext<value_type, alignment, CharT>(memory, value, endian);
0119 }
0120
0121 template <typename value_type>
0122 using make_unsigned_t = std::make_unsigned_t<value_type>;
0123
0124
0125
0126 template <typename value_type, endianness endian, std::size_t alignment>
0127 [[nodiscard]] inline value_type readAtBitAlignment(const void *memory,
0128 uint64_t startBit) {
0129 assert(startBit < 8);
0130 if (startBit == 0)
0131 return read<value_type, endian, alignment>(memory);
0132 else {
0133
0134 value_type val[2];
0135 memcpy(&val[0],
0136 LLVM_ASSUME_ALIGNED(
0137 memory, (detail::PickAlignment<value_type, alignment>::value)),
0138 sizeof(value_type) * 2);
0139 val[0] = byte_swap<value_type, endian>(val[0]);
0140 val[1] = byte_swap<value_type, endian>(val[1]);
0141
0142
0143 make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
0144
0145 make_unsigned_t<value_type> numBitsFirstVal =
0146 (sizeof(value_type) * 8) - startBit;
0147 lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
0148
0149
0150 make_unsigned_t<value_type> upperVal =
0151 val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
0152
0153 upperVal <<= numBitsFirstVal;
0154
0155 return lowerVal | upperVal;
0156 }
0157 }
0158
0159
0160
0161 template <typename value_type, endianness endian, std::size_t alignment>
0162 inline void writeAtBitAlignment(void *memory, value_type value,
0163 uint64_t startBit) {
0164 assert(startBit < 8);
0165 if (startBit == 0)
0166 write<value_type, endian, alignment>(memory, value);
0167 else {
0168
0169 value_type val[2];
0170 memcpy(&val[0],
0171 LLVM_ASSUME_ALIGNED(
0172 memory, (detail::PickAlignment<value_type, alignment>::value)),
0173 sizeof(value_type) * 2);
0174 val[0] = byte_swap<value_type, endian>(val[0]);
0175 val[1] = byte_swap<value_type, endian>(val[1]);
0176
0177
0178
0179 val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
0180 make_unsigned_t<value_type> numBitsFirstVal =
0181 (sizeof(value_type) * 8) - startBit;
0182 make_unsigned_t<value_type> lowerVal = value;
0183 if (startBit > 0) {
0184
0185
0186
0187 lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
0188
0189 lowerVal <<= startBit;
0190 }
0191 val[0] |= lowerVal;
0192
0193
0194
0195 val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
0196
0197 make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
0198
0199 upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
0200 val[1] |= upperVal;
0201
0202
0203 val[0] = byte_swap<value_type, endian>(val[0]);
0204 val[1] = byte_swap<value_type, endian>(val[1]);
0205 memcpy(LLVM_ASSUME_ALIGNED(
0206 memory, (detail::PickAlignment<value_type, alignment>::value)),
0207 &val[0], sizeof(value_type) * 2);
0208 }
0209 }
0210
0211 }
0212
0213 namespace detail {
0214
0215 template <typename ValueType, endianness Endian, std::size_t Alignment,
0216 std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
0217 struct packed_endian_specific_integral {
0218 using value_type = ValueType;
0219 static constexpr endianness endian = Endian;
0220 static constexpr std::size_t alignment = Alignment;
0221
0222 packed_endian_specific_integral() = default;
0223
0224 explicit packed_endian_specific_integral(value_type val) { *this = val; }
0225
0226 operator value_type() const {
0227 return endian::read<value_type, endian, alignment>(
0228 (const void*)Value.buffer);
0229 }
0230
0231 void operator=(value_type newValue) {
0232 endian::write<value_type, endian, alignment>(
0233 (void*)Value.buffer, newValue);
0234 }
0235
0236 packed_endian_specific_integral &operator+=(value_type newValue) {
0237 *this = *this + newValue;
0238 return *this;
0239 }
0240
0241 packed_endian_specific_integral &operator-=(value_type newValue) {
0242 *this = *this - newValue;
0243 return *this;
0244 }
0245
0246 packed_endian_specific_integral &operator|=(value_type newValue) {
0247 *this = *this | newValue;
0248 return *this;
0249 }
0250
0251 packed_endian_specific_integral &operator&=(value_type newValue) {
0252 *this = *this & newValue;
0253 return *this;
0254 }
0255
0256 private:
0257 struct {
0258 alignas(ALIGN) char buffer[sizeof(value_type)];
0259 } Value;
0260
0261 public:
0262 struct ref {
0263 explicit ref(void *Ptr) : Ptr(Ptr) {}
0264
0265 operator value_type() const {
0266 return endian::read<value_type, endian, alignment>(Ptr);
0267 }
0268
0269 void operator=(value_type NewValue) {
0270 endian::write<value_type, endian, alignment>(Ptr, NewValue);
0271 }
0272
0273 private:
0274 void *Ptr;
0275 };
0276 };
0277
0278 }
0279
0280 using ulittle16_t =
0281 detail::packed_endian_specific_integral<uint16_t, llvm::endianness::little,
0282 unaligned>;
0283 using ulittle32_t =
0284 detail::packed_endian_specific_integral<uint32_t, llvm::endianness::little,
0285 unaligned>;
0286 using ulittle64_t =
0287 detail::packed_endian_specific_integral<uint64_t, llvm::endianness::little,
0288 unaligned>;
0289
0290 using little16_t =
0291 detail::packed_endian_specific_integral<int16_t, llvm::endianness::little,
0292 unaligned>;
0293 using little32_t =
0294 detail::packed_endian_specific_integral<int32_t, llvm::endianness::little,
0295 unaligned>;
0296 using little64_t =
0297 detail::packed_endian_specific_integral<int64_t, llvm::endianness::little,
0298 unaligned>;
0299
0300 using aligned_ulittle16_t =
0301 detail::packed_endian_specific_integral<uint16_t, llvm::endianness::little,
0302 aligned>;
0303 using aligned_ulittle32_t =
0304 detail::packed_endian_specific_integral<uint32_t, llvm::endianness::little,
0305 aligned>;
0306 using aligned_ulittle64_t =
0307 detail::packed_endian_specific_integral<uint64_t, llvm::endianness::little,
0308 aligned>;
0309
0310 using aligned_little16_t =
0311 detail::packed_endian_specific_integral<int16_t, llvm::endianness::little,
0312 aligned>;
0313 using aligned_little32_t =
0314 detail::packed_endian_specific_integral<int32_t, llvm::endianness::little,
0315 aligned>;
0316 using aligned_little64_t =
0317 detail::packed_endian_specific_integral<int64_t, llvm::endianness::little,
0318 aligned>;
0319
0320 using ubig16_t =
0321 detail::packed_endian_specific_integral<uint16_t, llvm::endianness::big,
0322 unaligned>;
0323 using ubig32_t =
0324 detail::packed_endian_specific_integral<uint32_t, llvm::endianness::big,
0325 unaligned>;
0326 using ubig64_t =
0327 detail::packed_endian_specific_integral<uint64_t, llvm::endianness::big,
0328 unaligned>;
0329
0330 using big16_t =
0331 detail::packed_endian_specific_integral<int16_t, llvm::endianness::big,
0332 unaligned>;
0333 using big32_t =
0334 detail::packed_endian_specific_integral<int32_t, llvm::endianness::big,
0335 unaligned>;
0336 using big64_t =
0337 detail::packed_endian_specific_integral<int64_t, llvm::endianness::big,
0338 unaligned>;
0339
0340 using aligned_ubig16_t =
0341 detail::packed_endian_specific_integral<uint16_t, llvm::endianness::big,
0342 aligned>;
0343 using aligned_ubig32_t =
0344 detail::packed_endian_specific_integral<uint32_t, llvm::endianness::big,
0345 aligned>;
0346 using aligned_ubig64_t =
0347 detail::packed_endian_specific_integral<uint64_t, llvm::endianness::big,
0348 aligned>;
0349
0350 using aligned_big16_t =
0351 detail::packed_endian_specific_integral<int16_t, llvm::endianness::big,
0352 aligned>;
0353 using aligned_big32_t =
0354 detail::packed_endian_specific_integral<int32_t, llvm::endianness::big,
0355 aligned>;
0356 using aligned_big64_t =
0357 detail::packed_endian_specific_integral<int64_t, llvm::endianness::big,
0358 aligned>;
0359
0360 using unaligned_uint16_t =
0361 detail::packed_endian_specific_integral<uint16_t, llvm::endianness::native,
0362 unaligned>;
0363 using unaligned_uint32_t =
0364 detail::packed_endian_specific_integral<uint32_t, llvm::endianness::native,
0365 unaligned>;
0366 using unaligned_uint64_t =
0367 detail::packed_endian_specific_integral<uint64_t, llvm::endianness::native,
0368 unaligned>;
0369
0370 using unaligned_int16_t =
0371 detail::packed_endian_specific_integral<int16_t, llvm::endianness::native,
0372 unaligned>;
0373 using unaligned_int32_t =
0374 detail::packed_endian_specific_integral<int32_t, llvm::endianness::native,
0375 unaligned>;
0376 using unaligned_int64_t =
0377 detail::packed_endian_specific_integral<int64_t, llvm::endianness::native,
0378 unaligned>;
0379
0380 template <typename T>
0381 using little_t =
0382 detail::packed_endian_specific_integral<T, llvm::endianness::little,
0383 unaligned>;
0384 template <typename T>
0385 using big_t = detail::packed_endian_specific_integral<T, llvm::endianness::big,
0386 unaligned>;
0387
0388 template <typename T>
0389 using aligned_little_t =
0390 detail::packed_endian_specific_integral<T, llvm::endianness::little,
0391 aligned>;
0392 template <typename T>
0393 using aligned_big_t =
0394 detail::packed_endian_specific_integral<T, llvm::endianness::big, aligned>;
0395
0396 namespace endian {
0397
0398 template <typename T, endianness E> [[nodiscard]] inline T read(const void *P) {
0399 return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
0400 }
0401
0402 [[nodiscard]] inline uint16_t read16(const void *P, endianness E) {
0403 return read<uint16_t>(P, E);
0404 }
0405 [[nodiscard]] inline uint32_t read32(const void *P, endianness E) {
0406 return read<uint32_t>(P, E);
0407 }
0408 [[nodiscard]] inline uint64_t read64(const void *P, endianness E) {
0409 return read<uint64_t>(P, E);
0410 }
0411
0412 template <endianness E> [[nodiscard]] inline uint16_t read16(const void *P) {
0413 return read<uint16_t, E>(P);
0414 }
0415 template <endianness E> [[nodiscard]] inline uint32_t read32(const void *P) {
0416 return read<uint32_t, E>(P);
0417 }
0418 template <endianness E> [[nodiscard]] inline uint64_t read64(const void *P) {
0419 return read<uint64_t, E>(P);
0420 }
0421
0422 [[nodiscard]] inline uint16_t read16le(const void *P) {
0423 return read16<llvm::endianness::little>(P);
0424 }
0425 [[nodiscard]] inline uint32_t read32le(const void *P) {
0426 return read32<llvm::endianness::little>(P);
0427 }
0428 [[nodiscard]] inline uint64_t read64le(const void *P) {
0429 return read64<llvm::endianness::little>(P);
0430 }
0431 [[nodiscard]] inline uint16_t read16be(const void *P) {
0432 return read16<llvm::endianness::big>(P);
0433 }
0434 [[nodiscard]] inline uint32_t read32be(const void *P) {
0435 return read32<llvm::endianness::big>(P);
0436 }
0437 [[nodiscard]] inline uint64_t read64be(const void *P) {
0438 return read64<llvm::endianness::big>(P);
0439 }
0440
0441 template <typename T, endianness E> inline void write(void *P, T V) {
0442 *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
0443 }
0444
0445 inline void write16(void *P, uint16_t V, endianness E) {
0446 write<uint16_t>(P, V, E);
0447 }
0448 inline void write32(void *P, uint32_t V, endianness E) {
0449 write<uint32_t>(P, V, E);
0450 }
0451 inline void write64(void *P, uint64_t V, endianness E) {
0452 write<uint64_t>(P, V, E);
0453 }
0454
0455 template <endianness E> inline void write16(void *P, uint16_t V) {
0456 write<uint16_t, E>(P, V);
0457 }
0458 template <endianness E> inline void write32(void *P, uint32_t V) {
0459 write<uint32_t, E>(P, V);
0460 }
0461 template <endianness E> inline void write64(void *P, uint64_t V) {
0462 write<uint64_t, E>(P, V);
0463 }
0464
0465 inline void write16le(void *P, uint16_t V) {
0466 write16<llvm::endianness::little>(P, V);
0467 }
0468 inline void write32le(void *P, uint32_t V) {
0469 write32<llvm::endianness::little>(P, V);
0470 }
0471 inline void write64le(void *P, uint64_t V) {
0472 write64<llvm::endianness::little>(P, V);
0473 }
0474 inline void write16be(void *P, uint16_t V) {
0475 write16<llvm::endianness::big>(P, V);
0476 }
0477 inline void write32be(void *P, uint32_t V) {
0478 write32<llvm::endianness::big>(P, V);
0479 }
0480 inline void write64be(void *P, uint64_t V) {
0481 write64<llvm::endianness::big>(P, V);
0482 }
0483
0484 }
0485
0486 }
0487 }
0488
0489 #endif