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); +  } +} | 
