summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael J. Spencer <bigcheesegs@gmail.com>2010-10-21 20:28:21 +0000
committerMichael J. Spencer <bigcheesegs@gmail.com>2010-10-21 20:28:21 +0000
commit5e0b2bf657dd8b6b3bb58439e6cb293f3116687f (patch)
tree8d692616f4fb03bd88385566947ffbd9da0ef6c6
parentd451f888b85d01caa586b0d45bacb41836fd2c31 (diff)
downloadllvm-5e0b2bf657dd8b6b3bb58439e6cb293f3116687f.tar.gz
llvm-5e0b2bf657dd8b6b3bb58439e6cb293f3116687f.tar.bz2
llvm-5e0b2bf657dd8b6b3bb58439e6cb293f3116687f.tar.xz
Support: Add Endian.h
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117057 91177308-0d34-0410-b5e6-96231b3b80d8
-rwxr-xr-xcmake/config-ix.cmake3
-rw-r--r--include/llvm/Config/config.h.cmake3
-rw-r--r--include/llvm/Support/Endian.h228
-rw-r--r--unittests/CMakeLists.txt3
-rw-r--r--unittests/Support/EndianTest.cpp72
5 files changed, 308 insertions, 1 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 16c17e20ec..3355c0d506 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 26a39b224e..01b9460c4e 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 0000000000..985c5870dd
--- /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 d37b8906b4..df51bf821f 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 0000000000..d9172935d6
--- /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);
+}
+
+}