From: Michael J. Spencer Date: Thu, 21 Oct 2010 20:28:21 +0000 (+0000) Subject: Support: Add Endian.h X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=5e0b2bf657dd8b6b3bb58439e6cb293f3116687f;p=oota-llvm.git Support: Add Endian.h git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117057 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 16c17e20ec9..3355c0d5063 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 26a39b224e4..01b9460c4e1 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 00000000000..985c5870dd4 --- /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 +static typename enable_if_c::type +SwapByteOrderIfDifferent(value_type value) { + // Target endianess is the same as the host. Just pass the value through. + return value; +} + +template +static typename enable_if_c::type +SwapByteOrderIfDifferent(value_type value) { + return sys::SwapByteOrder(value); +} + +namespace detail { + +template +struct alignment_access_helper; + +template +struct alignment_access_helper +{ + value_type val; +}; + +// Provides unaligned loads and stores. +#pragma pack(push) +#pragma pack(1) +template +struct alignment_access_helper +{ + 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 + static value_type read_le(const void *memory) { + return SwapByteOrderIfDifferent( + reinterpret_cast *>(memory)->val); + } + + template + static void write_le(void *memory, value_type value) { + reinterpret_cast *> + (memory)->val = + SwapByteOrderIfDifferent< value_type + , host_endianness + , little>(value); + } + + template + static value_type read_be(const void *memory) { + return SwapByteOrderIfDifferent( + reinterpret_cast *>(memory)->val); + } + + template + static void write_be(void *memory, value_type value) { + reinterpret_cast *>(memory)->val = + SwapByteOrderIfDifferent< value_type + , host_endianness + , big>(value); + } +}; + +namespace detail { + +template +class packed_endian_specific_integral; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_le(Value); + } +private: + uint8_t Value[sizeof(value_type)]; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_be(Value); + } +private: + uint8_t Value[sizeof(value_type)]; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_le(&Value); + } +private: + value_type Value; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_be(&Value); + } +private: + value_type Value; +}; + +} // end namespace detail + +typedef detail::packed_endian_specific_integral + ulittle8_t; +typedef detail::packed_endian_specific_integral + ulittle16_t; +typedef detail::packed_endian_specific_integral + ulittle32_t; +typedef detail::packed_endian_specific_integral + ulittle64_t; + +typedef detail::packed_endian_specific_integral + little8_t; +typedef detail::packed_endian_specific_integral + little16_t; +typedef detail::packed_endian_specific_integral + little32_t; +typedef detail::packed_endian_specific_integral + little64_t; + +typedef detail::packed_endian_specific_integral + aligned_ulittle8_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle16_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle32_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle64_t; + +typedef detail::packed_endian_specific_integral + aligned_little8_t; +typedef detail::packed_endian_specific_integral + aligned_little16_t; +typedef detail::packed_endian_specific_integral + aligned_little32_t; +typedef detail::packed_endian_specific_integral + aligned_little64_t; + +typedef detail::packed_endian_specific_integral + ubig8_t; +typedef detail::packed_endian_specific_integral + ubig16_t; +typedef detail::packed_endian_specific_integral + ubig32_t; +typedef detail::packed_endian_specific_integral + ubig64_t; + +typedef detail::packed_endian_specific_integral + big8_t; +typedef detail::packed_endian_specific_integral + big16_t; +typedef detail::packed_endian_specific_integral + big32_t; +typedef detail::packed_endian_specific_integral + big64_t; + +typedef detail::packed_endian_specific_integral + aligned_ubig8_t; +typedef detail::packed_endian_specific_integral + aligned_ubig16_t; +typedef detail::packed_endian_specific_integral + aligned_ubig32_t; +typedef detail::packed_endian_specific_integral + aligned_ubig64_t; + +typedef detail::packed_endian_specific_integral + aligned_big8_t; +typedef detail::packed_endian_specific_integral + aligned_big16_t; +typedef detail::packed_endian_specific_integral + aligned_big32_t; +typedef detail::packed_endian_specific_integral + aligned_big64_t; + +} // end namespace llvm +} // end namespace support + +#endif diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index d37b8906b48..df51bf821f8 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 00000000000..d9172935d66 --- /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 +#include +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(big))); + int32_t LittleAsHost = 0x02030400; + EXPECT_EQ(LittleAsHost, (endian::read_le(little))); + + EXPECT_EQ((endian::read_be(big + 1)), + (endian::read_le(little + 1))); +} + +TEST(Endian, Write) { + unsigned char data[5]; + endian::write_be(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(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(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(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(big + 1); + little32_t *little_val = + reinterpret_cast(little + 1); + + EXPECT_EQ(*big_val, *little_val); +} + +}