diff options
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/orc/tests/unit')
15 files changed, 1861 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp new file mode 100644 index 000000000000..6625a590e363 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp @@ -0,0 +1,50 @@ +//===-- adt_test.cpp ------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "adt.h" +#include "gtest/gtest.h" + +#include <sstream> +#include <string> + +using namespace __orc_rt; + +TEST(ADTTest, SpanDefaultConstruction) { + span<int> S; + EXPECT_TRUE(S.empty()) << "Default constructed span not empty"; + EXPECT_EQ(S.size(), 0U) << "Default constructed span size not zero"; + EXPECT_EQ(S.begin(), S.end()) << "Default constructed span begin != end"; +} + +TEST(ADTTest, SpanConstructFromFixedArray) { + int A[] = {1, 2, 3, 4, 5}; + span<int> S(A); + EXPECT_FALSE(S.empty()) << "Span should be non-empty"; + EXPECT_EQ(S.size(), 5U) << "Span has unexpected size"; + EXPECT_EQ(std::distance(S.begin(), S.end()), 5U) + << "Unexpected iterator range size"; + EXPECT_EQ(S.data(), &A[0]) << "Span data has unexpected value"; + for (unsigned I = 0; I != S.size(); ++I) + EXPECT_EQ(S[I], A[I]) << "Unexpected span element value"; +} + +TEST(ADTTest, SpanConstructFromIteratorAndSize) { + int A[] = {1, 2, 3, 4, 5}; + span<int> S(&A[0], 5); + EXPECT_FALSE(S.empty()) << "Span should be non-empty"; + EXPECT_EQ(S.size(), 5U) << "Span has unexpected size"; + EXPECT_EQ(std::distance(S.begin(), S.end()), 5U) + << "Unexpected iterator range size"; + EXPECT_EQ(S.data(), &A[0]) << "Span data has unexpected value"; + for (unsigned I = 0; I != S.size(); ++I) + EXPECT_EQ(S[I], A[I]) << "Unexpected span element value"; +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp new file mode 100644 index 000000000000..4c27d54fb4a9 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp @@ -0,0 +1,143 @@ +//===-- adt_test.cpp ------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "bitmask_enum.h" +#include "gtest/gtest.h" + +#include <sstream> +#include <string> + +using namespace __orc_rt; + +namespace { + +enum Flags { F0 = 0, F1 = 1, F2 = 2, F3 = 4, F4 = 8 }; + +} // namespace + +namespace __orc_rt { +ORC_RT_DECLARE_ENUM_AS_BITMASK(Flags, F4); +} // namespace __orc_rt + +static_assert(is_bitmask_enum<Flags>::value != 0); +static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4); + +namespace { + +static_assert(is_bitmask_enum<Flags>::value != 0); +static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4); + +TEST(BitmaskEnumTest, BitwiseOr) { + Flags f = F1 | F2; + EXPECT_EQ(3, f); + + f = f | F3; + EXPECT_EQ(7, f); +} + +TEST(BitmaskEnumTest, BitwiseOrEquals) { + Flags f = F1; + f |= F3; + EXPECT_EQ(5, f); + + // |= should return a reference to the LHS. + f = F2; + (f |= F3) = F1; + EXPECT_EQ(F1, f); +} + +TEST(BitmaskEnumTest, BitwiseAnd) { + Flags f = static_cast<Flags>(3) & F2; + EXPECT_EQ(F2, f); + + f = (f | F3) & (F1 | F2 | F3); + EXPECT_EQ(6, f); +} + +TEST(BitmaskEnumTest, BitwiseAndEquals) { + Flags f = F1 | F2 | F3; + f &= F1 | F2; + EXPECT_EQ(3, f); + + // &= should return a reference to the LHS. + (f &= F1) = F3; + EXPECT_EQ(F3, f); +} + +TEST(BitmaskEnumTest, BitwiseXor) { + Flags f = (F1 | F2) ^ (F2 | F3); + EXPECT_EQ(5, f); + + f = f ^ F1; + EXPECT_EQ(4, f); +} + +TEST(BitmaskEnumTest, BitwiseXorEquals) { + Flags f = (F1 | F2); + f ^= (F2 | F4); + EXPECT_EQ(9, f); + + // ^= should return a reference to the LHS. + (f ^= F4) = F3; + EXPECT_EQ(F3, f); +} + +TEST(BitmaskEnumTest, ConstantExpression) { + constexpr Flags f1 = ~F1; + constexpr Flags f2 = F1 | F2; + constexpr Flags f3 = F1 & F2; + constexpr Flags f4 = F1 ^ F2; + EXPECT_EQ(f1, ~F1); + EXPECT_EQ(f2, F1 | F2); + EXPECT_EQ(f3, F1 & F2); + EXPECT_EQ(f4, F1 ^ F2); +} + +TEST(BitmaskEnumTest, BitwiseNot) { + Flags f = ~F1; + EXPECT_EQ(14, f); // Largest value for f is 15. + EXPECT_EQ(15, ~F0); +} + +enum class FlagsClass { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 4, + ORC_RT_MARK_AS_BITMASK_ENUM(F3) +}; + +TEST(BitmaskEnumTest, ScopedEnum) { + FlagsClass f = (FlagsClass::F1 & ~FlagsClass::F0) | FlagsClass::F2; + f |= FlagsClass::F3; + EXPECT_EQ(7, static_cast<int>(f)); +} + +struct Container { + enum Flags { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 4, + ORC_RT_MARK_AS_BITMASK_ENUM(F3) + }; + + static Flags getFlags() { + Flags f = F0 | F1; + f |= F2; + return f; + } +}; + +TEST(BitmaskEnumTest, EnumInStruct) { EXPECT_EQ(3, Container::getFlags()); } + +} // namespace diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp new file mode 100644 index 000000000000..497cb937e2af --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp @@ -0,0 +1,200 @@ +//===-- c_api_test.cpp ----------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "orc_rt/c_api.h" +#include "gtest/gtest.h" + +TEST(CAPITest, CWrapperFunctionResultInit) { + orc_rt_CWrapperFunctionResult R; + orc_rt_CWrapperFunctionResultInit(&R); + + EXPECT_EQ(R.Size, 0U); + EXPECT_EQ(R.Data.ValuePtr, nullptr); + + // Check that this value isn't treated as an out-of-band error. + EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr); + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultAllocSmall) { + constexpr size_t SmallAllocSize = sizeof(const char *); + + auto R = orc_rt_CWrapperFunctionResultAllocate(SmallAllocSize); + char *DataPtr = orc_rt_CWrapperFunctionResultData(&R); + + for (size_t I = 0; I != SmallAllocSize; ++I) + DataPtr[I] = 0x55 + I; + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, SmallAllocSize); + for (size_t I = 0; I != SmallAllocSize; ++I) + EXPECT_EQ(R.Data.Value[I], (char)(0x55 + I)) + << "Unexpected value at index " << I; + + // Check that this value isn't treated as an out-of-band error. + EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr); + + // Check that orc_rt_CWrapperFunctionResult(Data|Result|Size) and + // orc_rt_CWrapperFunctionResultGetOutOfBandError behave as expected. + EXPECT_EQ(orc_rt_CWrapperFunctionResultData(&R), R.Data.Value); + EXPECT_EQ(orc_rt_CWrapperFunctionResultSize(&R), SmallAllocSize); + EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R)); + EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr); + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultAllocLarge) { + constexpr size_t LargeAllocSize = sizeof(const char *) + 1; + + auto R = orc_rt_CWrapperFunctionResultAllocate(LargeAllocSize); + char *DataPtr = orc_rt_CWrapperFunctionResultData(&R); + + for (size_t I = 0; I != LargeAllocSize; ++I) + DataPtr[I] = 0x55 + I; + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, LargeAllocSize); + EXPECT_EQ(R.Data.ValuePtr, DataPtr); + for (size_t I = 0; I != LargeAllocSize; ++I) + EXPECT_EQ(R.Data.ValuePtr[I], (char)(0x55 + I)) + << "Unexpected value at index " << I; + + // Check that this value isn't treated as an out-of-band error. + EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr); + + // Check that orc_rt_CWrapperFunctionResult(Data|Result|Size) and + // orc_rt_CWrapperFunctionResultGetOutOfBandError behave as expected. + EXPECT_EQ(orc_rt_CWrapperFunctionResultData(&R), R.Data.ValuePtr); + EXPECT_EQ(orc_rt_CWrapperFunctionResultSize(&R), LargeAllocSize); + EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R)); + EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr); + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultFromRangeSmall) { + constexpr size_t SmallAllocSize = sizeof(const char *); + + char Source[SmallAllocSize]; + for (size_t I = 0; I != SmallAllocSize; ++I) + Source[I] = 0x55 + I; + + orc_rt_CWrapperFunctionResult R = + orc_rt_CreateCWrapperFunctionResultFromRange(Source, SmallAllocSize); + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, SmallAllocSize); + for (size_t I = 0; I != SmallAllocSize; ++I) + EXPECT_EQ(R.Data.Value[I], (char)(0x55 + I)) + << "Unexpected value at index " << I; + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultFromRangeLarge) { + constexpr size_t LargeAllocSize = sizeof(const char *) + 1; + + char Source[LargeAllocSize]; + for (size_t I = 0; I != LargeAllocSize; ++I) + Source[I] = 0x55 + I; + + orc_rt_CWrapperFunctionResult R = + orc_rt_CreateCWrapperFunctionResultFromRange(Source, LargeAllocSize); + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, LargeAllocSize); + for (size_t I = 0; I != LargeAllocSize; ++I) + EXPECT_EQ(R.Data.ValuePtr[I], (char)(0x55 + I)) + << "Unexpected value at index " << I; + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultFromStringSmall) { + constexpr size_t SmallAllocSize = sizeof(const char *); + + char Source[SmallAllocSize]; + for (size_t I = 0; I != SmallAllocSize - 1; ++I) + Source[I] = 'a' + I; + Source[SmallAllocSize - 1] = '\0'; + + orc_rt_CWrapperFunctionResult R = + orc_rt_CreateCWrapperFunctionResultFromString(Source); + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, SmallAllocSize); + for (size_t I = 0; I != SmallAllocSize - 1; ++I) + EXPECT_EQ(R.Data.Value[I], (char)('a' + I)) + << "Unexpected value at index " << I; + EXPECT_EQ(R.Data.Value[SmallAllocSize - 1], '\0') + << "Unexpected value at index " << (SmallAllocSize - 1); + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultFromStringLarge) { + constexpr size_t LargeAllocSize = sizeof(const char *) + 1; + + char Source[LargeAllocSize]; + for (size_t I = 0; I != LargeAllocSize - 1; ++I) + Source[I] = 'a' + I; + Source[LargeAllocSize - 1] = '\0'; + + orc_rt_CWrapperFunctionResult R = + orc_rt_CreateCWrapperFunctionResultFromString(Source); + + // Check that the inline storage in R.Data.Value contains the expected + // sequence. + EXPECT_EQ(R.Size, LargeAllocSize); + for (size_t I = 0; I != LargeAllocSize - 1; ++I) + EXPECT_EQ(R.Data.ValuePtr[I], (char)('a' + I)) + << "Unexpected value at index " << I; + EXPECT_EQ(R.Data.ValuePtr[LargeAllocSize - 1], '\0') + << "Unexpected value at index " << (LargeAllocSize - 1); + + // Check that we can dispose of the value. + orc_rt_DisposeCWrapperFunctionResult(&R); +} + +TEST(CAPITest, CWrapperFunctionResultFromOutOfBandError) { + constexpr const char *ErrMsg = "test error message"; + orc_rt_CWrapperFunctionResult R = + orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(ErrMsg); + +#ifndef NDEBUG + EXPECT_DEATH({ orc_rt_CWrapperFunctionResultData(&R); }, + "Cannot get data for out-of-band error value"); + EXPECT_DEATH({ orc_rt_CWrapperFunctionResultSize(&R); }, + "Cannot get size for out-of-band error value"); +#endif + + EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R)); + const char *OOBErrMsg = orc_rt_CWrapperFunctionResultGetOutOfBandError(&R); + EXPECT_NE(OOBErrMsg, nullptr); + EXPECT_NE(OOBErrMsg, ErrMsg); + EXPECT_TRUE(strcmp(OOBErrMsg, ErrMsg) == 0); + + orc_rt_DisposeCWrapperFunctionResult(&R); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp new file mode 100644 index 000000000000..71b677af694c --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/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 "endianness.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<uint8_t>(value); + EXPECT_EQ(original_uint8, getSwappedBytes(getSwappedBytes(original_uint8))); + + uint16_t original_uint16 = static_cast<uint16_t>(value); + EXPECT_EQ(original_uint16, + getSwappedBytes(getSwappedBytes(original_uint16))); + + uint32_t original_uint32 = static_cast<uint32_t>(value); + EXPECT_EQ(original_uint32, + getSwappedBytes(getSwappedBytes(original_uint32))); + + uint64_t original_uint64 = static_cast<uint64_t>(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<int8_t>(value); + EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8))); + + int16_t original_int16 = static_cast<int16_t>(value); + EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16))); + + int32_t original_int32 = static_cast<int32_t>(value); + EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32))); + + int64_t original_int64 = static_cast<int64_t>(value); + EXPECT_EQ(original_int64, getSwappedBytes(getSwappedBytes(original_int64))); + + // Test other sign. + value *= -1; + + original_int8 = static_cast<int8_t>(value); + EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8))); + + original_int16 = static_cast<int16_t>(value); + EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16))); + + original_int32 = static_cast<int32_t>(value); + EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32))); + + original_int64 = static_cast<int64_t>(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); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp new file mode 100644 index 000000000000..5251d788e01b --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp @@ -0,0 +1,295 @@ +//===-- error_test.cpp --sssssssss-----------------------------------------===// +// +// 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. +// +// Note: +// This unit test was adapted from +// llvm/unittests/Support/ExtensibleRTTITest.cpp +// +//===----------------------------------------------------------------------===// + +#include "error.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +namespace { + +class CustomError : public RTTIExtends<CustomError, ErrorInfoBase> { +public: + CustomError(int V1) : V1(V1) {} + std::string toString() const override { + return "CustomError V1 = " + std::to_string(V1); + } + int getV1() const { return V1; } + +protected: + int V1; +}; + +class CustomSubError : public RTTIExtends<CustomSubError, CustomError> { +public: + CustomSubError(int V1, std::string V2) + : RTTIExtends<CustomSubError, CustomError>(V1), V2(std::move(V2)) {} + std::string toString() const override { + return "CustomSubError V1 = " + std::to_string(V1) + ", " + V2; + } + const std::string &getV2() const { return V2; } + +protected: + std::string V2; +}; + +} // end anonymous namespace + +// Test that a checked success value doesn't cause any issues. +TEST(Error, CheckedSuccess) { + Error E = Error::success(); + EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; +} + +// Check that a consumed success value doesn't cause any issues. +TEST(Error, ConsumeSuccess) { consumeError(Error::success()); } + +TEST(Error, ConsumeError) { + Error E = make_error<CustomError>(42); + if (E) { + consumeError(std::move(E)); + } else + ADD_FAILURE() << "Error failure value should convert to true"; +} + +// Test that unchecked success values cause an abort. +TEST(Error, UncheckedSuccess) { + EXPECT_DEATH({ Error E = Error::success(); }, + "Error must be checked prior to destruction") + << "Unchecked Error Succes value did not cause abort()"; +} + +// Test that a checked but unhandled error causes an abort. +TEST(Error, CheckedButUnhandledError) { + auto DropUnhandledError = []() { + Error E = make_error<CustomError>(42); + (void)!E; + }; + EXPECT_DEATH(DropUnhandledError(), + "Error must be checked prior to destruction") + << "Unhandled Error failure value did not cause an abort()"; +} + +// Test that error_cast works as expected. +TEST(Error, BasicErrorCast) { + { + // Check casting base error value to base error type. + auto E = make_error<CustomError>(42); + if (auto CSE = error_cast<CustomSubError>(E)) { + ADD_FAILURE() << "Derived cast incorrectly matched base error"; + } else if (auto CE = error_cast<CustomError>(E)) { + EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; + } else + ADD_FAILURE() << "Unexpected error value"; + } + + { + // Check casting derived error value to base error type. + auto E = make_error<CustomSubError>(42, "foo"); + if (auto CE = error_cast<CustomError>(E)) { + EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; + } else + ADD_FAILURE() << "Unexpected error value"; + } + + { + // Check casting derived error value to derived error type. + auto E = make_error<CustomSubError>(42, "foo"); + if (auto CSE = error_cast<CustomSubError>(E)) { + EXPECT_EQ(CSE->getV1(), 42) << "Unexpected wrapped value"; + EXPECT_EQ(CSE->getV2(), "foo") << "Unexpected wrapped value"; + } else + ADD_FAILURE() << "Unexpected error value"; + } +} + +// ErrorAsOutParameter tester. +static void errAsOutParamHelper(Error &Err) { + ErrorAsOutParameter ErrAsOutParam(&Err); + // Verify that checked flag is raised - assignment should not crash. + Err = Error::success(); + // Raise the checked bit manually - caller should still have to test the + // error. + (void)!!Err; +} + +// Test that ErrorAsOutParameter sets the checked flag on construction. +TEST(Error, ErrorAsOutParameterChecked) { + Error E = Error::success(); + errAsOutParamHelper(E); + (void)!!E; +} + +// Test that ErrorAsOutParameter clears the checked flag on destruction. +TEST(Error, ErrorAsOutParameterUnchecked) { + EXPECT_DEATH( + { + Error E = Error::success(); + errAsOutParamHelper(E); + }, + "Error must be checked prior to destruction") + << "ErrorAsOutParameter did not clear the checked flag on destruction."; +} + +// Check 'Error::isA<T>' method handling. +TEST(Error, IsAHandling) { + // Check 'isA' handling. + Error E = make_error<CustomError>(42); + Error F = make_error<CustomSubError>(42, "foo"); + Error G = Error::success(); + + EXPECT_TRUE(E.isA<CustomError>()); + EXPECT_FALSE(E.isA<CustomSubError>()); + EXPECT_TRUE(F.isA<CustomError>()); + EXPECT_TRUE(F.isA<CustomSubError>()); + EXPECT_FALSE(G.isA<CustomError>()); + + consumeError(std::move(E)); + consumeError(std::move(F)); + consumeError(std::move(G)); +} + +TEST(Error, StringError) { + auto E = make_error<StringError>("foo"); + if (auto SE = error_cast<StringError>(E)) { + EXPECT_EQ(SE->toString(), "foo") << "Unexpected StringError value"; + } else + ADD_FAILURE() << "Expected StringError value"; +} + +// Test Checked Expected<T> in success mode. +TEST(Error, CheckedExpectedInSuccessMode) { + Expected<int> A = 7; + EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; + // Access is safe in second test, since we checked the error in the first. + EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; +} + +// Test Expected with reference type. +TEST(Error, ExpectedWithReferenceType) { + int A = 7; + Expected<int &> B = A; + // 'Check' B. + (void)!!B; + int &C = *B; + EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; +} + +// Test Unchecked Expected<T> in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +TEST(Error, UncheckedExpectedInSuccessModeDestruction) { + EXPECT_DEATH({ Expected<int> A = 7; }, + "Expected<T> must be checked before access or destruction.") + << "Unchecekd Expected<T> success value did not cause an abort()."; +} + +// Test Unchecked Expected<T> in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +TEST(Error, UncheckedExpectedInSuccessModeAccess) { + EXPECT_DEATH( + { + Expected<int> A = 7; + *A; + }, + "Expected<T> must be checked before access or destruction.") + << "Unchecekd Expected<T> success value did not cause an abort()."; +} + +// Test Unchecked Expected<T> in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +TEST(Error, UncheckedExpectedInSuccessModeAssignment) { + EXPECT_DEATH( + { + Expected<int> A = 7; + A = 7; + }, + "Expected<T> must be checked before access or destruction.") + << "Unchecekd Expected<T> success value did not cause an abort()."; +} + +// Test Expected<T> in failure mode. +TEST(Error, ExpectedInFailureMode) { + Expected<int> A = make_error<CustomError>(42); + EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; + Error E = A.takeError(); + EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; + consumeError(std::move(E)); +} + +// Check that an Expected instance with an error value doesn't allow access to +// operator*. +// Test runs in debug mode only. +TEST(Error, AccessExpectedInFailureMode) { + Expected<int> A = make_error<CustomError>(42); + EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.") + << "Incorrect Expected error value"; + consumeError(A.takeError()); +} + +// Check that an Expected instance with an error triggers an abort if +// unhandled. +// Test runs in debug mode only. +TEST(Error, UnhandledExpectedInFailureMode) { + EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, + "Expected<T> must be checked before access or destruction.") + << "Unchecked Expected<T> failure value did not cause an abort()"; +} + +// Test covariance of Expected. +TEST(Error, ExpectedCovariance) { + class B {}; + class D : public B {}; + + Expected<B *> A1(Expected<D *>(nullptr)); + // Check A1 by converting to bool before assigning to it. + (void)!!A1; + A1 = Expected<D *>(nullptr); + // Check A1 again before destruction. + (void)!!A1; + + Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); + // Check A2 by converting to bool before assigning to it. + (void)!!A2; + A2 = Expected<std::unique_ptr<D>>(nullptr); + // Check A2 again before destruction. + (void)!!A2; +} + +// Test that the ExitOnError utility works as expected. +TEST(Error, CantFailSuccess) { + cantFail(Error::success()); + + int X = cantFail(Expected<int>(42)); + EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; + + int Dummy = 42; + int &Y = cantFail(Expected<int &>(Dummy)); + EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail"; +} + +// Test that cantFail results in a crash if you pass it a failure value. +TEST(Error, CantFailDeath) { + EXPECT_DEATH(cantFail(make_error<StringError>("foo")), + "cantFail called on failure value") + << "cantFail(Error) did not cause an abort for failure value"; + + EXPECT_DEATH(cantFail(Expected<int>(make_error<StringError>("foo"))), + "cantFail called on failure value") + << "cantFail(Expected<int>) did not cause an abort for failure value"; +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp new file mode 100644 index 000000000000..05b91f3f8609 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp @@ -0,0 +1,115 @@ +//===-- executor_address_test.cpp -----------------------------------------===// +// +// 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. +// +// Note: +// This unit test was adapted from +// llvm/unittests/Support/ExecutorAddressTest.cpp +// +//===----------------------------------------------------------------------===// + +#include "executor_address.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(ExecutorAddrTest, DefaultAndNull) { + // Check that default constructed values and isNull behave as expected. + + ExecutorAddr Default; + ExecutorAddr Null(0); + ExecutorAddr NonNull(1); + + EXPECT_TRUE(Null.isNull()); + EXPECT_EQ(Default, Null); + + EXPECT_FALSE(NonNull.isNull()); + EXPECT_NE(Default, NonNull); +} + +TEST(ExecutorAddrTest, Ordering) { + // Check that ordering operations. + ExecutorAddr A1(1), A2(2); + + EXPECT_LE(A1, A1); + EXPECT_LT(A1, A2); + EXPECT_GT(A2, A1); + EXPECT_GE(A2, A2); +} + +TEST(ExecutorAddrTest, PtrConversion) { + // Test toPtr / fromPtr round-tripping. + int X = 0; + auto XAddr = ExecutorAddr::fromPtr(&X); + int *XPtr = XAddr.toPtr<int *>(); + + EXPECT_EQ(XPtr, &X); +} + +static void F() {} + +TEST(ExecutorAddrTest, PtrConversionWithFunctionType) { + // Test that function types (as opposed to function pointer types) can be + // used with toPtr. + auto FAddr = ExecutorAddr::fromPtr(F); + void (*FPtr)() = FAddr.toPtr<void()>(); + + EXPECT_EQ(FPtr, &F); +} + +TEST(ExecutorAddrTest, WrappingAndUnwrapping) { + constexpr uintptr_t RawAddr = 0x123456; + int *RawPtr = (int *)RawAddr; + + constexpr uintptr_t TagOffset = 8 * (sizeof(uintptr_t) - 1); + uintptr_t TagVal = 0xA5; + uintptr_t TagBits = TagVal << TagOffset; + void *TaggedPtr = (void *)((uintptr_t)RawPtr | TagBits); + + ExecutorAddr EA = + ExecutorAddr::fromPtr(TaggedPtr, ExecutorAddr::Untag(8, TagOffset)); + + EXPECT_EQ(EA.getValue(), RawAddr); + + void *ReconstitutedTaggedPtr = + EA.toPtr<void *>(ExecutorAddr::Tag(TagVal, TagOffset)); + + EXPECT_EQ(TaggedPtr, ReconstitutedTaggedPtr); +} + +TEST(ExecutorAddrTest, AddrRanges) { + ExecutorAddr A0(0), A1(1), A2(2), A3(3); + ExecutorAddrRange R0(A0, A1), R1(A1, A2), R2(A2, A3), R3(A0, A2), R4(A1, A3); + // 012 + // R0: # -- Before R1 + // R1: # -- + // R2: # -- After R1 + // R3: ## -- Overlaps R1 start + // R4: ## -- Overlaps R1 end + + EXPECT_EQ(R1, ExecutorAddrRange(A1, A2)); + EXPECT_EQ(R1, ExecutorAddrRange(A1, ExecutorAddrDiff(1))); + EXPECT_NE(R1, R2); + + EXPECT_TRUE(R1.contains(A1)); + EXPECT_FALSE(R1.contains(A0)); + EXPECT_FALSE(R1.contains(A2)); + + EXPECT_FALSE(R1.overlaps(R0)); + EXPECT_FALSE(R1.overlaps(R2)); + EXPECT_TRUE(R1.overlaps(R3)); + EXPECT_TRUE(R1.overlaps(R4)); +} + +TEST(ExecutorAddrTest, Hashable) { + uint64_t RawAddr = 0x1234567890ABCDEF; + ExecutorAddr Addr(RawAddr); + + EXPECT_EQ(std::hash<uint64_t>()(RawAddr), std::hash<ExecutorAddr>()(Addr)); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp new file mode 100644 index 000000000000..181091ca1e60 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp @@ -0,0 +1,19 @@ +//===-- executor_symbol_def_test.cpp --------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "executor_symbol_def.h" +#include "simple_packed_serialization_utils.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(ExecutorSymbolDefTest, Serialization) { + blobSerializationRoundTrip<SPSExecutorSymbolDef>(ExecutorSymbolDef{}); + blobSerializationRoundTrip<SPSExecutorSymbolDef>( + ExecutorSymbolDef{ExecutorAddr{0x70}, {JITSymbolFlags::Callable, 9}}); +}
\ No newline at end of file diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp new file mode 100644 index 000000000000..feca1ec1d18c --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp @@ -0,0 +1,54 @@ +//===-- extensible_rtti_test.cpp ------------------------------------------===// +// +// 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. +// +// Note: +// This unit test was adapted from +// llvm/unittests/Support/ExtensibleRTTITest.cpp +// +//===----------------------------------------------------------------------===// + +#include "extensible_rtti.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +namespace { + +class MyBase : public RTTIExtends<MyBase, RTTIRoot> {}; + +class MyDerivedA : public RTTIExtends<MyDerivedA, MyBase> {}; + +class MyDerivedB : public RTTIExtends<MyDerivedB, MyBase> {}; + +} // end anonymous namespace + +TEST(ExtensibleRTTITest, BaseCheck) { + MyBase MB; + MyDerivedA MDA; + MyDerivedB MDB; + + // Check MB properties. + EXPECT_TRUE(isa<RTTIRoot>(MB)); + EXPECT_TRUE(isa<MyBase>(MB)); + EXPECT_FALSE(isa<MyDerivedA>(MB)); + EXPECT_FALSE(isa<MyDerivedB>(MB)); + + // Check MDA properties. + EXPECT_TRUE(isa<RTTIRoot>(MDA)); + EXPECT_TRUE(isa<MyBase>(MDA)); + EXPECT_TRUE(isa<MyDerivedA>(MDA)); + EXPECT_FALSE(isa<MyDerivedB>(MDA)); + + // Check MDB properties. + EXPECT_TRUE(isa<RTTIRoot>(MDB)); + EXPECT_TRUE(isa<MyBase>(MDB)); + EXPECT_FALSE(isa<MyDerivedA>(MDB)); + EXPECT_TRUE(isa<MyDerivedB>(MDB)); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp new file mode 100644 index 000000000000..a1c6958fcd52 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp @@ -0,0 +1,204 @@ +//===-- interval_map_test.cpp ---------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "interval_map.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(IntervalMapTest, DefaultConstructed) { + // Check that a default-constructed IntervalMap behaves as expected. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + EXPECT_TRUE(M.empty()); + EXPECT_TRUE(M.begin() == M.end()); + EXPECT_TRUE(M.find(0) == M.end()); +} + +TEST(IntervalMapTest, InsertSingleElement) { + // Check that a map with a single element inserted behaves as expected. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + M.insert(7, 8, 42); + + EXPECT_FALSE(M.empty()); + EXPECT_EQ(std::next(M.begin()), M.end()); + EXPECT_EQ(M.find(7), M.begin()); + EXPECT_EQ(M.find(8), M.end()); + EXPECT_EQ(M.lookup(7), 42U); + EXPECT_EQ(M.lookup(8), 0U); // 8 not present, so should return unsigned(). +} + +TEST(IntervalMapTest, InsertCoalesceWithPrevious) { + // Check that insertions coalesce with previous ranges that share the same + // value. Also check that they _don't_ coalesce if the values are different. + + // Check that insertion coalesces with previous range when values are equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1; + + M1.insert(7, 8, 42); + M1.insert(8, 9, 42); + + EXPECT_FALSE(M1.empty()); + EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range. + EXPECT_EQ(M1.find(7), M1.find(8)); // 7 and 8 should point to same range. + EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved. + + // Check that insertion does not coalesce with previous range when values are + // not equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2; + + M2.insert(7, 8, 42); + M2.insert(8, 9, 7); + + EXPECT_FALSE(M2.empty()); + EXPECT_EQ(std::next(std::next(M2.begin())), M2.end()); // Expect two ranges. + EXPECT_NE(M2.find(7), M2.find(8)); // 7 and 8 should be different ranges. + EXPECT_EQ(M2.lookup(7), 42U); // Keys 7 and 8 should map to different values. + EXPECT_EQ(M2.lookup(8), 7U); +} + +TEST(IntervalMapTest, InsertCoalesceWithFollowing) { + // Check that insertions coalesce with following ranges that share the same + // value. Also check that they _don't_ coalesce if the values are different. + + // Check that insertion coalesces with following range when values are equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1; + + M1.insert(8, 9, 42); + M1.insert(7, 8, 42); + + EXPECT_FALSE(M1.empty()); + EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range. + EXPECT_EQ(M1.find(7), M1.find(8)); // 7 and 8 should point to same range. + EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved. + + // Check that insertion does not coalesce with previous range when values are + // not equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2; + + M2.insert(8, 9, 42); + M2.insert(7, 8, 7); + + EXPECT_FALSE(M2.empty()); + EXPECT_EQ(std::next(std::next(M2.begin())), M2.end()); // Expect two ranges. + EXPECT_EQ(M2.lookup(7), 7U); // Keys 7 and 8 should map to different values. + EXPECT_EQ(M2.lookup(8), 42U); +} + +TEST(IntervalMapTest, InsertCoalesceBoth) { + // Check that insertions coalesce with ranges on both sides where posssible. + // Also check that they _don't_ coalesce if the values are different. + + // Check that insertion coalesces with both previous and following ranges + // when values are equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1; + + M1.insert(7, 8, 42); + M1.insert(9, 10, 42); + + // Check no coalescing yet. + EXPECT_NE(M1.find(7), M1.find(9)); + + // Insert a 3rd range to trigger coalescing on both sides. + M1.insert(8, 9, 42); + + EXPECT_FALSE(M1.empty()); + EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range. + EXPECT_EQ(M1.find(7), M1.find(8)); // 7, 8, and 9 should point to same range. + EXPECT_EQ(M1.find(8), M1.find(9)); + EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved. + + // Check that insertion does not coalesce with previous range when values are + // not equal. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2; + + M2.insert(7, 8, 42); + M2.insert(8, 9, 7); + M2.insert(9, 10, 42); + + EXPECT_FALSE(M2.empty()); + // Expect three ranges. + EXPECT_EQ(std::next(std::next(std::next(M2.begin()))), M2.end()); + EXPECT_NE(M2.find(7), M2.find(8)); // All keys should map to different ranges. + EXPECT_NE(M2.find(8), M2.find(9)); + EXPECT_EQ(M2.lookup(7), 42U); // Key 7, 8, and 9 should map to different vals. + EXPECT_EQ(M2.lookup(8), 7U); + EXPECT_EQ(M2.lookup(9), 42U); +} + +TEST(IntervalMapTest, EraseSingleElement) { + // Check that we can insert and then remove a single range. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + M.insert(7, 10, 42); + EXPECT_FALSE(M.empty()); + M.erase(7, 10); + EXPECT_TRUE(M.empty()); +} + +TEST(IntervalMapTest, EraseSplittingLeft) { + // Check that removal of a trailing subrange succeeds, but leaves the + // residual range in-place. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + M.insert(7, 10, 42); + EXPECT_FALSE(M.empty()); + M.erase(9, 10); + EXPECT_EQ(std::next(M.begin()), M.end()); + EXPECT_EQ(M.begin()->first.first, 7U); + EXPECT_EQ(M.begin()->first.second, 9U); +} + +TEST(IntervalMapTest, EraseSplittingRight) { + // Check that removal of a leading subrange succeeds, but leaves the + // residual range in-place. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + M.insert(7, 10, 42); + EXPECT_FALSE(M.empty()); + M.erase(7, 8); + EXPECT_EQ(std::next(M.begin()), M.end()); + EXPECT_EQ(M.begin()->first.first, 8U); + EXPECT_EQ(M.begin()->first.second, 10U); +} + +TEST(IntervalMapTest, EraseSplittingBoth) { + // Check that removal of an interior subrange leaves both the leading and + // trailing residual subranges in-place. + IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M; + + M.insert(7, 10, 42); + EXPECT_FALSE(M.empty()); + M.erase(8, 9); + EXPECT_EQ(std::next(std::next(M.begin())), M.end()); + EXPECT_EQ(M.begin()->first.first, 7U); + EXPECT_EQ(M.begin()->first.second, 8U); + EXPECT_EQ(std::next(M.begin())->first.first, 9U); + EXPECT_EQ(std::next(M.begin())->first.second, 10U); +} + +TEST(IntervalMapTest, NonCoalescingMapPermitsNonComparableKeys) { + // Test that values that can't be equality-compared are still usable when + // coalescing is disabled and behave as expected. + + struct S {}; // Struct with no equality comparison. + + IntervalMap<unsigned, S, IntervalCoalescing::Disabled> M; + + M.insert(7, 8, S()); + + EXPECT_FALSE(M.empty()); + EXPECT_EQ(std::next(M.begin()), M.end()); + EXPECT_EQ(M.find(7), M.begin()); + EXPECT_EQ(M.find(8), M.end()); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp new file mode 100644 index 000000000000..7971a55f271f --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp @@ -0,0 +1,121 @@ +//===-- interval_set_test.cpp ---------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "interval_set.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(IntervalSetTest, DefaultConstructed) { + // Check that a default-constructed IntervalSet behaves as expected. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + EXPECT_TRUE(S.empty()); + EXPECT_TRUE(S.begin() == S.end()); + EXPECT_TRUE(S.find(0) == S.end()); +} + +TEST(IntervalSetTest, InsertSingleElement) { + // Check that a set with a single element inserted behaves as expected. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 8); + + EXPECT_FALSE(S.empty()); + EXPECT_EQ(std::next(S.begin()), S.end()); + EXPECT_EQ(S.find(7), S.begin()); + EXPECT_EQ(S.find(8), S.end()); +} + +TEST(IntervalSetTest, InsertCoalesceWithPrevious) { + // Check that insertions coalesce with previous ranges. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 8); + S.insert(8, 9); + + EXPECT_FALSE(S.empty()); + EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range. + EXPECT_EQ(S.find(7), S.find(8)); // 7 and 8 should point to same range. +} + +TEST(IntervalSetTest, InsertCoalesceWithFollowing) { + // Check that insertions coalesce with following ranges. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(8, 9); + S.insert(7, 8); + + EXPECT_FALSE(S.empty()); + EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range. + EXPECT_EQ(S.find(7), S.find(8)); // 7 and 8 should point to same range. +} + +TEST(IntervalSetTest, InsertCoalesceBoth) { + // Check that insertions coalesce with ranges on both sides. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 8); + S.insert(9, 10); + + // Check no coalescing yet. + EXPECT_NE(S.find(7), S.find(9)); + + // Insert a 3rd range to trigger coalescing on both sides. + S.insert(8, 9); + + EXPECT_FALSE(S.empty()); + EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range. + EXPECT_EQ(S.find(7), S.find(8)); // 7, 8, and 9 should point to same range. + EXPECT_EQ(S.find(8), S.find(9)); +} + +TEST(IntervalSetTest, EraseSplittingLeft) { + // Check that removal of a trailing subrange succeeds, but leaves the + // residual range in-place. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 10); + EXPECT_FALSE(S.empty()); + S.erase(9, 10); + EXPECT_EQ(std::next(S.begin()), S.end()); + EXPECT_EQ(S.begin()->first, 7U); + EXPECT_EQ(S.begin()->second, 9U); +} + +TEST(IntervalSetTest, EraseSplittingRight) { + // Check that removal of a leading subrange succeeds, but leaves the + // residual range in-place. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 10); + EXPECT_FALSE(S.empty()); + S.erase(7, 8); + EXPECT_EQ(std::next(S.begin()), S.end()); + EXPECT_EQ(S.begin()->first, 8U); + EXPECT_EQ(S.begin()->second, 10U); +} + +TEST(IntervalSetTest, EraseSplittingBoth) { + // Check that removal of an interior subrange leaves both the leading and + // trailing residual subranges in-place. + IntervalSet<unsigned, IntervalCoalescing::Enabled> S; + + S.insert(7, 10); + EXPECT_FALSE(S.empty()); + S.erase(8, 9); + EXPECT_EQ(std::next(std::next(S.begin())), S.end()); + EXPECT_EQ(S.begin()->first, 7U); + EXPECT_EQ(S.begin()->second, 8U); + EXPECT_EQ(std::next(S.begin())->first, 9U); + EXPECT_EQ(std::next(S.begin())->second, 10U); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp new file mode 100644 index 000000000000..d02101704d65 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp @@ -0,0 +1,18 @@ +//===-- orc_unit_test_main.cpp --------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp new file mode 100644 index 000000000000..397114b4017e --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp @@ -0,0 +1,184 @@ +//===-- simple_packed_serialization_test.cpp ------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "simple_packed_serialization.h" +#include "simple_packed_serialization_utils.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +TEST(SimplePackedSerializationTest, SPSOutputBuffer) { + constexpr unsigned NumBytes = 8; + char Buffer[NumBytes]; + char Zero = 0; + SPSOutputBuffer OB(Buffer, NumBytes); + + // Expect that we can write NumBytes of content. + for (unsigned I = 0; I != NumBytes; ++I) { + char C = I; + EXPECT_TRUE(OB.write(&C, 1)); + } + + // Expect an error when we attempt to write an extra byte. + EXPECT_FALSE(OB.write(&Zero, 1)); + + // Check that the buffer contains the expected content. + for (unsigned I = 0; I != NumBytes; ++I) + EXPECT_EQ(Buffer[I], (char)I); +} + +TEST(SimplePackedSerializationTest, SPSInputBuffer) { + char Buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + SPSInputBuffer IB(Buffer, sizeof(Buffer)); + + char C; + for (unsigned I = 0; I != sizeof(Buffer); ++I) { + EXPECT_TRUE(IB.read(&C, 1)); + EXPECT_EQ(C, (char)I); + } + + EXPECT_FALSE(IB.read(&C, 1)); +} + +template <typename T> static void testFixedIntegralTypeSerialization() { + blobSerializationRoundTrip<T, T>(0); + blobSerializationRoundTrip<T, T>(static_cast<T>(1)); + if (std::is_signed<T>::value) { + blobSerializationRoundTrip<T, T>(static_cast<T>(-1)); + blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::min()); + } + blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::max()); +} + +TEST(SimplePackedSerializationTest, BoolSerialization) { + blobSerializationRoundTrip<bool, bool>(true); + blobSerializationRoundTrip<bool, bool>(false); +} + +TEST(SimplePackedSerializationTest, CharSerialization) { + blobSerializationRoundTrip<char, char>((char)0x00); + blobSerializationRoundTrip<char, char>((char)0xAA); + blobSerializationRoundTrip<char, char>((char)0xFF); +} + +TEST(SimplePackedSerializationTest, Int8Serialization) { + testFixedIntegralTypeSerialization<int8_t>(); +} + +TEST(SimplePackedSerializationTest, UInt8Serialization) { + testFixedIntegralTypeSerialization<uint8_t>(); +} + +TEST(SimplePackedSerializationTest, Int16Serialization) { + testFixedIntegralTypeSerialization<int16_t>(); +} + +TEST(SimplePackedSerializationTest, UInt16Serialization) { + testFixedIntegralTypeSerialization<uint16_t>(); +} + +TEST(SimplePackedSerializationTest, Int32Serialization) { + testFixedIntegralTypeSerialization<int32_t>(); +} + +TEST(SimplePackedSerializationTest, UInt32Serialization) { + testFixedIntegralTypeSerialization<uint32_t>(); +} + +TEST(SimplePackedSerializationTest, Int64Serialization) { + testFixedIntegralTypeSerialization<int64_t>(); +} + +TEST(SimplePackedSerializationTest, UInt64Serialization) { + testFixedIntegralTypeSerialization<uint64_t>(); +} + +TEST(SimplePackedSerializationTest, SequenceSerialization) { + std::vector<int32_t> V({1, 2, -47, 139}); + blobSerializationRoundTrip<SPSSequence<int32_t>, std::vector<int32_t>>(V); +} + +TEST(SimplePackedSerializationTest, StringViewCharSequenceSerialization) { + const char *HW = "Hello, world!"; + blobSerializationRoundTrip<SPSString, std::string_view>(std::string_view(HW)); +} + +TEST(SimplePackedSerializationTest, SpanSerialization) { + const char Data[] = {3, 2, 1, 0, 1, 2, 3}; // Span should handle nulls. + span<const char> OutS(Data, sizeof(Data)); + + size_t Size = SPSArgList<SPSSequence<char>>::size(OutS); + auto Buffer = std::make_unique<char[]>(Size); + SPSOutputBuffer OB(Buffer.get(), Size); + + EXPECT_TRUE(SPSArgList<SPSSequence<char>>::serialize(OB, OutS)); + + SPSInputBuffer IB(Buffer.get(), Size); + + span<const char> InS; + + EXPECT_TRUE(SPSArgList<SPSSequence<char>>::deserialize(IB, InS)); + + // Check that the serialized and deserialized values match. + EXPECT_EQ(InS.size(), OutS.size()); + EXPECT_EQ(memcmp(OutS.data(), InS.data(), InS.size()), 0); + + // Check that the span points directly to the input buffer. + EXPECT_EQ(InS.data(), Buffer.get() + sizeof(uint64_t)); +} + +TEST(SimplePackedSerializationTest, StdTupleSerialization) { + std::tuple<int32_t, std::string, bool> P(42, "foo", true); + blobSerializationRoundTrip<SPSTuple<int32_t, SPSString, bool>>(P); +} + +TEST(SimplePackedSerializationTest, StdPairSerialization) { + std::pair<int32_t, std::string> P(42, "foo"); + blobSerializationRoundTrip<SPSTuple<int32_t, SPSString>, + std::pair<int32_t, std::string>>(P); +} + +TEST(SimplePackedSerializationTest, StdOptionalNoValueSerialization) { + std::optional<int64_t> NoValue; + blobSerializationRoundTrip<SPSOptional<int64_t>>(NoValue); +} + +TEST(SimplePackedSerializationTest, StdOptionalValueSerialization) { + std::optional<int64_t> Value(42); + blobSerializationRoundTrip<SPSOptional<int64_t>>(Value); +} + +TEST(SimplePackedSerializationTest, ArgListSerialization) { + using BAL = SPSArgList<bool, int32_t, SPSString>; + + bool Arg1 = true; + int32_t Arg2 = 42; + std::string Arg3 = "foo"; + + size_t Size = BAL::size(Arg1, Arg2, Arg3); + auto Buffer = std::make_unique<char[]>(Size); + SPSOutputBuffer OB(Buffer.get(), Size); + + EXPECT_TRUE(BAL::serialize(OB, Arg1, Arg2, Arg3)); + + SPSInputBuffer IB(Buffer.get(), Size); + + bool ArgOut1; + int32_t ArgOut2; + std::string ArgOut3; + + EXPECT_TRUE(BAL::deserialize(IB, ArgOut1, ArgOut2, ArgOut3)); + + EXPECT_EQ(Arg1, ArgOut1); + EXPECT_EQ(Arg2, ArgOut2); + EXPECT_EQ(Arg3, ArgOut3); +} diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h new file mode 100644 index 000000000000..746be43d250b --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h @@ -0,0 +1,34 @@ +//===-- simple_packed_serialization_utils.h -------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H +#define ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H + +#include "simple_packed_serialization.h" +#include "gtest/gtest.h" + +template <typename SPSTagT, typename T> +static void blobSerializationRoundTrip(const T &Value) { + using BST = __orc_rt::SPSSerializationTraits<SPSTagT, T>; + + size_t Size = BST::size(Value); + auto Buffer = std::make_unique<char[]>(Size); + __orc_rt::SPSOutputBuffer OB(Buffer.get(), Size); + + EXPECT_TRUE(BST::serialize(OB, Value)); + + __orc_rt::SPSInputBuffer IB(Buffer.get(), Size); + + T DSValue; + EXPECT_TRUE(BST::deserialize(IB, DSValue)); + + EXPECT_EQ(Value, DSValue) + << "Incorrect value after serialization/deserialization round-trip"; +} + +#endif // ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H
\ No newline at end of file diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp new file mode 100644 index 000000000000..15ee2ce7d24d --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp @@ -0,0 +1,66 @@ +//===---------- string_pool_test.cpp - Unit tests for StringPool ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "string_pool.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +namespace { + +TEST(StringPool, UniquingAndComparisons) { + StringPool SP; + auto P1 = SP.intern("hello"); + + std::string S("hel"); + S += "lo"; + auto P2 = SP.intern(S); + + auto P3 = SP.intern("goodbye"); + + EXPECT_EQ(P1, P2) << "Failed to unique entries"; + EXPECT_NE(P1, P3) << "Unequal pooled strings comparing equal"; + + // We want to test that less-than comparison of PooledStringPtrs compiles, + // however we can't test the actual result as this is a pointer comparison and + // PooledStringPtr doesn't expose the underlying address of the string. + (void)(P1 < P3); +} + +TEST(StringPool, Dereference) { + StringPool SP; + auto Foo = SP.intern("foo"); + EXPECT_EQ(*Foo, "foo") << "Equality on dereferenced string failed"; +} + +TEST(StringPool, ClearDeadEntries) { + StringPool SP; + { + auto P1 = SP.intern("s1"); + SP.clearDeadEntries(); + EXPECT_FALSE(SP.empty()) << "\"s1\" entry in pool should still be retained"; + } + SP.clearDeadEntries(); + EXPECT_TRUE(SP.empty()) << "pool should be empty"; +} + +TEST(StringPool, NullPtr) { + // Make sure that we can default construct and then destroy a null + // PooledStringPtr. + PooledStringPtr Null; +} + +TEST(StringPool, Hashable) { + StringPool SP; + PooledStringPtr P1 = SP.intern("s1"); + PooledStringPtr Null; + EXPECT_NE(std::hash<PooledStringPtr>()(P1), + std::hash<PooledStringPtr>()(Null)); +} + +} // end anonymous namespace diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp new file mode 100644 index 000000000000..f10c5093046d --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp @@ -0,0 +1,184 @@ +//===-- wrapper_function_utils_test.cpp -----------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "wrapper_function_utils.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +namespace { +constexpr const char *TestString = "test string"; +} // end anonymous namespace + +TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) { + WrapperFunctionResult R; + EXPECT_TRUE(R.empty()); + EXPECT_EQ(R.size(), 0U); + EXPECT_EQ(R.getOutOfBandError(), nullptr); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) { + orc_rt_CWrapperFunctionResult CR = + orc_rt_CreateCWrapperFunctionResultFromString(TestString); + WrapperFunctionResult R(CR); + EXPECT_EQ(R.size(), strlen(TestString) + 1); + EXPECT_TRUE(strcmp(R.data(), TestString) == 0); + EXPECT_FALSE(R.empty()); + EXPECT_EQ(R.getOutOfBandError(), nullptr); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) { + auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1); + EXPECT_EQ(R.size(), strlen(TestString) + 1); + EXPECT_TRUE(strcmp(R.data(), TestString) == 0); + EXPECT_FALSE(R.empty()); + EXPECT_EQ(R.getOutOfBandError(), nullptr); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) { + auto R = WrapperFunctionResult::copyFrom(TestString); + EXPECT_EQ(R.size(), strlen(TestString) + 1); + EXPECT_TRUE(strcmp(R.data(), TestString) == 0); + EXPECT_FALSE(R.empty()); + EXPECT_EQ(R.getOutOfBandError(), nullptr); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromStdString) { + auto R = WrapperFunctionResult::copyFrom(std::string(TestString)); + EXPECT_EQ(R.size(), strlen(TestString) + 1); + EXPECT_TRUE(strcmp(R.data(), TestString) == 0); + EXPECT_FALSE(R.empty()); + EXPECT_EQ(R.getOutOfBandError(), nullptr); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) { + auto R = WrapperFunctionResult::createOutOfBandError(TestString); + EXPECT_FALSE(R.empty()); + EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionCCallCreateEmpty) { + EXPECT_TRUE(!!WrapperFunctionCall::Create<SPSArgList<>>(ExecutorAddr())); +} + +static void voidNoop() {} + +static orc_rt_CWrapperFunctionResult voidNoopWrapper(const char *ArgData, + size_t ArgSize) { + return WrapperFunction<void()>::handle(ArgData, ArgSize, voidNoop).release(); +} + +static orc_rt_CWrapperFunctionResult addWrapper(const char *ArgData, + size_t ArgSize) { + return WrapperFunction<int32_t(int32_t, int32_t)>::handle( + ArgData, ArgSize, + [](int32_t X, int32_t Y) -> int32_t { return X + Y; }) + .release(); +} + +extern "C" __orc_rt_Opaque __orc_rt_jit_dispatch_ctx{}; + +extern "C" orc_rt_CWrapperFunctionResult +__orc_rt_jit_dispatch(__orc_rt_Opaque *Ctx, const void *FnTag, + const char *ArgData, size_t ArgSize) { + using WrapperFunctionType = + orc_rt_CWrapperFunctionResult (*)(const char *, size_t); + + return reinterpret_cast<WrapperFunctionType>(const_cast<void *>(FnTag))( + ArgData, ArgSize); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionCallVoidNoopAndHandle) { + EXPECT_FALSE(!!WrapperFunction<void()>::call((void *)&voidNoopWrapper)); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionCallAddWrapperAndHandle) { + int32_t Result; + EXPECT_FALSE(!!WrapperFunction<int32_t(int32_t, int32_t)>::call( + (void *)&addWrapper, Result, 1, 2)); + EXPECT_EQ(Result, (int32_t)3); +} + +class AddClass { +public: + AddClass(int32_t X) : X(X) {} + int32_t addMethod(int32_t Y) { return X + Y; } + +private: + int32_t X; +}; + +static orc_rt_CWrapperFunctionResult addMethodWrapper(const char *ArgData, + size_t ArgSize) { + return WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::handle( + ArgData, ArgSize, makeMethodWrapperHandler(&AddClass::addMethod)) + .release(); +} + +TEST(WrapperFunctionUtilsTest, WrapperFunctionMethodCallAndHandleRet) { + int32_t Result; + AddClass AddObj(1); + EXPECT_FALSE(!!WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::call( + (void *)&addMethodWrapper, Result, ExecutorAddr::fromPtr(&AddObj), 2)); + EXPECT_EQ(Result, (int32_t)3); +} + +static orc_rt_CWrapperFunctionResult sumArrayWrapper(const char *ArgData, + size_t ArgSize) { + return WrapperFunction<int8_t(SPSExecutorAddrRange)>::handle( + ArgData, ArgSize, + [](ExecutorAddrRange R) { + int8_t Sum = 0; + for (char C : R.toSpan<char>()) + Sum += C; + return Sum; + }) + .release(); +} + +TEST(WrapperFunctionUtilsTest, SerializedWrapperFunctionCallTest) { + { + // Check wrapper function calls. + char A[] = {1, 2, 3, 4}; + + auto WFC = + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( + ExecutorAddr::fromPtr(sumArrayWrapper), + ExecutorAddrRange(ExecutorAddr::fromPtr(A), + ExecutorAddrDiff(sizeof(A))))); + + WrapperFunctionResult WFR(WFC.run()); + EXPECT_EQ(WFR.size(), 1U); + EXPECT_EQ(WFR.data()[0], 10); + } + + { + // Check calls to void functions. + auto WFC = + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( + ExecutorAddr::fromPtr(voidNoopWrapper), ExecutorAddrRange())); + auto Err = WFC.runWithSPSRet<void>(); + EXPECT_FALSE(!!Err); + } + + { + // Check calls with arguments and return values. + auto WFC = + cantFail(WrapperFunctionCall::Create<SPSArgList<int32_t, int32_t>>( + ExecutorAddr::fromPtr(addWrapper), 2, 4)); + + int32_t Result = 0; + auto Err = WFC.runWithSPSRet<int32_t>(Result); + EXPECT_FALSE(!!Err); + EXPECT_EQ(Result, 6); + } +} |
