mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-04 11:17:31 +00:00
93269f7395
llvm-svn: 117092
229 lines
7.8 KiB
C++
229 lines
7.8 KiB
C++
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file declares generic functions to read and write endian specific data.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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"
|
|
|
|
namespace llvm {
|
|
namespace support {
|
|
|
|
enum endianness {big, little};
|
|
enum alignment {unaligned, aligned};
|
|
|
|
template<typename value_type, int host, int target>
|
|
static typename enable_if_c<host == target, value_type>::type
|
|
SwapByteOrderIfDifferent(value_type value) {
|
|
// Target endianess is the same as the host. Just pass the value through.
|
|
return value;
|
|
}
|
|
|
|
template<typename value_type, int host, int target>
|
|
static typename enable_if_c<host != target, value_type>::type
|
|
SwapByteOrderIfDifferent(value_type value) {
|
|
return sys::SwapByteOrder<value_type>(value);
|
|
}
|
|
|
|
namespace detail {
|
|
|
|
template<typename value_type, alignment align>
|
|
struct alignment_access_helper;
|
|
|
|
template<typename value_type>
|
|
struct alignment_access_helper<value_type, aligned>
|
|
{
|
|
value_type val;
|
|
};
|
|
|
|
// Provides unaligned loads and stores.
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
template<typename value_type>
|
|
struct alignment_access_helper<value_type, unaligned>
|
|
{
|
|
value_type val;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
} // end namespace detail
|
|
|
|
#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
|
|
|
|
struct endian {
|
|
template<typename value_type, alignment align>
|
|
static value_type read_le(const void *memory) {
|
|
return SwapByteOrderIfDifferent<value_type, host_endianness, little>(
|
|
reinterpret_cast<const detail::alignment_access_helper
|
|
<value_type, align> *>(memory)->val);
|
|
}
|
|
|
|
template<typename value_type, alignment align>
|
|
static void write_le(void *memory, value_type value) {
|
|
reinterpret_cast<detail::alignment_access_helper<value_type, align> *>
|
|
(memory)->val =
|
|
SwapByteOrderIfDifferent< value_type
|
|
, host_endianness
|
|
, little>(value);
|
|
}
|
|
|
|
template<typename value_type, alignment align>
|
|
static value_type read_be(const void *memory) {
|
|
return SwapByteOrderIfDifferent<value_type, host_endianness, big>(
|
|
reinterpret_cast<const detail::alignment_access_helper
|
|
<value_type, align> *>(memory)->val);
|
|
}
|
|
|
|
template<typename value_type, alignment align>
|
|
static void write_be(void *memory, value_type value) {
|
|
reinterpret_cast<detail::alignment_access_helper
|
|
<value_type, align> *>(memory)->val =
|
|
SwapByteOrderIfDifferent< value_type
|
|
, host_endianness
|
|
, big>(value);
|
|
}
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template<typename value_type,
|
|
endianness target_endianness,
|
|
alignment target_alignment>
|
|
class packed_endian_specific_integral;
|
|
|
|
template<typename value_type>
|
|
class packed_endian_specific_integral<value_type, little, unaligned> {
|
|
public:
|
|
operator value_type() const {
|
|
return endian::read_le<value_type, unaligned>(Value);
|
|
}
|
|
private:
|
|
uint8_t Value[sizeof(value_type)];
|
|
};
|
|
|
|
template<typename value_type>
|
|
class packed_endian_specific_integral<value_type, big, unaligned> {
|
|
public:
|
|
operator value_type() const {
|
|
return endian::read_be<value_type, unaligned>(Value);
|
|
}
|
|
private:
|
|
uint8_t Value[sizeof(value_type)];
|
|
};
|
|
|
|
template<typename value_type>
|
|
class packed_endian_specific_integral<value_type, little, aligned> {
|
|
public:
|
|
operator value_type() const {
|
|
return endian::read_le<value_type, aligned>(&Value);
|
|
}
|
|
private:
|
|
value_type Value;
|
|
};
|
|
|
|
template<typename value_type>
|
|
class packed_endian_specific_integral<value_type, big, aligned> {
|
|
public:
|
|
operator value_type() const {
|
|
return endian::read_be<value_type, aligned>(&Value);
|
|
}
|
|
private:
|
|
value_type Value;
|
|
};
|
|
|
|
} // end namespace detail
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint8_t, little, unaligned> ulittle8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint16_t, little, unaligned> ulittle16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint32_t, little, unaligned> ulittle32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint64_t, little, unaligned> ulittle64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<int8_t, little, unaligned> little8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int16_t, little, unaligned> little16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int32_t, little, unaligned> little32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int64_t, little, unaligned> little64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint8_t, little, aligned> aligned_ulittle8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint16_t, little, aligned> aligned_ulittle16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint32_t, little, aligned> aligned_ulittle32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint64_t, little, aligned> aligned_ulittle64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<int8_t, little, aligned> aligned_little8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int16_t, little, aligned> aligned_little16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int32_t, little, aligned> aligned_little32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int64_t, little, aligned> aligned_little64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint8_t, big, unaligned> ubig8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint16_t, big, unaligned> ubig16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint32_t, big, unaligned> ubig32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint64_t, big, unaligned> ubig64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<int8_t, big, unaligned> big8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int16_t, big, unaligned> big16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int32_t, big, unaligned> big32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int64_t, big, unaligned> big64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint8_t, big, aligned> aligned_ubig8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint16_t, big, aligned> aligned_ubig16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint32_t, big, aligned> aligned_ubig32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<uint64_t, big, aligned> aligned_ubig64_t;
|
|
|
|
typedef detail::packed_endian_specific_integral
|
|
<int8_t, big, aligned> aligned_big8_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int16_t, big, aligned> aligned_big16_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int32_t, big, aligned> aligned_big32_t;
|
|
typedef detail::packed_endian_specific_integral
|
|
<int64_t, big, aligned> aligned_big64_t;
|
|
|
|
} // end namespace llvm
|
|
} // end namespace support
|
|
|
|
#endif
|