diff options
-rwxr-xr-x | cmake/config-ix.cmake | 3 | ||||
-rw-r--r-- | include/llvm/Config/config.h.cmake | 3 | ||||
-rw-r--r-- | include/llvm/Support/Endian.h | 228 | ||||
-rw-r--r-- | unittests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | unittests/Support/EndianTest.cpp | 72 |
5 files changed, 308 insertions, 1 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 16c17e2..3355c0d 100755 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -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 ) diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index 26a39b2..01b9460 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -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} diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h new file mode 100644 index 0000000..985c587 --- /dev/null +++ b/include/llvm/Support/Endian.h @@ -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 diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index d37b890..df51bf8 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -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 ) diff --git a/unittests/Support/EndianTest.cpp b/unittests/Support/EndianTest.cpp new file mode 100644 index 0000000..d917293 --- /dev/null +++ b/unittests/Support/EndianTest.cpp @@ -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); +} + +} |