diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt index 9a352267ed195..37ca504b92c17 100644 --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -14,6 +14,7 @@ set(ORC_IMPL_HEADERS # Implementation headers will go here. adt.h compiler.h + endian.h error.h extensible_rtti.h stl_extras.h diff --git a/compiler-rt/lib/orc/endian.h b/compiler-rt/lib/orc/endian.h new file mode 100644 index 0000000000000..4ee5505ce6ddf --- /dev/null +++ b/compiler-rt/lib/orc/endian.h @@ -0,0 +1,143 @@ +//===- endian.h - Endianness support ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares generic and optimized functions to swap the byte order of +// an integral type. +// +//===----------------------------------------------------------------------===// + +#ifndef ORC_RT_ENDIAN_H +#define ORC_RT_ENDIAN_H + +#include +#include +#include +#if defined(_MSC_VER) && !defined(_DEBUG) +#include +#endif + +#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \ + defined(__Fuchsia__) || defined(__EMSCRIPTEN__) +#include +#elif defined(_AIX) +#include +#elif defined(__sun) +/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ +#include +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#if defined(_BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#elif defined(__MVS__) +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#define BYTE_ORDER BIG_ENDIAN +#else +#if !defined(BYTE_ORDER) && !defined(_WIN32) +#include +#endif +#endif + +namespace __orc_rt { + +/// ByteSwap_16 - This function returns a byte-swapped representation of +/// the 16-bit argument. +inline uint16_t ByteSwap_16(uint16_t value) { +#if defined(_MSC_VER) && !defined(_DEBUG) + // The DLL version of the runtime lacks these functions (bug!?), but in a + // release build they're replaced with BSWAP instructions anyway. + return _byteswap_ushort(value); +#else + uint16_t Hi = value << 8; + uint16_t Lo = value >> 8; + return Hi | Lo; +#endif +} + +/// This function returns a byte-swapped representation of the 32-bit argument. +inline uint32_t ByteSwap_32(uint32_t value) { +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) + return __builtin_bswap32(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_ulong(value); +#else + uint32_t Byte0 = value & 0x000000FF; + uint32_t Byte1 = value & 0x0000FF00; + uint32_t Byte2 = value & 0x00FF0000; + uint32_t Byte3 = value & 0xFF000000; + return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); +#endif +} + +/// This function returns a byte-swapped representation of the 64-bit argument. +inline uint64_t ByteSwap_64(uint64_t value) { +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) + return __builtin_bswap64(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_uint64(value); +#else + uint64_t Hi = ByteSwap_32(uint32_t(value)); + uint32_t Lo = ByteSwap_32(uint32_t(value >> 32)); + return (Hi << 32) | Lo; +#endif +} + +#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +constexpr bool IsBigEndianHost = true; +#else +constexpr bool IsBigEndianHost = false; +#endif + +static const bool IsLittleEndianHost = !IsBigEndianHost; + +inline unsigned char getSwappedBytes(unsigned char C) { return C; } +inline signed char getSwappedBytes(signed char C) { return C; } +inline char getSwappedBytes(char C) { return C; } + +inline unsigned short getSwappedBytes(unsigned short C) { + return ByteSwap_16(C); +} +inline signed short getSwappedBytes(signed short C) { return ByteSwap_16(C); } + +inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); } +inline signed int getSwappedBytes(signed int C) { return ByteSwap_32(C); } + +inline unsigned long getSwappedBytes(unsigned long C) { + // Handle LLP64 and LP64 platforms. + return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) + : ByteSwap_64((uint64_t)C); +} +inline signed long getSwappedBytes(signed long C) { + // Handle LLP64 and LP64 platforms. + return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) + : ByteSwap_64((uint64_t)C); +} + +inline unsigned long long getSwappedBytes(unsigned long long C) { + return ByteSwap_64(C); +} +inline signed long long getSwappedBytes(signed long long C) { + return ByteSwap_64(C); +} + +template +inline std::enable_if_t::value, T> getSwappedBytes(T C) { + return static_cast( + getSwappedBytes(static_cast>(C))); +} + +template inline void swapByteOrder(T &Value) { + Value = getSwappedBytes(Value); +} + +} // end namespace __orc_rt + +#endif // ORC_RT_ENDIAN_H diff --git a/compiler-rt/lib/orc/unittests/CMakeLists.txt b/compiler-rt/lib/orc/unittests/CMakeLists.txt index d79a3c9cd8413..6ed0f309d68b1 100644 --- a/compiler-rt/lib/orc/unittests/CMakeLists.txt +++ b/compiler-rt/lib/orc/unittests/CMakeLists.txt @@ -81,6 +81,7 @@ endmacro() set(UNITTEST_SOURCES adt_test.cpp + endian_test.cpp error_test.cpp extensible_rtti_test.cpp orc_unit_test_main.cpp diff --git a/compiler-rt/lib/orc/unittests/endian_test.cpp b/compiler-rt/lib/orc/unittests/endian_test.cpp new file mode 100644 index 0000000000000..176c1fd8691db --- /dev/null +++ b/compiler-rt/lib/orc/unittests/endian_test.cpp @@ -0,0 +1,174 @@ +//===- endian_test.cpp ------------------------- swap byte order test -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of the ORC runtime. +// +// Adapted from the llvm/unittests/Support/SwapByteOrderTest.cpp LLVM unit test. +// +//===----------------------------------------------------------------------===// + +#include "endian.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(Endian, ByteSwap_32) { + EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344)); + EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD)); +} + +TEST(Endian, ByteSwap_64) { + EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL)); + EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL)); +} + +// In these first two tests all of the original_uintx values are truncated +// except for 64. We could avoid this, but there's really no point. +TEST(Endian, getSwappedBytes_UnsignedRoundTrip) { + // The point of the bit twiddling of magic is to test with and without bits + // in every byte. + uint64_t value = 1; + for (std::size_t i = 0; i <= sizeof(value); ++i) { + uint8_t original_uint8 = static_cast(value); + EXPECT_EQ(original_uint8, getSwappedBytes(getSwappedBytes(original_uint8))); + + uint16_t original_uint16 = static_cast(value); + EXPECT_EQ(original_uint16, + getSwappedBytes(getSwappedBytes(original_uint16))); + + uint32_t original_uint32 = static_cast(value); + EXPECT_EQ(original_uint32, + getSwappedBytes(getSwappedBytes(original_uint32))); + + uint64_t original_uint64 = static_cast(value); + EXPECT_EQ(original_uint64, + getSwappedBytes(getSwappedBytes(original_uint64))); + + value = (value << 8) | 0x55; // binary 0101 0101. + } +} + +TEST(Endian, getSwappedBytes_SignedRoundTrip) { + // The point of the bit twiddling of magic is to test with and without bits + // in every byte. + uint64_t value = 1; + for (std::size_t i = 0; i <= sizeof(value); ++i) { + int8_t original_int8 = static_cast(value); + EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8))); + + int16_t original_int16 = static_cast(value); + EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16))); + + int32_t original_int32 = static_cast(value); + EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32))); + + int64_t original_int64 = static_cast(value); + EXPECT_EQ(original_int64, getSwappedBytes(getSwappedBytes(original_int64))); + + // Test other sign. + value *= -1; + + original_int8 = static_cast(value); + EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8))); + + original_int16 = static_cast(value); + EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16))); + + original_int32 = static_cast(value); + EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32))); + + original_int64 = static_cast(value); + EXPECT_EQ(original_int64, getSwappedBytes(getSwappedBytes(original_int64))); + + // Return to normal sign and twiddle. + value *= -1; + value = (value << 8) | 0x55; // binary 0101 0101. + } +} + +TEST(Endian, getSwappedBytes_uint8_t) { + EXPECT_EQ(uint8_t(0x11), getSwappedBytes(uint8_t(0x11))); +} + +TEST(Endian, getSwappedBytes_uint16_t) { + EXPECT_EQ(uint16_t(0x1122), getSwappedBytes(uint16_t(0x2211))); +} + +TEST(Endian, getSwappedBytes_uint32_t) { + EXPECT_EQ(uint32_t(0x11223344), getSwappedBytes(uint32_t(0x44332211))); +} + +TEST(Endian, getSwappedBytes_uint64_t) { + EXPECT_EQ(uint64_t(0x1122334455667788ULL), + getSwappedBytes(uint64_t(0x8877665544332211ULL))); +} + +TEST(Endian, getSwappedBytes_int8_t) { + EXPECT_EQ(int8_t(0x11), getSwappedBytes(int8_t(0x11))); +} + +TEST(Endian, getSwappedBytes_int16_t) { + EXPECT_EQ(int16_t(0x1122), getSwappedBytes(int16_t(0x2211))); +} + +TEST(Endian, getSwappedBytes_int32_t) { + EXPECT_EQ(int32_t(0x11223344), getSwappedBytes(int32_t(0x44332211))); +} + +TEST(Endian, getSwappedBytes_int64_t) { + EXPECT_EQ(int64_t(0x1122334455667788LL), + getSwappedBytes(int64_t(0x8877665544332211LL))); +} + +TEST(Endian, swapByteOrder_uint8_t) { + uint8_t value = 0x11; + swapByteOrder(value); + EXPECT_EQ(uint8_t(0x11), value); +} + +TEST(Endian, swapByteOrder_uint16_t) { + uint16_t value = 0x2211; + swapByteOrder(value); + EXPECT_EQ(uint16_t(0x1122), value); +} + +TEST(Endian, swapByteOrder_uint32_t) { + uint32_t value = 0x44332211; + swapByteOrder(value); + EXPECT_EQ(uint32_t(0x11223344), value); +} + +TEST(Endian, swapByteOrder_uint64_t) { + uint64_t value = 0x8877665544332211ULL; + swapByteOrder(value); + EXPECT_EQ(uint64_t(0x1122334455667788ULL), value); +} + +TEST(Endian, swapByteOrder_int8_t) { + int8_t value = 0x11; + swapByteOrder(value); + EXPECT_EQ(int8_t(0x11), value); +} + +TEST(Endian, swapByteOrder_int16_t) { + int16_t value = 0x2211; + swapByteOrder(value); + EXPECT_EQ(int16_t(0x1122), value); +} + +TEST(Endian, swapByteOrder_int32_t) { + int32_t value = 0x44332211; + swapByteOrder(value); + EXPECT_EQ(int32_t(0x11223344), value); +} + +TEST(Endian, swapByteOrder_int64_t) { + int64_t value = 0x8877665544332211LL; + swapByteOrder(value); + EXPECT_EQ(int64_t(0x1122334455667788LL), value); +}