Support: Add Endian.h

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117057 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael J. Spencer 2010-10-21 20:28:21 +00:00
parent d451f888b8
commit 5e0b2bf657
5 changed files with 308 additions and 1 deletions

View File

@ -3,6 +3,7 @@ include(CheckLibraryExists)
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckCXXSourceCompiles)
include(TestBigEndian)
if( UNIX AND NOT BEOS )
# Used by check_symbol_exists:
@ -257,6 +258,8 @@ if( LLVM_ENABLE_THREADS )
endif()
endif()
test_big_endian(LLVM_IS_TARGET_BIG_ENDIAN)
if( ENABLE_THREADS )
message(STATUS "Threads enabled.")
else( ENABLE_THREADS )

View File

@ -506,6 +506,9 @@
/* Define if this is Win32ish platform */
#cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32}
/* Define if this is targeting a big endian system */
#cmakedefine LLVM_IS_TARGET_BIG_ENDIAN ${LLVM_IS_TARGET_BIG_ENDIAN}
/* Added by Kevin -- Maximum path length */
#cmakedefine MAXPATHLEN ${MAXPATHLEN}

View File

@ -0,0 +1,228 @@
//===- 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_TARGET_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

View File

@ -92,12 +92,13 @@ add_llvm_unittest(Support
Support/Casting.cpp
Support/CommandLineTest.cpp
Support/ConstantRangeTest.cpp
Support/EndianTest.cpp
Support/LeakDetectorTest.cpp
Support/MathExtrasTest.cpp
Support/raw_ostream_test.cpp
Support/RegexTest.cpp
Support/System.cpp
Support/SwapByteOrderTest.cpp
Support/System.cpp
Support/TypeBuilderTest.cpp
Support/ValueHandleTest.cpp
)

View File

@ -0,0 +1,72 @@
//===- unittests/Support/EndianTest.cpp - Endian.h tests ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
#include "llvm/Support/Endian.h"
#include "llvm/System/DataTypes.h"
#include <cstdlib>
#include <ctime>
using namespace llvm;
using namespace support;
#undef max
namespace {
TEST(Endian, Read) {
// These are 5 bytes so we can be sure at least one of the reads is unaligned.
unsigned char big[] = {0x00, 0x01, 0x02, 0x03, 0x04};
unsigned char little[] = {0x00, 0x04, 0x03, 0x02, 0x01};
int32_t BigAsHost = 0x00010203;
EXPECT_EQ(BigAsHost, (endian::read_be<int32_t, unaligned>(big)));
int32_t LittleAsHost = 0x02030400;
EXPECT_EQ(LittleAsHost, (endian::read_le<int32_t, unaligned>(little)));
EXPECT_EQ((endian::read_be<int32_t, unaligned>(big + 1)),
(endian::read_le<int32_t, unaligned>(little + 1)));
}
TEST(Endian, Write) {
unsigned char data[5];
endian::write_be<int32_t, unaligned>(data, -1362446643);
EXPECT_EQ(data[0], 0xAE);
EXPECT_EQ(data[1], 0xCA);
EXPECT_EQ(data[2], 0xB6);
EXPECT_EQ(data[3], 0xCD);
endian::write_be<int32_t, unaligned>(data + 1, -1362446643);
EXPECT_EQ(data[1], 0xAE);
EXPECT_EQ(data[2], 0xCA);
EXPECT_EQ(data[3], 0xB6);
EXPECT_EQ(data[4], 0xCD);
endian::write_le<int32_t, unaligned>(data, -1362446643);
EXPECT_EQ(data[0], 0xCD);
EXPECT_EQ(data[1], 0xB6);
EXPECT_EQ(data[2], 0xCA);
EXPECT_EQ(data[3], 0xAE);
endian::write_le<int32_t, unaligned>(data + 1, -1362446643);
EXPECT_EQ(data[1], 0xCD);
EXPECT_EQ(data[2], 0xB6);
EXPECT_EQ(data[3], 0xCA);
EXPECT_EQ(data[4], 0xAE);
}
TEST(Endian, PackedEndianSpecificIntegral) {
// These are 5 bytes so we can be sure at least one of the reads is unaligned.
unsigned char big[] = {0x00, 0x01, 0x02, 0x03, 0x04};
unsigned char little[] = {0x00, 0x04, 0x03, 0x02, 0x01};
big32_t *big_val =
reinterpret_cast<big32_t *>(big + 1);
little32_t *little_val =
reinterpret_cast<little32_t *>(little + 1);
EXPECT_EQ(*big_val, *little_val);
}
}