diff options
Diffstat (limited to 'unittests')
103 files changed, 5765 insertions, 486 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 8b82fb2f4ed6f..a4445f6e4651c 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" +#include <cmath> #include <ostream> #include <string> @@ -1305,13 +1306,13 @@ TEST(APFloatTest, roundToIntegral) { EXPECT_EQ(-0.0, P.convertToDouble()); P = APFloat::getNaN(APFloat::IEEEdouble); P.roundToIntegral(APFloat::rmTowardZero); - EXPECT_TRUE(IsNAN(P.convertToDouble())); + EXPECT_TRUE(std::isnan(P.convertToDouble())); P = APFloat::getInf(APFloat::IEEEdouble); P.roundToIntegral(APFloat::rmTowardZero); - EXPECT_TRUE(IsInf(P.convertToDouble()) && P.convertToDouble() > 0.0); + EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() > 0.0); P = APFloat::getInf(APFloat::IEEEdouble, true); P.roundToIntegral(APFloat::rmTowardZero); - EXPECT_TRUE(IsInf(P.convertToDouble()) && P.convertToDouble() < 0.0); + EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() < 0.0); } diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index 3b7ac5b894029..498f50c9c81ff 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -209,6 +209,103 @@ TEST(APIntTest, i1) { } } + +// Tests different div/rem varaints using scheme (a * b + c) / a +void testDiv(APInt a, APInt b, APInt c) { + ASSERT_TRUE(a.uge(b)); // Must: a >= b + ASSERT_TRUE(a.ugt(c)); // Must: a > c + + auto p = a * b + c; + + auto q = p.udiv(a); + auto r = p.urem(a); + EXPECT_EQ(b, q); + EXPECT_EQ(c, r); + APInt::udivrem(p, a, q, r); + EXPECT_EQ(b, q); + EXPECT_EQ(c, r); + q = p.sdiv(a); + r = p.srem(a); + EXPECT_EQ(b, q); + EXPECT_EQ(c, r); + APInt::sdivrem(p, a, q, r); + EXPECT_EQ(b, q); + EXPECT_EQ(c, r); + + if (b.ugt(c)) { // Test also symmetric case + q = p.udiv(b); + r = p.urem(b); + EXPECT_EQ(a, q); + EXPECT_EQ(c, r); + APInt::udivrem(p, b, q, r); + EXPECT_EQ(a, q); + EXPECT_EQ(c, r); + q = p.sdiv(b); + r = p.srem(b); + EXPECT_EQ(a, q); + EXPECT_EQ(c, r); + APInt::sdivrem(p, b, q, r); + EXPECT_EQ(a, q); + EXPECT_EQ(c, r); + } +} + +TEST(APIntTest, divrem_big1) { + // Tests KnuthDiv rare step D6 + testDiv({256, "1ffffffffffffffff", 16}, + {256, "1ffffffffffffffff", 16}, + {256, 0}); +} + +TEST(APIntTest, divrem_big2) { + // Tests KnuthDiv rare step D6 + testDiv({1024, "112233ceff" + "cecece000000ffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff33", 16}, + {1024, "111111ffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffccf" + "ffffffffffffffffffffffffffffff00", 16}, + {1024, 7919}); +} + +TEST(APIntTest, divrem_big3) { + // Tests KnuthDiv case without shift + testDiv({256, "80000001ffffffffffffffff", 16}, + {256, "ffffffffffffff0000000", 16}, + {256, 4219}); +} + +TEST(APIntTest, divrem_big4) { + // Tests heap allocation in divide() enfoced by huge numbers + testDiv(APInt{4096, 5}.shl(2001), + APInt{4096, 1}.shl(2000), + APInt{4096, 4219*13}); +} + +TEST(APIntTest, divrem_big5) { + // Tests one word divisor case of divide() + testDiv(APInt{1024, 19}.shl(811), + APInt{1024, 4356013}, // one word + APInt{1024, 1}); +} + +TEST(APIntTest, divrem_big6) { + // Tests some rare "borrow" cases in D4 step + testDiv(APInt{512, "ffffffffffffffff00000000000000000000000001", 16}, + APInt{512, "10000000000000001000000000000001", 16}, + APInt{512, "10000000000000000000000000000000", 16}); +} + +TEST(APIntTest, divrem_big7) { + // Yet another test for KnuthDiv rare step D6. + testDiv({224, "800000008000000200000005", 16}, + {224, "fffffffd", 16}, + {224, "80000000800000010000000f", 16}); +} + TEST(APIntTest, fromString) { EXPECT_EQ(APInt(32, 0), APInt(32, "0", 2)); EXPECT_EQ(APInt(32, 1), APInt(32, "1", 2)); @@ -678,6 +775,46 @@ TEST(APIntTest, nearestLogBase2) { EXPECT_EQ(A9.nearestLogBase2(), UINT32_MAX); } +TEST(APIntTest, IsSplat) { + APInt A(32, 0x01010101); + EXPECT_FALSE(A.isSplat(1)); + EXPECT_FALSE(A.isSplat(2)); + EXPECT_FALSE(A.isSplat(4)); + EXPECT_TRUE(A.isSplat(8)); + EXPECT_TRUE(A.isSplat(16)); + EXPECT_TRUE(A.isSplat(32)); + + APInt B(24, 0xAAAAAA); + EXPECT_FALSE(B.isSplat(1)); + EXPECT_TRUE(B.isSplat(2)); + EXPECT_TRUE(B.isSplat(4)); + EXPECT_TRUE(B.isSplat(8)); + EXPECT_TRUE(B.isSplat(24)); + + APInt C(24, 0xABAAAB); + EXPECT_FALSE(C.isSplat(1)); + EXPECT_FALSE(C.isSplat(2)); + EXPECT_FALSE(C.isSplat(4)); + EXPECT_FALSE(C.isSplat(8)); + EXPECT_TRUE(C.isSplat(24)); + + APInt D(32, 0xABBAABBA); + EXPECT_FALSE(D.isSplat(1)); + EXPECT_FALSE(D.isSplat(2)); + EXPECT_FALSE(D.isSplat(4)); + EXPECT_FALSE(D.isSplat(8)); + EXPECT_TRUE(D.isSplat(16)); + EXPECT_TRUE(D.isSplat(32)); + + APInt E(32, 0); + EXPECT_TRUE(E.isSplat(1)); + EXPECT_TRUE(E.isSplat(2)); + EXPECT_TRUE(E.isSplat(4)); + EXPECT_TRUE(E.isSplat(8)); + EXPECT_TRUE(E.isSplat(16)); + EXPECT_TRUE(E.isSplat(32)); +} + #if defined(__clang__) // Disable the pragma warning from versions of Clang without -Wself-move #pragma clang diagnostic push diff --git a/unittests/ADT/APSIntTest.cpp b/unittests/ADT/APSIntTest.cpp index eef9c8a90af98..5e4e87440bdb7 100644 --- a/unittests/ADT/APSIntTest.cpp +++ b/unittests/ADT/APSIntTest.cpp @@ -41,4 +41,106 @@ TEST(APSIntTest, MoveTest) { EXPECT_EQ(Bits, A.getRawData()); // Verify that "Wide" was really moved. } +TEST(APSIntTest, get) { + EXPECT_TRUE(APSInt::get(7).isSigned()); + EXPECT_EQ(64u, APSInt::get(7).getBitWidth()); + EXPECT_EQ(7u, APSInt::get(7).getZExtValue()); + EXPECT_EQ(7, APSInt::get(7).getSExtValue()); + EXPECT_TRUE(APSInt::get(-7).isSigned()); + EXPECT_EQ(64u, APSInt::get(-7).getBitWidth()); + EXPECT_EQ(-7, APSInt::get(-7).getSExtValue()); + EXPECT_EQ(UINT64_C(0) - 7, APSInt::get(-7).getZExtValue()); +} + +TEST(APSIntTest, getUnsigned) { + EXPECT_TRUE(APSInt::getUnsigned(7).isUnsigned()); + EXPECT_EQ(64u, APSInt::getUnsigned(7).getBitWidth()); + EXPECT_EQ(7u, APSInt::getUnsigned(7).getZExtValue()); + EXPECT_EQ(7, APSInt::getUnsigned(7).getSExtValue()); + EXPECT_TRUE(APSInt::getUnsigned(-7).isUnsigned()); + EXPECT_EQ(64u, APSInt::getUnsigned(-7).getBitWidth()); + EXPECT_EQ(-7, APSInt::getUnsigned(-7).getSExtValue()); + EXPECT_EQ(UINT64_C(0) - 7, APSInt::getUnsigned(-7).getZExtValue()); +} + +TEST(APSIntTest, getExtValue) { + EXPECT_TRUE(APSInt(APInt(3, 7), true).isUnsigned()); + EXPECT_TRUE(APSInt(APInt(3, 7), false).isSigned()); + EXPECT_TRUE(APSInt(APInt(4, 7), true).isUnsigned()); + EXPECT_TRUE(APSInt(APInt(4, 7), false).isSigned()); + EXPECT_TRUE(APSInt(APInt(4, -7), true).isUnsigned()); + EXPECT_TRUE(APSInt(APInt(4, -7), false).isSigned()); + EXPECT_EQ(7, APSInt(APInt(3, 7), true).getExtValue()); + EXPECT_EQ(-1, APSInt(APInt(3, 7), false).getExtValue()); + EXPECT_EQ(7, APSInt(APInt(4, 7), true).getExtValue()); + EXPECT_EQ(7, APSInt(APInt(4, 7), false).getExtValue()); + EXPECT_EQ(9, APSInt(APInt(4, -7), true).getExtValue()); + EXPECT_EQ(-7, APSInt(APInt(4, -7), false).getExtValue()); +} + +TEST(APSIntTest, compareValues) { + auto U = [](uint64_t V) { return APSInt::getUnsigned(V); }; + auto S = [](int64_t V) { return APSInt::get(V); }; + + // Bit-width matches and is-signed. + EXPECT_TRUE(APSInt::compareValues(S(7), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8), S(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(7), S(7)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8), S(-7)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-7)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-8)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-8), S(-7)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-7)) == 0); + + // Bit-width matches and not is-signed. + EXPECT_TRUE(APSInt::compareValues(U(7), U(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8), U(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7), U(7)) == 0); + + // Bit-width matches and mixed signs. + EXPECT_TRUE(APSInt::compareValues(U(7), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8), S(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7), S(7)) == 0); + EXPECT_TRUE(APSInt::compareValues(U(8), S(-7)) > 0); + + // Bit-width mismatch and is-signed. + EXPECT_TRUE(APSInt::compareValues(S(7).trunc(32), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8).trunc(32), S(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(7).trunc(32), S(7)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7).trunc(32), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8).trunc(32), S(-7)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-7).trunc(32), S(-7)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7).trunc(32), S(-8)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-8).trunc(32), S(-7)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(-7).trunc(32), S(-7)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(7), S(8).trunc(32)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8), S(7).trunc(32)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(7), S(7).trunc(32)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(8).trunc(32)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(8), S(-7).trunc(32)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-7).trunc(32)) == 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-8).trunc(32)) > 0); + EXPECT_TRUE(APSInt::compareValues(S(-8), S(-7).trunc(32)) < 0); + EXPECT_TRUE(APSInt::compareValues(S(-7), S(-7).trunc(32)) == 0); + + // Bit-width mismatch and not is-signed. + EXPECT_TRUE(APSInt::compareValues(U(7), U(8).trunc(32)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8), U(7).trunc(32)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7), U(7).trunc(32)) == 0); + EXPECT_TRUE(APSInt::compareValues(U(7).trunc(32), U(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8).trunc(32), U(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7).trunc(32), U(7)) == 0); + + // Bit-width mismatch and mixed signs. + EXPECT_TRUE(APSInt::compareValues(U(7).trunc(32), S(8)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8).trunc(32), S(7)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7).trunc(32), S(7)) == 0); + EXPECT_TRUE(APSInt::compareValues(U(8).trunc(32), S(-7)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7), S(8).trunc(32)) < 0); + EXPECT_TRUE(APSInt::compareValues(U(8), S(7).trunc(32)) > 0); + EXPECT_TRUE(APSInt::compareValues(U(7), S(7).trunc(32)) == 0); + EXPECT_TRUE(APSInt::compareValues(U(8), S(-7).trunc(32)) > 0); +} + } diff --git a/unittests/ADT/ArrayRefTest.cpp b/unittests/ADT/ArrayRefTest.cpp index f9c98a563fa3c..6955036f11319 100644 --- a/unittests/ADT/ArrayRefTest.cpp +++ b/unittests/ADT/ArrayRefTest.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" +#include <vector> using namespace llvm; // Check that the ArrayRef-of-pointer converting constructor only allows adding @@ -56,24 +57,24 @@ TEST(ArrayRefTest, DropBack) { TEST(ArrayRefTest, Equals) { static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8}; ArrayRef<int> AR1(A1); - EXPECT_TRUE(AR1.equals(1, 2, 3, 4, 5, 6, 7, 8)); - EXPECT_FALSE(AR1.equals(8, 1, 2, 4, 5, 6, 6, 7)); - EXPECT_FALSE(AR1.equals(2, 4, 5, 6, 6, 7, 8, 1)); - EXPECT_FALSE(AR1.equals(0, 1, 2, 4, 5, 6, 6, 7)); - EXPECT_FALSE(AR1.equals(1, 2, 42, 4, 5, 6, 7, 8)); - EXPECT_FALSE(AR1.equals(42, 2, 3, 4, 5, 6, 7, 8)); - EXPECT_FALSE(AR1.equals(1, 2, 3, 4, 5, 6, 7, 42)); - EXPECT_FALSE(AR1.equals(1, 2, 3, 4, 5, 6, 7)); - EXPECT_FALSE(AR1.equals(1, 2, 3, 4, 5, 6, 7, 8, 9)); + EXPECT_TRUE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8})); + EXPECT_FALSE(AR1.equals({8, 1, 2, 4, 5, 6, 6, 7})); + EXPECT_FALSE(AR1.equals({2, 4, 5, 6, 6, 7, 8, 1})); + EXPECT_FALSE(AR1.equals({0, 1, 2, 4, 5, 6, 6, 7})); + EXPECT_FALSE(AR1.equals({1, 2, 42, 4, 5, 6, 7, 8})); + EXPECT_FALSE(AR1.equals({42, 2, 3, 4, 5, 6, 7, 8})); + EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 42})); + EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7})); + EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8, 9})); ArrayRef<int> AR1a = AR1.drop_back(); - EXPECT_TRUE(AR1a.equals(1, 2, 3, 4, 5, 6, 7)); - EXPECT_FALSE(AR1a.equals(1, 2, 3, 4, 5, 6, 7, 8)); + EXPECT_TRUE(AR1a.equals({1, 2, 3, 4, 5, 6, 7})); + EXPECT_FALSE(AR1a.equals({1, 2, 3, 4, 5, 6, 7, 8})); ArrayRef<int> AR1b = AR1a.slice(2, 4); - EXPECT_TRUE(AR1b.equals(3, 4, 5, 6)); - EXPECT_FALSE(AR1b.equals(2, 3, 4, 5, 6)); - EXPECT_FALSE(AR1b.equals(3, 4, 5, 6, 7)); + EXPECT_TRUE(AR1b.equals({3, 4, 5, 6})); + EXPECT_FALSE(AR1b.equals({2, 3, 4, 5, 6})); + EXPECT_FALSE(AR1b.equals({3, 4, 5, 6, 7})); } TEST(ArrayRefTest, EmptyEquals) { @@ -90,4 +91,24 @@ TEST(ArrayRefTest, ConstConvert) { a = ArrayRef<int *>(A); } +static std::vector<int> ReturnTest12() { return {1, 2}; } +static void ArgTest12(ArrayRef<int> A) { + EXPECT_EQ(2U, A.size()); + EXPECT_EQ(1, A[0]); + EXPECT_EQ(2, A[1]); +} + +TEST(ArrayRefTest, InitializerList) { + ArrayRef<int> A = { 0, 1, 2, 3, 4 }; + for (int i = 0; i < 5; ++i) + EXPECT_EQ(i, A[i]); + + std::vector<int> B = ReturnTest12(); + A = B; + EXPECT_EQ(1, A[0]); + EXPECT_EQ(2, A[1]); + + ArgTest12({1, 2}); +} + } // end anonymous namespace diff --git a/unittests/ADT/DAGDeltaAlgorithmTest.cpp b/unittests/ADT/DAGDeltaAlgorithmTest.cpp index 370b7c20a0934..190df7f574707 100644 --- a/unittests/ADT/DAGDeltaAlgorithmTest.cpp +++ b/unittests/ADT/DAGDeltaAlgorithmTest.cpp @@ -22,7 +22,7 @@ class FixedDAGDeltaAlgorithm : public DAGDeltaAlgorithm { unsigned NumTests; protected: - virtual bool ExecuteOneTest(const changeset_ty &Changes) { + bool ExecuteOneTest(const changeset_ty &Changes) override { ++NumTests; return std::includes(Changes.begin(), Changes.end(), FailingSet.begin(), FailingSet.end()); diff --git a/unittests/ADT/DeltaAlgorithmTest.cpp b/unittests/ADT/DeltaAlgorithmTest.cpp index a1884cd8f3a14..bed57b1a17254 100644 --- a/unittests/ADT/DeltaAlgorithmTest.cpp +++ b/unittests/ADT/DeltaAlgorithmTest.cpp @@ -32,12 +32,12 @@ std::ostream &operator<<(std::ostream &OS, namespace { -class FixedDeltaAlgorithm : public DeltaAlgorithm { +class FixedDeltaAlgorithm final : public DeltaAlgorithm { changeset_ty FailingSet; unsigned NumTests; protected: - virtual bool ExecuteOneTest(const changeset_ty &Changes) { + bool ExecuteOneTest(const changeset_ty &Changes) override { ++NumTests; return std::includes(Changes.begin(), Changes.end(), FailingSet.begin(), FailingSet.end()); diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp index f4979839c78d5..97807771725d4 100644 --- a/unittests/ADT/DenseMapTest.cpp +++ b/unittests/ADT/DenseMapTest.cpp @@ -46,6 +46,7 @@ public: CtorTester(const CtorTester &Arg) : Value(Arg.Value) { EXPECT_TRUE(Constructed.insert(this).second); } + CtorTester &operator=(const CtorTester &) = default; ~CtorTester() { EXPECT_EQ(1u, Constructed.erase(this)); } diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp index acaa83cddddd8..b28561bd01155 100644 --- a/unittests/ADT/HashingTest.cpp +++ b/unittests/ADT/HashingTest.cpp @@ -33,7 +33,6 @@ struct LargeTestInteger { uint64_t arr[8]; }; struct NonPOD { uint64_t x, y; NonPOD(uint64_t x, uint64_t y) : x(x), y(y) {} - ~NonPOD() {} friend hash_code hash_value(const NonPOD &obj) { return hash_combine(obj.x, obj.y); } @@ -421,4 +420,29 @@ TEST(HashingTest, HashCombineBasicTest) { hash_combine(bigarr[0], l2, bigarr[9], l3, bigarr[18], bigarr[19])); } +TEST(HashingTest, HashCombineArgs18) { + // This tests that we can pass in up to 18 args. +#define CHECK_SAME(...) \ + EXPECT_EQ(hash_combine(__VA_ARGS__), hash_combine(__VA_ARGS__)) + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8); + CHECK_SAME(1, 2, 3, 4, 5, 6, 7); + CHECK_SAME(1, 2, 3, 4, 5, 6); + CHECK_SAME(1, 2, 3, 4, 5); + CHECK_SAME(1, 2, 3, 4); + CHECK_SAME(1, 2, 3); + CHECK_SAME(1, 2); + CHECK_SAME(1); +#undef CHECK_SAME +} + } diff --git a/unittests/ADT/MapVectorTest.cpp b/unittests/ADT/MapVectorTest.cpp index 2caa8c7b5bb5c..ff8464293c79c 100644 --- a/unittests/ADT/MapVectorTest.cpp +++ b/unittests/ADT/MapVectorTest.cpp @@ -14,6 +14,31 @@ using namespace llvm; +TEST(MapVectorTest, swap) { + MapVector<int, int> MV1, MV2; + std::pair<MapVector<int, int>::iterator, bool> R; + + R = MV1.insert(std::make_pair(1, 2)); + ASSERT_EQ(R.first, MV1.begin()); + EXPECT_EQ(R.first->first, 1); + EXPECT_EQ(R.first->second, 2); + EXPECT_TRUE(R.second); + + EXPECT_FALSE(MV1.empty()); + EXPECT_TRUE(MV2.empty()); + MV2.swap(MV1); + EXPECT_TRUE(MV1.empty()); + EXPECT_FALSE(MV2.empty()); + + auto I = MV1.find(1); + ASSERT_EQ(MV1.end(), I); + + I = MV2.find(1); + ASSERT_EQ(I, MV2.begin()); + EXPECT_EQ(I->first, 1); + EXPECT_EQ(I->second, 2); +} + TEST(MapVectorTest, insert_pop) { MapVector<int, int> MV; std::pair<MapVector<int, int>::iterator, bool> R; diff --git a/unittests/ADT/OptionalTest.cpp b/unittests/ADT/OptionalTest.cpp index cadadced13972..92c4eec487a67 100644 --- a/unittests/ADT/OptionalTest.cpp +++ b/unittests/ADT/OptionalTest.cpp @@ -183,10 +183,10 @@ struct MultiArgConstructor { explicit MultiArgConstructor(int x, bool positive) : x(x), y(positive ? x : -x) {} - MultiArgConstructor(const MultiArgConstructor &) LLVM_DELETED_FUNCTION; - MultiArgConstructor(MultiArgConstructor &&) LLVM_DELETED_FUNCTION; - MultiArgConstructor &operator=(const MultiArgConstructor &) LLVM_DELETED_FUNCTION; - MultiArgConstructor &operator=(MultiArgConstructor &&) LLVM_DELETED_FUNCTION; + MultiArgConstructor(const MultiArgConstructor &) = delete; + MultiArgConstructor(MultiArgConstructor &&) = delete; + MultiArgConstructor &operator=(const MultiArgConstructor &) = delete; + MultiArgConstructor &operator=(MultiArgConstructor &&) = delete; static unsigned Destructions; ~MultiArgConstructor() { @@ -340,7 +340,7 @@ struct Immovable { } private: // This should disable all move/copy operations. - Immovable(Immovable&& other) LLVM_DELETED_FUNCTION; + Immovable(Immovable&& other) = delete; }; unsigned Immovable::Constructions = 0; diff --git a/unittests/ADT/PointerIntPairTest.cpp b/unittests/ADT/PointerIntPairTest.cpp index 296d47590d788..0bbcd9f869eca 100644 --- a/unittests/ADT/PointerIntPairTest.cpp +++ b/unittests/ADT/PointerIntPairTest.cpp @@ -42,7 +42,6 @@ TEST_F(PointerIntPairTest, DefaultInitialize) { EXPECT_EQ(0U, Pair.getInt()); } -#if !(defined(_MSC_VER) && _MSC_VER==1700) TEST_F(PointerIntPairTest, ManyUnusedBits) { // In real code this would be a word-sized integer limited to 31 bits. struct Fixnum31 { @@ -71,6 +70,5 @@ TEST_F(PointerIntPairTest, ManyUnusedBits) { EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1, PointerLikeTypeTraits<decltype(pair)>::NumLowBitsAvailable); } -#endif } // end anonymous namespace diff --git a/unittests/ADT/SCCIteratorTest.cpp b/unittests/ADT/SCCIteratorTest.cpp index 3f1ba1c5843f6..da8c04483f9ca 100644 --- a/unittests/ADT/SCCIteratorTest.cpp +++ b/unittests/ADT/SCCIteratorTest.cpp @@ -39,8 +39,6 @@ public: NodeSubset() : Elements(0) { assert(N <= sizeof(BitVector)*CHAR_BIT && "Graph too big!"); } - /// NodeSubset - Copy constructor. - NodeSubset(const NodeSubset &other) : Elements(other.Elements) {} /// Comparison operators. bool operator==(const NodeSubset &other) const { @@ -252,7 +250,7 @@ TEST(SCCIteratorTest, AllSmallGraphs) { typedef Graph<NUM_NODES> GT; /// Enumerate all graphs using NUM_GRAPHS bits. - assert(NUM_GRAPHS < sizeof(unsigned) * CHAR_BIT && "Too many graphs!"); + static_assert(NUM_GRAPHS < sizeof(unsigned) * CHAR_BIT, "Too many graphs!"); for (unsigned GraphDescriptor = 0; GraphDescriptor < (1U << NUM_GRAPHS); ++GraphDescriptor) { GT G; diff --git a/unittests/ADT/SmallVectorTest.cpp b/unittests/ADT/SmallVectorTest.cpp index ba6c395e69fa1..46f7021ac165d 100644 --- a/unittests/ADT/SmallVectorTest.cpp +++ b/unittests/ADT/SmallVectorTest.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "gtest/gtest.h" @@ -144,8 +145,8 @@ struct NonCopyable { NonCopyable(NonCopyable &&) {} NonCopyable &operator=(NonCopyable &&) { return *this; } private: - NonCopyable(const NonCopyable &) LLVM_DELETED_FUNCTION; - NonCopyable &operator=(const NonCopyable &) LLVM_DELETED_FUNCTION; + NonCopyable(const NonCopyable &) = delete; + NonCopyable &operator=(const NonCopyable &) = delete; }; LLVM_ATTRIBUTE_USED void CompileTest() { @@ -153,17 +154,11 @@ LLVM_ATTRIBUTE_USED void CompileTest() { V.resize(42); } -// Test fixture class -template <typename VectorT> -class SmallVectorTest : public testing::Test { +class SmallVectorTestBase : public testing::Test { protected: - VectorT theVector; - VectorT otherVector; - - void SetUp() { - Constructable::reset(); - } + void SetUp() override { Constructable::reset(); } + template <typename VectorT> void assertEmpty(VectorT & v) { // Size tests EXPECT_EQ(0u, v.size()); @@ -173,7 +168,8 @@ protected: EXPECT_TRUE(v.begin() == v.end()); } - // Assert that theVector contains the specified values, in order. + // Assert that v contains the specified values, in order. + template <typename VectorT> void assertValuesInOrder(VectorT & v, size_t size, ...) { EXPECT_EQ(size, v.size()); @@ -188,6 +184,7 @@ protected: } // Generate a sequence of values to initialize the vector. + template <typename VectorT> void makeSequence(VectorT & v, int start, int end) { for (int i = start; i <= end; ++i) { v.push_back(Constructable(i)); @@ -195,6 +192,15 @@ protected: } }; +// Test fixture class +template <typename VectorT> +class SmallVectorTest : public SmallVectorTestBase { +protected: + VectorT theVector; + VectorT otherVector; +}; + + typedef ::testing::Types<SmallVector<Constructable, 0>, SmallVector<Constructable, 1>, SmallVector<Constructable, 2>, @@ -664,6 +670,67 @@ TYPED_TEST(SmallVectorTest, IteratorTest) { this->theVector.insert(this->theVector.end(), L.begin(), L.end()); } +template <typename InvalidType> class DualSmallVectorsTest; + +template <typename VectorT1, typename VectorT2> +class DualSmallVectorsTest<std::pair<VectorT1, VectorT2>> : public SmallVectorTestBase { +protected: + VectorT1 theVector; + VectorT2 otherVector; + + template <typename T, unsigned N> + static unsigned NumBuiltinElts(const SmallVector<T, N>&) { return N; } +}; + +typedef ::testing::Types< + // Small mode -> Small mode. + std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 4>>, + // Small mode -> Big mode. + std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 2>>, + // Big mode -> Small mode. + std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 4>>, + // Big mode -> Big mode. + std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 2>> + > DualSmallVectorTestTypes; + +TYPED_TEST_CASE(DualSmallVectorsTest, DualSmallVectorTestTypes); + +TYPED_TEST(DualSmallVectorsTest, MoveAssignment) { + SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); + + // Set up our vector with four elements. + for (unsigned I = 0; I < 4; ++I) + this->otherVector.push_back(Constructable(I)); + + const Constructable *OrigDataPtr = this->otherVector.data(); + + // Move-assign from the other vector. + this->theVector = + std::move(static_cast<SmallVectorImpl<Constructable>&>(this->otherVector)); + + // Make sure we have the right result. + this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); + + // Make sure the # of constructor/destructor calls line up. There + // are two live objects after clearing the other vector. + this->otherVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls()-4, + Constructable::getNumDestructorCalls()); + + // If the source vector (otherVector) was in small-mode, assert that we just + // moved the data pointer over. + EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || + this->theVector.data() == OrigDataPtr); + + // There shouldn't be any live objects any more. + this->theVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls(), + Constructable::getNumDestructorCalls()); + + // We shouldn't have copied anything in this whole process. + EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); +} + struct notassignable { int &x; notassignable(int &x) : x(x) {} @@ -717,8 +784,8 @@ template <int I> struct EmplaceableArg { explicit EmplaceableArg(bool) : State(EAS_Arg) {} private: - EmplaceableArg &operator=(EmplaceableArg &&) LLVM_DELETED_FUNCTION; - EmplaceableArg &operator=(const EmplaceableArg &) LLVM_DELETED_FUNCTION; + EmplaceableArg &operator=(EmplaceableArg &&) = delete; + EmplaceableArg &operator=(const EmplaceableArg &) = delete; }; enum EmplaceableState { ES_Emplaced, ES_Moved }; @@ -758,8 +825,8 @@ struct Emplaceable { } private: - Emplaceable(const Emplaceable &) LLVM_DELETED_FUNCTION; - Emplaceable &operator=(const Emplaceable &) LLVM_DELETED_FUNCTION; + Emplaceable(const Emplaceable &) = delete; + Emplaceable &operator=(const Emplaceable &) = delete; }; TEST(SmallVectorTest, EmplaceBack) { @@ -827,6 +894,32 @@ TEST(SmallVectorTest, EmplaceBack) { EXPECT_TRUE(V.back().A2.State == EAS_RValue); EXPECT_TRUE(V.back().A3.State == EAS_LValue); } + { + SmallVector<int, 1> V; + V.emplace_back(); + V.emplace_back(42); + EXPECT_EQ(2U, V.size()); + EXPECT_EQ(0, V[0]); + EXPECT_EQ(42, V[1]); + } +} + +TEST(SmallVectorTest, InitializerList) { + SmallVector<int, 2> V1 = {}; + EXPECT_TRUE(V1.empty()); + V1 = {0, 0}; + EXPECT_TRUE(makeArrayRef(V1).equals({0, 0})); + V1 = {-1, -1}; + EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1})); + + SmallVector<int, 2> V2 = {1, 2, 3, 4}; + EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4})); + V2.assign({4}); + EXPECT_TRUE(makeArrayRef(V2).equals({4})); + V2.append({3, 2}); + EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2})); + V2.insert(V2.begin() + 1, 5); + EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2})); } } // end namespace diff --git a/unittests/ADT/StringMapTest.cpp b/unittests/ADT/StringMapTest.cpp index 33d668fe2ddf9..4ed0b76f0f41a 100644 --- a/unittests/ADT/StringMapTest.cpp +++ b/unittests/ADT/StringMapTest.cpp @@ -244,7 +244,7 @@ TEST_F(StringMapTest, InsertRehashingPairTest) { // Create a non-default constructable value struct StringMapTestStruct { StringMapTestStruct(int i) : i(i) {} - StringMapTestStruct() LLVM_DELETED_FUNCTION; + StringMapTestStruct() = delete; int i; }; @@ -258,7 +258,7 @@ TEST_F(StringMapTest, NonDefaultConstructable) { struct Immovable { Immovable() {} - Immovable(Immovable&&) LLVM_DELETED_FUNCTION; // will disable the other special members + Immovable(Immovable&&) = delete; // will disable the other special members }; struct MoveOnly { @@ -272,8 +272,8 @@ struct MoveOnly { } private: - MoveOnly(const MoveOnly &) LLVM_DELETED_FUNCTION; - MoveOnly &operator=(const MoveOnly &) LLVM_DELETED_FUNCTION; + MoveOnly(const MoveOnly &) = delete; + MoveOnly &operator=(const MoveOnly &) = delete; }; TEST_F(StringMapTest, MoveOnly) { diff --git a/unittests/ADT/TinyPtrVectorTest.cpp b/unittests/ADT/TinyPtrVectorTest.cpp index a402e8be9df6d..294dfac0c6336 100644 --- a/unittests/ADT/TinyPtrVectorTest.cpp +++ b/unittests/ADT/TinyPtrVectorTest.cpp @@ -438,3 +438,24 @@ TEST(TinyPtrVectorTest, ArrayRefCtorTest) { EXPECT_TRUE(V[i] == data[i]); } } + +TEST(TinyPtrVectorTest, MutableArrayRefTest) { + int data_array[128]; + std::vector<int *> data; + + for (unsigned i = 0, e = 128; i != e; ++i) { + data_array[i] = 324 - int(i); + data.push_back(&data_array[i]); + } + + TinyPtrVector<int *> V(data); + EXPECT_TRUE(V.size() == 128); + EXPECT_FALSE(V.empty()); + + MutableArrayRef<int *> mut_array = V; + for (unsigned i = 0, e = 128; i != e; ++i) { + EXPECT_TRUE(mut_array[i] == data[i]); + mut_array[i] = 324 + mut_array[i]; + EXPECT_TRUE(mut_array[i] == (324 + data[i])); + } +} diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp index 1f9aa32aeab01..b0f01b26e7229 100644 --- a/unittests/ADT/TripleTest.cpp +++ b/unittests/ADT/TripleTest.cpp @@ -129,6 +129,18 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::UnknownOS, T.getOS()); EXPECT_EQ(Triple::EABI, T.getEnvironment()); + T = Triple("armv6hl-none-linux-gnueabi"); + EXPECT_EQ(Triple::arm, T.getArch()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::GNUEABI, T.getEnvironment()); + + T = Triple("armv7hl-none-linux-gnueabi"); + EXPECT_EQ(Triple::arm, T.getArch()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::GNUEABI, T.getEnvironment()); + T = Triple("amdil-unknown-unknown"); EXPECT_EQ(Triple::amdil, T.getArch()); EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); @@ -149,6 +161,11 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); EXPECT_EQ(Triple::UnknownOS, T.getOS()); + T = Triple("sparcel-unknown-unknown"); + EXPECT_EQ(Triple::sparcel, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::UnknownOS, T.getOS()); + T = Triple("spir-unknown-unknown"); EXPECT_EQ(Triple::spir, T.getArch()); EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); @@ -159,6 +176,12 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); EXPECT_EQ(Triple::UnknownOS, T.getOS()); + T = Triple("x86_64-unknown-cloudabi"); + EXPECT_EQ(Triple::x86_64, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::CloudABI, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("huh"); EXPECT_EQ(Triple::UnknownArch, T.getArch()); } @@ -214,12 +237,12 @@ TEST(TripleTest, Normalization) { // Check that normalizing a permutated set of valid components returns a // triple with the unpermuted components. StringRef C[4]; - for (int Arch = 1+Triple::UnknownArch; Arch <= Triple::amdil; ++Arch) { + for (int Arch = 1+Triple::UnknownArch; Arch <= Triple::LastArchType; ++Arch) { C[0] = Triple::getArchTypeName(Triple::ArchType(Arch)); - for (int Vendor = 1+Triple::UnknownVendor; Vendor <= Triple::PC; + for (int Vendor = 1+Triple::UnknownVendor; Vendor <= Triple::LastVendorType; ++Vendor) { C[1] = Triple::getVendorTypeName(Triple::VendorType(Vendor)); - for (int OS = 1+Triple::UnknownOS; OS <= Triple::Minix; ++OS) { + for (int OS = 1+Triple::UnknownOS; OS <= Triple::LastOSType; ++OS) { if (OS == Triple::Win32) continue; @@ -234,7 +257,7 @@ TEST(TripleTest, Normalization) { EXPECT_EQ(E, Triple::normalize(Join(C[2], C[0], C[1]))); EXPECT_EQ(E, Triple::normalize(Join(C[2], C[1], C[0]))); - for (int Env = 1 + Triple::UnknownEnvironment; Env <= Triple::Android; + for (int Env = 1 + Triple::UnknownEnvironment; Env <= Triple::LastEnvironmentType; ++Env) { C[3] = Triple::getEnvironmentTypeName(Triple::EnvironmentType(Env)); @@ -401,6 +424,21 @@ TEST(TripleTest, BitWidthPredicates) { EXPECT_FALSE(T.isArch16Bit()); EXPECT_FALSE(T.isArch32Bit()); EXPECT_TRUE(T.isArch64Bit()); + + T.setArch(Triple::sparc); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_TRUE(T.isArch32Bit()); + EXPECT_FALSE(T.isArch64Bit()); + + T.setArch(Triple::sparcel); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_TRUE(T.isArch32Bit()); + EXPECT_FALSE(T.isArch64Bit()); + + T.setArch(Triple::sparcv9); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_FALSE(T.isArch32Bit()); + EXPECT_TRUE(T.isArch64Bit()); } TEST(TripleTest, BitWidthArchVariants) { @@ -650,20 +688,177 @@ TEST(TripleTest, NormalizeWindows) { } TEST(TripleTest, getARMCPUForArch) { + // Standard ARM Architectures. + { + llvm::Triple Triple("armv4-unknown-eabi"); + EXPECT_STREQ("strongarm", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv4t-unknown-eabi"); + EXPECT_STREQ("arm7tdmi", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv5-unknown-eabi"); + EXPECT_STREQ("arm10tdmi", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv5t-unknown-eabi"); + EXPECT_STREQ("arm10tdmi", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv5e-unknown-eabi"); + EXPECT_STREQ("arm1022e", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv5tej-unknown-eabi"); + EXPECT_STREQ("arm926ej-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6-unknown-eabi"); + EXPECT_STREQ("arm1136jf-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6j-unknown-eabi"); + EXPECT_STREQ("arm1136j-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6k-unknown-eabi"); + EXPECT_STREQ("arm1176jzf-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6zk-unknown-eabi"); + EXPECT_STREQ("arm1176jzf-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6t2-unknown-eabi"); + EXPECT_STREQ("arm1156t2-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6m-unknown-eabi"); + EXPECT_STREQ("cortex-m0", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7-unknown-eabi"); + EXPECT_STREQ("cortex-a8", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7a-unknown-eabi"); + EXPECT_STREQ("cortex-a8", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7m-unknown-eabi"); + EXPECT_STREQ("cortex-m3", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7r-unknown-eabi"); + EXPECT_STREQ("cortex-r4", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7r-unknown-eabi"); + EXPECT_STREQ("cortex-r4", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7r-unknown-eabi"); + EXPECT_STREQ("cortex-r4", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7r-unknown-eabi"); + EXPECT_STREQ("cortex-r4", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv8a-unknown-eabi"); + EXPECT_STREQ("cortex-a53", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv8.1a-unknown-eabi"); + EXPECT_STREQ("generic", Triple.getARMCPUForArch()); + } + // Non-synonym names, using -march style, not default arch. + { + llvm::Triple Triple("arm"); + EXPECT_STREQ("cortex-a8", Triple.getARMCPUForArch("armv7-a")); + } + { + llvm::Triple Triple("arm"); + EXPECT_STREQ("cortex-m3", Triple.getARMCPUForArch("armv7-m")); + } + { + llvm::Triple Triple("arm"); + EXPECT_STREQ("cortex-a53", Triple.getARMCPUForArch("armv8")); + } + { + llvm::Triple Triple("arm"); + EXPECT_STREQ("cortex-a53", Triple.getARMCPUForArch("armv8-a")); + } + // Platform specific defaults. + { + llvm::Triple Triple("arm--nacl"); + EXPECT_STREQ("cortex-a8", Triple.getARMCPUForArch()); + } { llvm::Triple Triple("armv6-unknown-freebsd"); EXPECT_STREQ("arm1176jzf-s", Triple.getARMCPUForArch()); } { + llvm::Triple Triple("arm--win32"); + EXPECT_STREQ("cortex-a9", Triple.getARMCPUForArch()); + } + // Some alternative architectures + { + llvm::Triple Triple("xscale-unknown-eabi"); + EXPECT_STREQ("xscale", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("iwmmxt-unknown-eabi"); + EXPECT_STREQ("iwmmxt", Triple.getARMCPUForArch()); + } + { llvm::Triple Triple("armv7s-apple-ios7"); EXPECT_STREQ("swift", Triple.getARMCPUForArch()); } { - llvm::Triple Triple("armv7-apple-ios7"); + llvm::Triple Triple("armv7em-apple-ios7"); + EXPECT_STREQ("cortex-m4", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv7l-linux-gnueabihf"); EXPECT_STREQ("cortex-a8", Triple.getARMCPUForArch()); - EXPECT_STREQ("swift", Triple.getARMCPUForArch("armv7s")); } -} + { + llvm::Triple Triple("armv6sm-apple-ios7"); + EXPECT_STREQ("cortex-m0", Triple.getARMCPUForArch()); + } + // armeb is permitted, but armebeb is not + { + llvm::Triple Triple("armeb-none-eabi"); + EXPECT_STREQ("arm7tdmi", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armebeb-none-eabi"); + EXPECT_EQ(nullptr, Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armebv6eb-none-eabi"); + EXPECT_EQ(nullptr, Triple.getARMCPUForArch()); + } + // armebv6 and armv6eb are permitted, but armebv6eb is not + { + llvm::Triple Triple("armebv6-non-eabi"); + EXPECT_STREQ("arm1136jf-s", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armv6eb-none-eabi"); + EXPECT_STREQ("arm1136jf-s", Triple.getARMCPUForArch()); + } + // xscaleeb is permitted, but armebxscale is not + { + llvm::Triple Triple("xscaleeb-none-eabi"); + EXPECT_STREQ("xscale", Triple.getARMCPUForArch()); + } + { + llvm::Triple Triple("armebxscale-none-eabi"); + EXPECT_EQ(nullptr, Triple.getARMCPUForArch()); + } } TEST(TripleTest, NormalizeARM) { @@ -682,3 +877,90 @@ TEST(TripleTest, NormalizeARM) { T = Triple("armv6eb--netbsd-eabi"); EXPECT_EQ(Triple::armeb, T.getArch()); } + +TEST(TripleTest, ParseARMArch) { + // ARM + { + Triple T = Triple("arm"); + EXPECT_EQ(Triple::arm, T.getArch()); + } + { + Triple T = Triple("armv6t2"); + EXPECT_EQ(Triple::arm, T.getArch()); + } + { + Triple T = Triple("armv8"); + EXPECT_EQ(Triple::arm, T.getArch()); + } + { + Triple T = Triple("armeb"); + EXPECT_EQ(Triple::armeb, T.getArch()); + } + { + Triple T = Triple("armv5eb"); + EXPECT_EQ(Triple::armeb, T.getArch()); + } + { + Triple T = Triple("armebv7m"); + EXPECT_EQ(Triple::armeb, T.getArch()); + } + { + Triple T = Triple("armv7eb"); + EXPECT_EQ(Triple::armeb, T.getArch()); + } + // THUMB + { + Triple T = Triple("thumb"); + EXPECT_EQ(Triple::thumb, T.getArch()); + } + { + Triple T = Triple("thumbv7a"); + EXPECT_EQ(Triple::thumb, T.getArch()); + } + { + Triple T = Triple("thumbeb"); + EXPECT_EQ(Triple::thumbeb, T.getArch()); + } + { + Triple T = Triple("thumbv4teb"); + EXPECT_EQ(Triple::thumbeb, T.getArch()); + } + { + Triple T = Triple("thumbebv7"); + EXPECT_EQ(Triple::thumbeb, T.getArch()); + } + { + Triple T = Triple("armv6m"); + EXPECT_EQ(Triple::thumb, T.getArch()); + } + { + Triple T = Triple("thumbv2"); + EXPECT_EQ(Triple::UnknownArch, T.getArch()); + } + { + Triple T = Triple("thumbebv6eb"); + EXPECT_EQ(Triple::UnknownArch, T.getArch()); + } + // AARCH64 + { + Triple T = Triple("arm64"); + EXPECT_EQ(Triple::aarch64, T.getArch()); + } + { + Triple T = Triple("aarch64"); + EXPECT_EQ(Triple::aarch64, T.getArch()); + } + { + Triple T = Triple("aarch64_be"); + EXPECT_EQ(Triple::aarch64_be, T.getArch()); + } + { + Triple T = Triple("aarch64be"); + EXPECT_EQ(Triple::UnknownArch, T.getArch()); + } + { + Triple T = Triple("arm64be"); + EXPECT_EQ(Triple::UnknownArch, T.getArch()); + } +} +} // end anonymous namespace diff --git a/unittests/ADT/TwineTest.cpp b/unittests/ADT/TwineTest.cpp index 39d3b561b6689..9683e97511b6c 100644 --- a/unittests/ADT/TwineTest.cpp +++ b/unittests/ADT/TwineTest.cpp @@ -29,6 +29,7 @@ TEST(TwineTest, Construction) { EXPECT_EQ("hi", Twine(StringRef("hi")).str()); EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str()); EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str()); + EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str()); } TEST(TwineTest, Numbers) { @@ -62,6 +63,10 @@ TEST(TwineTest, Concat) { repr(Twine("hi").concat(Twine()))); EXPECT_EQ("(Twine cstring:\"hi\" empty)", repr(Twine().concat(Twine("hi")))); + EXPECT_EQ("(Twine smallstring:\"hi\" empty)", + repr(Twine().concat(Twine(SmallString<5>("hi"))))); + EXPECT_EQ("(Twine smallstring:\"hey\" cstring:\"there\")", + repr(Twine(SmallString<7>("hey")).concat(Twine("there")))); // Concatenation of unary ropes. EXPECT_EQ("(Twine cstring:\"a\" cstring:\"b\")", @@ -72,6 +77,8 @@ TEST(TwineTest, Concat) { repr(Twine("a").concat(Twine("b")).concat(Twine("c")))); EXPECT_EQ("(Twine cstring:\"a\" rope:(Twine cstring:\"b\" cstring:\"c\"))", repr(Twine("a").concat(Twine("b").concat(Twine("c"))))); + EXPECT_EQ("(Twine cstring:\"a\" rope:(Twine smallstring:\"b\" cstring:\"c\"))", + repr(Twine("a").concat(Twine(SmallString<3>("b")).concat(Twine("c"))))); } TEST(TwineTest, toNullTerminatedStringRef) { @@ -79,6 +86,9 @@ TEST(TwineTest, toNullTerminatedStringRef) { EXPECT_EQ(0, *Twine("hello").toNullTerminatedStringRef(storage).end()); EXPECT_EQ(0, *Twine(StringRef("hello")).toNullTerminatedStringRef(storage).end()); + EXPECT_EQ(0, *Twine(SmallString<11>("hello")) + .toNullTerminatedStringRef(storage) + .end()); } // I suppose linking in the entire code generator to add a unit test to check diff --git a/unittests/ADT/ilistTest.cpp b/unittests/ADT/ilistTest.cpp index 44442ebf75adc..9127b05b4b8fd 100644 --- a/unittests/ADT/ilistTest.cpp +++ b/unittests/ADT/ilistTest.cpp @@ -21,7 +21,8 @@ struct Node : ilist_node<Node> { int Value; Node() {} - Node(int _Value) : Value(_Value) {} + Node(int Value) : Value(Value) {} + Node(const Node&) = default; ~Node() { Value = -1; } }; diff --git a/unittests/Analysis/AliasAnalysisTest.cpp b/unittests/Analysis/AliasAnalysisTest.cpp new file mode 100644 index 0000000000000..66ed4637c7ae5 --- /dev/null +++ b/unittests/Analysis/AliasAnalysisTest.cpp @@ -0,0 +1,104 @@ +//===--- AliasAnalysisTest.cpp - Mixed TBAA unit tests --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/CommandLine.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +class AliasAnalysisTest : public testing::Test { +protected: + AliasAnalysisTest() : M("AliasAnalysisTBAATest", C) {} + + // This is going to check that calling getModRefInfo without a location, and + // with a default location, first, doesn't crash, and second, gives the right + // answer. + void CheckModRef(Instruction *I, AliasAnalysis::ModRefResult Result) { + static char ID; + class CheckModRefTestPass : public FunctionPass { + public: + CheckModRefTestPass(Instruction *I, AliasAnalysis::ModRefResult Result) + : FunctionPass(ID), ExpectResult(Result), I(I) {} + static int initialize() { + PassInfo *PI = new PassInfo("CheckModRef testing pass", "", &ID, + nullptr, true, true); + PassRegistry::getPassRegistry()->registerPass(*PI, false); + initializeAliasAnalysisAnalysisGroup(*PassRegistry::getPassRegistry()); + initializeBasicAliasAnalysisPass(*PassRegistry::getPassRegistry()); + return 0; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequiredTransitive<AliasAnalysis>(); + } + bool runOnFunction(Function &) override { + AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); + EXPECT_EQ(AA.getModRefInfo(I, AliasAnalysis::Location()), ExpectResult); + EXPECT_EQ(AA.getModRefInfo(I), ExpectResult); + return false; + } + AliasAnalysis::ModRefResult ExpectResult; + Instruction *I; + }; + static int initialize = CheckModRefTestPass::initialize(); + (void)initialize; + CheckModRefTestPass *P = new CheckModRefTestPass(I, Result); + legacy::PassManager PM; + PM.add(createBasicAliasAnalysisPass()); + PM.add(P); + PM.run(M); + } + + LLVMContext C; + Module M; +}; + +TEST_F(AliasAnalysisTest, getModRefInfo) { + // Setup function. + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false); + auto *F = cast<Function>(M.getOrInsertFunction("f", FTy)); + auto *BB = BasicBlock::Create(C, "entry", F); + auto IntType = Type::getInt32Ty(C); + auto PtrType = Type::getInt32PtrTy(C); + auto *Value = ConstantInt::get(IntType, 42); + auto *Addr = ConstantPointerNull::get(PtrType); + + auto *Store1 = new StoreInst(Value, Addr, BB); + auto *Load1 = new LoadInst(Addr, "load", BB); + auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB); + auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); + auto *CmpXChg1 = new AtomicCmpXchgInst(Addr, ConstantInt::get(IntType, 0), + ConstantInt::get(IntType, 1), + Monotonic, Monotonic, CrossThread, BB); + auto *AtomicRMW = + new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), + Monotonic, CrossThread, BB); + + ReturnInst::Create(C, nullptr, BB); + + // Check basic results + CheckModRef(Store1, AliasAnalysis::ModRefResult::Mod); + CheckModRef(Load1, AliasAnalysis::ModRefResult::Ref); + CheckModRef(Add1, AliasAnalysis::ModRefResult::NoModRef); + CheckModRef(VAArg1, AliasAnalysis::ModRefResult::ModRef); + CheckModRef(CmpXChg1, AliasAnalysis::ModRefResult::ModRef); + CheckModRef(AtomicRMW, AliasAnalysis::ModRefResult::ModRef); +} + +} // end anonymous namspace +} // end llvm namespace diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp index dba9d4991ec58..b29c168ce08b3 100644 --- a/unittests/Analysis/CFGTest.cpp +++ b/unittests/Analysis/CFGTest.cpp @@ -16,7 +16,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" @@ -72,23 +72,23 @@ protected: PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass", "", &ID, nullptr, true, true); PassRegistry::getPassRegistry()->registerPass(*PI, false); - initializeLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry()); initializeDominatorTreeWrapperPassPass( *PassRegistry::getPassRegistry()); return 0; } - void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequired<LoopInfo>(); + AU.addRequired<LoopInfoWrapperPass>(); AU.addRequired<DominatorTreeWrapperPass>(); } - bool runOnFunction(Function &F) { + bool runOnFunction(Function &F) override { if (!F.hasName() || F.getName() != "test") return false; - LoopInfo *LI = &getAnalysis<LoopInfo>(); + LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, nullptr), @@ -107,7 +107,7 @@ protected: IsPotentiallyReachableTestPass *P = new IsPotentiallyReachableTestPass(ExpectedResult, A, B); - PassManager PM; + legacy::PassManager PM; PM.add(P); PM.run(*M); } diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt index baf0c28a8d9cc..35a6d92ce1793 100644 --- a/unittests/Analysis/CMakeLists.txt +++ b/unittests/Analysis/CMakeLists.txt @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(AnalysisTests + AliasAnalysisTest.cpp CallGraphTest.cpp CFGTest.cpp LazyCallGraphTest.cpp diff --git a/unittests/Analysis/MixedTBAATest.cpp b/unittests/Analysis/MixedTBAATest.cpp index d7935e35548ac..7b8a25c443892 100644 --- a/unittests/Analysis/MixedTBAATest.cpp +++ b/unittests/Analysis/MixedTBAATest.cpp @@ -13,7 +13,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/CommandLine.h" #include "gtest/gtest.h" @@ -27,7 +27,7 @@ protected: LLVMContext C; Module M; MDBuilder MD; - PassManager PM; + legacy::PassManager PM; }; TEST_F(MixedTBAATest, MixedTBAA) { diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp index 90f6997e98cda..6ce7ff43a312f 100644 --- a/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/unittests/Analysis/ScalarEvolutionTest.cpp @@ -14,7 +14,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "gtest/gtest.h" namespace llvm { @@ -25,14 +25,14 @@ namespace { class ScalarEvolutionsTest : public testing::Test { protected: ScalarEvolutionsTest() : M("", Context), SE(*new ScalarEvolution) {} - ~ScalarEvolutionsTest() { + ~ScalarEvolutionsTest() override { // Manually clean up, since we allocated new SCEV objects after the // pass was finished. SE.releaseMemory(); } LLVMContext Context; Module M; - PassManager PM; + legacy::PassManager PM; ScalarEvolution &SE; }; diff --git a/unittests/AsmParser/AsmParserTest.cpp b/unittests/AsmParser/AsmParserTest.cpp new file mode 100644 index 0000000000000..8847b18716731 --- /dev/null +++ b/unittests/AsmParser/AsmParserTest.cpp @@ -0,0 +1,47 @@ +//===- llvm/unittest/AsmParser/AsmParserTest.cpp - asm parser unittests ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(AsmParserTest, NullTerminatedInput) { + LLVMContext &Ctx = getGlobalContext(); + StringRef Source = "; Empty module \n"; + SMDiagnostic Error; + auto Mod = parseAssemblyString(Source, Error, Ctx); + + EXPECT_TRUE(Mod != nullptr); + EXPECT_TRUE(Error.getMessage().empty()); +} + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG + +TEST(AsmParserTest, NonNullTerminatedInput) { + LLVMContext &Ctx = getGlobalContext(); + StringRef Source = "; Empty module \n\1\2"; + SMDiagnostic Error; + std::unique_ptr<Module> Mod; + EXPECT_DEATH(Mod = parseAssemblyString(Source.substr(0, Source.size() - 2), + Error, Ctx), + "Buffer is not null terminated!"); +} + +#endif +#endif + +} // end anonymous namespace diff --git a/unittests/AsmParser/CMakeLists.txt b/unittests/AsmParser/CMakeLists.txt new file mode 100644 index 0000000000000..1920bfaa3aac7 --- /dev/null +++ b/unittests/AsmParser/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + AsmParser + Core + Support + ) + +add_llvm_unittest(AsmParserTests + AsmParserTest.cpp + ) diff --git a/unittests/AsmParser/Makefile b/unittests/AsmParser/Makefile new file mode 100644 index 0000000000000..41eadd4304338 --- /dev/null +++ b/unittests/AsmParser/Makefile @@ -0,0 +1,15 @@ +##===- unittests/AsmParser/Makefile ------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = AsmParser +LINK_COMPONENTS := AsmParser Core Support + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Bitcode/BitReaderTest.cpp b/unittests/Bitcode/BitReaderTest.cpp index 1f28ec6f0d6d9..2e6dd0b499dec 100644 --- a/unittests/Bitcode/BitReaderTest.cpp +++ b/unittests/Bitcode/BitReaderTest.cpp @@ -75,13 +75,77 @@ TEST(BitReaderTest, DematerializeFunctionPreservesLinkageType) { GlobalValue::InternalLinkage); // Check that the linkage type is preserved after dematerialization. - M->getFunction("func")->Dematerialize(); + M->getFunction("func")->dematerialize(); EXPECT_TRUE(M->getFunction("func")->empty()); EXPECT_TRUE(M->getFunction("func")->getLinkage() == GlobalValue::InternalLinkage); EXPECT_FALSE(verifyModule(*M, &dbgs())); } +// Tests that lazy evaluation can parse functions out of order. +TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) { + SmallString<1024> Mem; + LLVMContext Context; + std::unique_ptr<Module> M = getLazyModuleFromAssembly( + Context, Mem, "define void @f() {\n" + " unreachable\n" + "}\n" + "define void @g() {\n" + " unreachable\n" + "}\n" + "define void @h() {\n" + " unreachable\n" + "}\n" + "define void @j() {\n" + " unreachable\n" + "}\n"); + EXPECT_FALSE(verifyModule(*M, &dbgs())); + + Function *F = M->getFunction("f"); + Function *G = M->getFunction("g"); + Function *H = M->getFunction("h"); + Function *J = M->getFunction("j"); + + // Initially all functions are not materialized (no basic blocks). + EXPECT_TRUE(F->empty()); + EXPECT_TRUE(G->empty()); + EXPECT_TRUE(H->empty()); + EXPECT_TRUE(J->empty()); + EXPECT_FALSE(verifyModule(*M, &dbgs())); + + // Materialize h. + H->materialize(); + EXPECT_TRUE(F->empty()); + EXPECT_TRUE(G->empty()); + EXPECT_FALSE(H->empty()); + EXPECT_TRUE(J->empty()); + EXPECT_FALSE(verifyModule(*M, &dbgs())); + + // Materialize g. + G->materialize(); + EXPECT_TRUE(F->empty()); + EXPECT_FALSE(G->empty()); + EXPECT_FALSE(H->empty()); + EXPECT_TRUE(J->empty()); + EXPECT_FALSE(verifyModule(*M, &dbgs())); + + // Materialize j. + J->materialize(); + EXPECT_TRUE(F->empty()); + EXPECT_FALSE(G->empty()); + EXPECT_FALSE(H->empty()); + EXPECT_FALSE(J->empty()); + EXPECT_FALSE(verifyModule(*M, &dbgs())); + + // Materialize f. + F->materialize(); + EXPECT_FALSE(F->empty()); + EXPECT_FALSE(G->empty()); + EXPECT_FALSE(H->empty()); + EXPECT_FALSE(J->empty()); + EXPECT_FALSE(verifyModule(*M, &dbgs())); +} + TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677 SmallString<1024> Mem; @@ -96,7 +160,7 @@ TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677 EXPECT_FALSE(verifyModule(*M, &dbgs())); // Try (and fail) to dematerialize @func. - M->getFunction("func")->Dematerialize(); + M->getFunction("func")->dematerialize(); EXPECT_FALSE(M->getFunction("func")->empty()); } @@ -127,7 +191,7 @@ TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionBefore) { EXPECT_FALSE(verifyModule(*M, &dbgs())); // Try (and fail) to dematerialize @func. - M->getFunction("func")->Dematerialize(); + M->getFunction("func")->dematerialize(); EXPECT_FALSE(M->getFunction("func")->empty()); EXPECT_FALSE(verifyModule(*M, &dbgs())); } @@ -159,7 +223,7 @@ TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionAfter) { EXPECT_FALSE(verifyModule(*M, &dbgs())); // Try (and fail) to dematerialize @func. - M->getFunction("func")->Dematerialize(); + M->getFunction("func")->dematerialize(); EXPECT_FALSE(M->getFunction("func")->empty()); EXPECT_FALSE(verifyModule(*M, &dbgs())); } diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 19c2d24534b20..e5befcec6e0f1 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -13,6 +13,7 @@ endfunction() add_subdirectory(ADT) add_subdirectory(Analysis) +add_subdirectory(AsmParser) add_subdirectory(Bitcode) add_subdirectory(CodeGen) add_subdirectory(DebugInfo) @@ -22,5 +23,6 @@ add_subdirectory(LineEditor) add_subdirectory(Linker) add_subdirectory(MC) add_subdirectory(Option) +add_subdirectory(ProfileData) add_subdirectory(Support) add_subdirectory(Transforms) diff --git a/unittests/CodeGen/DIEHashTest.cpp b/unittests/CodeGen/DIEHashTest.cpp index efb0920b179fe..c1b11600252b6 100644 --- a/unittests/CodeGen/DIEHashTest.cpp +++ b/unittests/CodeGen/DIEHashTest.cpp @@ -10,6 +10,7 @@ #include "llvm/CodeGen/DIE.h" #include "../lib/CodeGen/AsmPrinter/DIEHash.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" @@ -18,7 +19,20 @@ using namespace llvm; namespace { -TEST(DIEHashTest, Data1) { + +// Test fixture +class DIEHashTest : public testing::Test { + StringMap<DwarfStringPoolEntry> Pool; + +public: + DIEString getString(StringRef S) { + DwarfStringPoolEntry Entry = {nullptr, 1, 1}; + return DIEString( + DwarfStringPoolEntryRef(*Pool.insert(std::make_pair(S, Entry)).first)); + } +}; + +TEST_F(DIEHashTest, Data1) { DIEHash Hash; DIE Die(dwarf::DW_TAG_base_type); DIEInteger Size(4); @@ -28,7 +42,7 @@ TEST(DIEHashTest, Data1) { } // struct {}; -TEST(DIEHashTest, TrivialType) { +TEST_F(DIEHashTest, TrivialType) { DIE Unnamed(dwarf::DW_TAG_structure_type); DIEInteger One(1); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); @@ -43,10 +57,10 @@ TEST(DIEHashTest, TrivialType) { } // struct foo { }; -TEST(DIEHashTest, NamedType) { +TEST_F(DIEHashTest, NamedType) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger One(1); - DIEString FooStr(&One, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); @@ -57,19 +71,19 @@ TEST(DIEHashTest, NamedType) { } // namespace space { struct foo { }; } -TEST(DIEHashTest, NamespacedType) { +TEST_F(DIEHashTest, NamespacedType) { DIE CU(dwarf::DW_TAG_compile_unit); auto Space = make_unique<DIE>(dwarf::DW_TAG_namespace); DIEInteger One(1); - DIEString SpaceStr(&One, "space"); + DIEString SpaceStr = getString("space"); Space->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &SpaceStr); // DW_AT_declaration is ignored. Space->addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One); // sibling? auto Foo = make_unique<DIE>(dwarf::DW_TAG_structure_type); - DIEString FooStr(&One, "foo"); + DIEString FooStr = getString("foo"); Foo->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); Foo->addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); @@ -84,13 +98,13 @@ TEST(DIEHashTest, NamespacedType) { } // struct { int member; }; -TEST(DIEHashTest, TypeWithMember) { +TEST_F(DIEHashTest, TypeWithMember) { DIE Unnamed(dwarf::DW_TAG_structure_type); DIEInteger Four(4); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); DIE Int(dwarf::DW_TAG_base_type); - DIEString IntStr(&Four, "int"); + DIEString IntStr = getString("int"); Int.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &IntStr); Int.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); DIEInteger Five(5); @@ -99,7 +113,7 @@ TEST(DIEHashTest, TypeWithMember) { DIEEntry IntRef(Int); auto Member = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemberStr(&Four, "member"); + DIEString MemberStr = getString("member"); Member->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemberStr); DIEInteger Zero(0); Member->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, @@ -114,14 +128,14 @@ TEST(DIEHashTest, TypeWithMember) { } // struct foo { int mem1, mem2; }; -TEST(DIEHashTest, ReusedType) { +TEST_F(DIEHashTest, ReusedType) { DIE Unnamed(dwarf::DW_TAG_structure_type); DIEInteger Eight(8); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); DIEInteger Four(4); DIE Int(dwarf::DW_TAG_base_type); - DIEString IntStr(&Four, "int"); + DIEString IntStr = getString("int"); Int.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &IntStr); Int.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); DIEInteger Five(5); @@ -130,7 +144,7 @@ TEST(DIEHashTest, ReusedType) { DIEEntry IntRef(Int); auto Mem1 = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString Mem1Str(&Four, "mem1"); + DIEString Mem1Str = getString("mem1"); Mem1->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &Mem1Str); DIEInteger Zero(0); Mem1->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, @@ -140,7 +154,7 @@ TEST(DIEHashTest, ReusedType) { Unnamed.addChild(std::move(Mem1)); auto Mem2 = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString Mem2Str(&Four, "mem2"); + DIEString Mem2Str = getString("mem2"); Mem2->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &Mem2Str); Mem2->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Four); @@ -154,15 +168,15 @@ TEST(DIEHashTest, ReusedType) { } // struct foo { static foo f; }; -TEST(DIEHashTest, RecursiveType) { +TEST_F(DIEHashTest, RecursiveType) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger One(1); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); - DIEString FooStr(&One, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); auto Mem = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemStr(&One, "mem"); + DIEString MemStr = getString("mem"); Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); DIEEntry FooRef(Foo); Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRef); @@ -176,15 +190,15 @@ TEST(DIEHashTest, RecursiveType) { } // struct foo { foo *mem; }; -TEST(DIEHashTest, Pointer) { +TEST_F(DIEHashTest, Pointer) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger Eight(8); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); - DIEString FooStr(&Eight, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); auto Mem = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemStr(&Eight, "mem"); + DIEString MemStr = getString("mem"); Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); DIEInteger Zero(0); Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); @@ -205,15 +219,15 @@ TEST(DIEHashTest, Pointer) { } // struct foo { foo &mem; }; -TEST(DIEHashTest, Reference) { +TEST_F(DIEHashTest, Reference) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger Eight(8); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); - DIEString FooStr(&Eight, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); auto Mem = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemStr(&Eight, "mem"); + DIEString MemStr = getString("mem"); Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); DIEInteger Zero(0); Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); @@ -238,15 +252,15 @@ TEST(DIEHashTest, Reference) { } // struct foo { foo &&mem; }; -TEST(DIEHashTest, RValueReference) { +TEST_F(DIEHashTest, RValueReference) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger Eight(8); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); - DIEString FooStr(&Eight, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); auto Mem = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemStr(&Eight, "mem"); + DIEString MemStr = getString("mem"); Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); DIEInteger Zero(0); Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); @@ -271,15 +285,15 @@ TEST(DIEHashTest, RValueReference) { } // struct foo { foo foo::*mem; }; -TEST(DIEHashTest, PtrToMember) { +TEST_F(DIEHashTest, PtrToMember) { DIE Foo(dwarf::DW_TAG_structure_type); DIEInteger Eight(8); Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); - DIEString FooStr(&Eight, "foo"); + DIEString FooStr = getString("foo"); Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); auto Mem = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString MemStr(&Eight, "mem"); + DIEString MemStr = getString("mem"); Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); DIEInteger Zero(0); Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); @@ -305,13 +319,13 @@ TEST(DIEHashTest, PtrToMember) { // // struct bar; // { }; // struct foo { bar foo::*mem; }; -TEST(DIEHashTest, PtrToMemberDeclDefMatch) { +TEST_F(DIEHashTest, PtrToMemberDeclDefMatch) { DIEInteger Zero(0); DIEInteger One(1); DIEInteger Eight(8); - DIEString FooStr(&Eight, "foo"); - DIEString BarStr(&Eight, "bar"); - DIEString MemStr(&Eight, "mem"); + DIEString FooStr = getString("foo"); + DIEString BarStr = getString("bar"); + DIEString MemStr = getString("mem"); uint64_t MD5ResDecl; { DIE Bar(dwarf::DW_TAG_structure_type); @@ -378,13 +392,13 @@ TEST(DIEHashTest, PtrToMemberDeclDefMatch) { // // struct bar; // { }; // struct foo { bar bar::*mem; }; -TEST(DIEHashTest, PtrToMemberDeclDefMisMatch) { +TEST_F(DIEHashTest, PtrToMemberDeclDefMisMatch) { DIEInteger Zero(0); DIEInteger One(1); DIEInteger Eight(8); - DIEString FooStr(&Eight, "foo"); - DIEString BarStr(&Eight, "bar"); - DIEString MemStr(&Eight, "mem"); + DIEString FooStr = getString("foo"); + DIEString BarStr = getString("bar"); + DIEString MemStr = getString("mem"); uint64_t MD5ResDecl; { DIE Bar(dwarf::DW_TAG_structure_type); @@ -451,12 +465,12 @@ TEST(DIEHashTest, PtrToMemberDeclDefMisMatch) { // struct { } a; // struct foo { decltype(a) mem; }; -TEST(DIEHashTest, RefUnnamedType) { +TEST_F(DIEHashTest, RefUnnamedType) { DIEInteger Zero(0); DIEInteger One(1); DIEInteger Eight(8); - DIEString FooStr(&Zero, "foo"); - DIEString MemStr(&Zero, "mem"); + DIEString FooStr = getString("foo"); + DIEString MemStr = getString("mem"); DIE Unnamed(dwarf::DW_TAG_structure_type); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); @@ -485,13 +499,13 @@ TEST(DIEHashTest, RefUnnamedType) { } // struct { struct foo { }; }; -TEST(DIEHashTest, NestedType) { +TEST_F(DIEHashTest, NestedType) { DIE Unnamed(dwarf::DW_TAG_structure_type); DIEInteger One(1); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); auto Foo = make_unique<DIE>(dwarf::DW_TAG_structure_type); - DIEString FooStr(&One, "foo"); + DIEString FooStr = getString("foo"); Foo->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); Foo->addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); @@ -504,13 +518,13 @@ TEST(DIEHashTest, NestedType) { } // struct { static void func(); }; -TEST(DIEHashTest, MemberFunc) { +TEST_F(DIEHashTest, MemberFunc) { DIE Unnamed(dwarf::DW_TAG_structure_type); DIEInteger One(1); Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); auto Func = make_unique<DIE>(dwarf::DW_TAG_subprogram); - DIEString FuncStr(&One, "func"); + DIEString FuncStr = getString("func"); Func->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FuncStr); Unnamed.addChild(std::move(Func)); @@ -524,18 +538,18 @@ TEST(DIEHashTest, MemberFunc) { // struct A { // static void func(); // }; -TEST(DIEHashTest, MemberFuncFlag) { +TEST_F(DIEHashTest, MemberFuncFlag) { DIE A(dwarf::DW_TAG_structure_type); DIEInteger One(1); - DIEString AStr(&One, "A"); + DIEString AStr = getString("A"); A.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &AStr); A.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); A.addValue(dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, &One); A.addValue(dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, &One); auto Func = make_unique<DIE>(dwarf::DW_TAG_subprogram); - DIEString FuncStr(&One, "func"); - DIEString FuncLinkage(&One, "_ZN1A4funcEv"); + DIEString FuncStr = getString("func"); + DIEString FuncLinkage = getString("_ZN1A4funcEv"); DIEInteger Two(2); Func->addValue(dwarf::DW_AT_external, dwarf::DW_FORM_flag_present, &One); Func->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FuncStr); @@ -557,10 +571,10 @@ TEST(DIEHashTest, MemberFuncFlag) { // const static int PI = -3; // }; // A a; -TEST(DIEHashTest, MemberSdata) { +TEST_F(DIEHashTest, MemberSdata) { DIE A(dwarf::DW_TAG_structure_type); DIEInteger One(1); - DIEString AStr(&One, "A"); + DIEString AStr = getString("A"); A.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &AStr); A.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); A.addValue(dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, &One); @@ -568,7 +582,7 @@ TEST(DIEHashTest, MemberSdata) { DIEInteger Four(4); DIEInteger Five(5); - DIEString FStr(&One, "int"); + DIEString FStr = getString("int"); DIE IntTyDIE(dwarf::DW_TAG_base_type); IntTyDIE.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); IntTyDIE.addValue(dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, &Five); @@ -580,7 +594,7 @@ TEST(DIEHashTest, MemberSdata) { DIEEntry PITy(*PITyDIE); auto PI = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString PIStr(&One, "PI"); + DIEString PIStr = getString("PI"); DIEInteger Two(2); DIEInteger NegThree(-3); PI->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &PIStr); @@ -602,17 +616,17 @@ TEST(DIEHashTest, MemberSdata) { // const static float PI = 3.14; // }; // A a; -TEST(DIEHashTest, MemberBlock) { +TEST_F(DIEHashTest, MemberBlock) { DIE A(dwarf::DW_TAG_structure_type); DIEInteger One(1); - DIEString AStr(&One, "A"); + DIEString AStr = getString("A"); A.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &AStr); A.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); A.addValue(dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, &One); A.addValue(dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, &One); DIEInteger Four(4); - DIEString FStr(&One, "float"); + DIEString FStr = getString("float"); auto FloatTyDIE = make_unique<DIE>(dwarf::DW_TAG_base_type); FloatTyDIE->addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); FloatTyDIE->addValue(dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, &Four); @@ -624,7 +638,7 @@ TEST(DIEHashTest, MemberBlock) { DIEEntry PITy(*PITyDIE); auto PI = make_unique<DIE>(dwarf::DW_TAG_member); - DIEString PIStr(&One, "PI"); + DIEString PIStr = getString("PI"); DIEInteger Two(2); PI->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &PIStr); PI->addValue(dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, &One); diff --git a/unittests/DebugInfo/CMakeLists.txt b/unittests/DebugInfo/CMakeLists.txt index e844e95251ab2..dae472bafdd71 100644 --- a/unittests/DebugInfo/CMakeLists.txt +++ b/unittests/DebugInfo/CMakeLists.txt @@ -1,11 +1,3 @@ -set(LLVM_LINK_COMPONENTS - DebugInfo - ) -set(DebugInfoSources - DWARFFormValueTest.cpp - ) - -add_llvm_unittest(DebugInfoTests - ${DebugInfoSources} - ) +add_subdirectory(DWARF) +add_subdirectory(PDB) diff --git a/unittests/DebugInfo/DWARF/CMakeLists.txt b/unittests/DebugInfo/DWARF/CMakeLists.txt new file mode 100644 index 0000000000000..4bec17cbb524c --- /dev/null +++ b/unittests/DebugInfo/DWARF/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoDWARF + ) + +set(DebugInfoSources + DWARFFormValueTest.cpp + ) + +add_llvm_unittest(DebugInfoDWARFTests + ${DebugInfoSources} + ) diff --git a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp new file mode 100644 index 0000000000000..371e2af95decf --- /dev/null +++ b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp @@ -0,0 +1,124 @@ +//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" +#include "gtest/gtest.h" +#include <climits> +using namespace llvm; +using namespace dwarf; + +namespace { + +TEST(DWARFFormValue, FixedFormSizes) { + // Size of DW_FORM_addr and DW_FORM_ref_addr are equal in DWARF2, + // DW_FORM_ref_addr is always 4 bytes in DWARF32 starting from DWARF3. + ArrayRef<uint8_t> sizes = DWARFFormValue::getFixedFormSizes(4, 2); + EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); + sizes = DWARFFormValue::getFixedFormSizes(8, 2); + EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); + sizes = DWARFFormValue::getFixedFormSizes(8, 3); + EXPECT_EQ(4, sizes[DW_FORM_ref_addr]); + // Check that we don't have fixed form sizes for weird address sizes. + EXPECT_EQ(0U, DWARFFormValue::getFixedFormSizes(16, 2).size()); +} + +bool isFormClass(uint16_t Form, DWARFFormValue::FormClass FC) { + return DWARFFormValue(Form).isFormClass(FC); +} + +TEST(DWARFFormValue, FormClass) { + EXPECT_TRUE(isFormClass(DW_FORM_addr, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Constant)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE( + isFormClass(DW_FORM_sec_offset, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_str_index, DWARFFormValue::FC_String)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_addr_index, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Reference)); + EXPECT_TRUE(isFormClass(DW_FORM_ref_sig8, DWARFFormValue::FC_Reference)); +} + +template<typename RawTypeT> +DWARFFormValue createDataXFormValue(uint16_t Form, RawTypeT Value) { + char Raw[sizeof(RawTypeT)]; + memcpy(Raw, &Value, sizeof(RawTypeT)); + uint32_t Offset = 0; + DWARFFormValue Result(Form); + DataExtractor Data(StringRef(Raw, sizeof(RawTypeT)), + sys::IsLittleEndianHost, sizeof(void*)); + Result.extractValue(Data, &Offset, nullptr); + return Result; +} + +DWARFFormValue createULEBFormValue(uint64_t Value) { + SmallString<10> RawData; + raw_svector_ostream OS(RawData); + encodeULEB128(Value, OS); + uint32_t Offset = 0; + DWARFFormValue Result(DW_FORM_udata); + DataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void*)); + Result.extractValue(Data, &Offset, nullptr); + return Result; +} + +DWARFFormValue createSLEBFormValue(int64_t Value) { + SmallString<10> RawData; + raw_svector_ostream OS(RawData); + encodeSLEB128(Value, OS); + uint32_t Offset = 0; + DWARFFormValue Result(DW_FORM_sdata); + DataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void*)); + Result.extractValue(Data, &Offset, nullptr); + return Result; +} + +TEST(DWARFFormValue, SignedConstantForms) { + // Check that we correctly sign extend fixed size forms. + auto Sign1 = createDataXFormValue<uint8_t>(DW_FORM_data1, -123); + auto Sign2 = createDataXFormValue<uint16_t>(DW_FORM_data2, -12345); + auto Sign4 = createDataXFormValue<uint32_t>(DW_FORM_data4, -123456789); + auto Sign8 = createDataXFormValue<uint64_t>(DW_FORM_data8, -1); + EXPECT_EQ(Sign1.getAsSignedConstant().getValue(), -123); + EXPECT_EQ(Sign2.getAsSignedConstant().getValue(), -12345); + EXPECT_EQ(Sign4.getAsSignedConstant().getValue(), -123456789); + EXPECT_EQ(Sign8.getAsSignedConstant().getValue(), -1); + + // Check that we can handle big positive values, but that we return + // an error just over the limit. + auto UMax = createULEBFormValue(LLONG_MAX); + auto TooBig = createULEBFormValue(uint64_t(LLONG_MAX) + 1); + EXPECT_EQ(UMax.getAsSignedConstant().getValue(), LLONG_MAX); + EXPECT_EQ(TooBig.getAsSignedConstant().hasValue(), false); + + // Sanity check some other forms. + auto Data1 = createDataXFormValue<uint8_t>(DW_FORM_data1, 120); + auto Data2 = createDataXFormValue<uint16_t>(DW_FORM_data2, 32000); + auto Data4 = createDataXFormValue<uint32_t>(DW_FORM_data4, 2000000000); + auto Data8 = createDataXFormValue<uint64_t>(DW_FORM_data8, 0x1234567812345678LL); + auto LEBMin = createSLEBFormValue(LLONG_MIN); + auto LEBMax = createSLEBFormValue(LLONG_MAX); + auto LEB1 = createSLEBFormValue(-42); + auto LEB2 = createSLEBFormValue(42); + EXPECT_EQ(Data1.getAsSignedConstant().getValue(), 120); + EXPECT_EQ(Data2.getAsSignedConstant().getValue(), 32000); + EXPECT_EQ(Data4.getAsSignedConstant().getValue(), 2000000000); + EXPECT_EQ(Data8.getAsSignedConstant().getValue(), 0x1234567812345678LL); + EXPECT_EQ(LEBMin.getAsSignedConstant().getValue(), LLONG_MIN); + EXPECT_EQ(LEBMax.getAsSignedConstant().getValue(), LLONG_MAX); + EXPECT_EQ(LEB1.getAsSignedConstant().getValue(), -42); + EXPECT_EQ(LEB2.getAsSignedConstant().getValue(), 42); +} + +} // end anonymous namespace diff --git a/unittests/DebugInfo/DWARF/Makefile b/unittests/DebugInfo/DWARF/Makefile new file mode 100644 index 0000000000000..b0f40e1ca9d94 --- /dev/null +++ b/unittests/DebugInfo/DWARF/Makefile @@ -0,0 +1,16 @@ +##===- unittests/DebugInfo/Makefile ------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TESTNAME = DebugInfoDWARF +LINK_COMPONENTS := DebugInfoDWARF object support + +include $(LEVEL)/Makefile.config + +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/DebugInfo/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARFFormValueTest.cpp deleted file mode 100644 index 38b932e3c9caf..0000000000000 --- a/unittests/DebugInfo/DWARFFormValueTest.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARFFormValue.h" -#include "llvm/Support/Dwarf.h" -#include "gtest/gtest.h" -using namespace llvm; -using namespace dwarf; - -namespace { - -TEST(DWARFFormValue, FixedFormSizes) { - // Size of DW_FORM_addr and DW_FORM_ref_addr are equal in DWARF2, - // DW_FORM_ref_addr is always 4 bytes in DWARF32 starting from DWARF3. - ArrayRef<uint8_t> sizes = DWARFFormValue::getFixedFormSizes(4, 2); - EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); - sizes = DWARFFormValue::getFixedFormSizes(8, 2); - EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); - sizes = DWARFFormValue::getFixedFormSizes(8, 3); - EXPECT_EQ(4, sizes[DW_FORM_ref_addr]); - // Check that we don't have fixed form sizes for weird address sizes. - EXPECT_EQ(0U, DWARFFormValue::getFixedFormSizes(16, 2).size()); -} - -bool isFormClass(uint16_t Form, DWARFFormValue::FormClass FC) { - return DWARFFormValue(Form).isFormClass(FC); -} - -TEST(DWARFFormValue, FormClass) { - EXPECT_TRUE(isFormClass(DW_FORM_addr, DWARFFormValue::FC_Address)); - EXPECT_FALSE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Address)); - EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Constant)); - EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_SectionOffset)); - EXPECT_TRUE( - isFormClass(DW_FORM_sec_offset, DWARFFormValue::FC_SectionOffset)); - EXPECT_TRUE(isFormClass(DW_FORM_GNU_str_index, DWARFFormValue::FC_String)); - EXPECT_TRUE(isFormClass(DW_FORM_GNU_addr_index, DWARFFormValue::FC_Address)); - EXPECT_FALSE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Address)); - EXPECT_TRUE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Reference)); - EXPECT_TRUE(isFormClass(DW_FORM_ref_sig8, DWARFFormValue::FC_Reference)); -} - -} // end anonymous namespace diff --git a/unittests/DebugInfo/Makefile b/unittests/DebugInfo/Makefile index 999ded90b0f68..1889ad22db113 100644 --- a/unittests/DebugInfo/Makefile +++ b/unittests/DebugInfo/Makefile @@ -6,11 +6,10 @@ # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## - LEVEL = ../.. -TESTNAME = DebugInfo -LINK_COMPONENTS := debuginfo object support include $(LEVEL)/Makefile.config +PARALLEL_DIRS := DWARF PDB + include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt new file mode 100644 index 0000000000000..91924a5a87544 --- /dev/null +++ b/unittests/DebugInfo/PDB/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoPDB + ) + +set(DebugInfoPDBSources + PDBApiTest.cpp + ) + +add_llvm_unittest(DebugInfoPDBTests + ${DebugInfoPDBSources} + ) diff --git a/unittests/DebugInfo/PDB/Makefile b/unittests/DebugInfo/PDB/Makefile new file mode 100644 index 0000000000000..eb118a3fd2bd1 --- /dev/null +++ b/unittests/DebugInfo/PDB/Makefile @@ -0,0 +1,16 @@ +##===- unittests/DebugInfo/PDB/Makefile -------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TESTNAME = DebugInfoPDB +LINK_COMPONENTS := DebugInfoPDB support + +include $(LEVEL)/Makefile.config + +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/DebugInfo/PDB/PDBApiTest.cpp b/unittests/DebugInfo/PDB/PDBApiTest.cpp new file mode 100644 index 0000000000000..ebd3d7bb6b3ca --- /dev/null +++ b/unittests/DebugInfo/PDB/PDBApiTest.cpp @@ -0,0 +1,397 @@ +//===- llvm/unittest/DebugInfo/PDB/PDBApiTest.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <unordered_map> + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" + +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +#define MOCK_SYMBOL_ACCESSOR(Func) \ + decltype(std::declval<IPDBRawSymbol>().Func()) Func() const override { \ + typedef decltype(IPDBRawSymbol::Func()) ReturnType; \ + return ReturnType(); \ + } + +class MockSession : public IPDBSession { + uint64_t getLoadAddress() const override { return 0; } + void setLoadAddress(uint64_t Address) override {} + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override { + return nullptr; + } + std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override { + return nullptr; + } + std::unique_ptr<IPDBSourceFile> + getSourceFileById(uint32_t SymbolId) const override { + return nullptr; + } + + std::unique_ptr<PDBSymbol> + findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override { + return nullptr; + } + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override { + return nullptr; + } + + std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override { + return nullptr; + } + std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const override { + return nullptr; + } + + std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override { + return nullptr; + } +}; + +class MockRawSymbol : public IPDBRawSymbol { +public: + MockRawSymbol(PDB_SymType SymType) + : Type(SymType) {} + + void dump(raw_ostream &OS, int Indent) const override {} + + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type) const override { + return nullptr; + } + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const override { + return nullptr; + } + std::unique_ptr<IPDBEnumSymbols> + findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, + uint32_t RVA) const override { + return nullptr; + } + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByRVA(uint32_t RVA) const override { + return nullptr; + } + + void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const override {} + void getFrontEndVersion(VersionInfo &Version) const override {} + void getBackEndVersion(VersionInfo &Version) const override {} + + PDB_SymType getSymTag() const override { return Type; } + + MOCK_SYMBOL_ACCESSOR(getAccess) + MOCK_SYMBOL_ACCESSOR(getAddressOffset) + MOCK_SYMBOL_ACCESSOR(getAddressSection) + MOCK_SYMBOL_ACCESSOR(getAge) + MOCK_SYMBOL_ACCESSOR(getArrayIndexTypeId) + MOCK_SYMBOL_ACCESSOR(getBaseDataOffset) + MOCK_SYMBOL_ACCESSOR(getBaseDataSlot) + MOCK_SYMBOL_ACCESSOR(getBaseSymbolId) + MOCK_SYMBOL_ACCESSOR(getBuiltinType) + MOCK_SYMBOL_ACCESSOR(getBitPosition) + MOCK_SYMBOL_ACCESSOR(getCallingConvention) + MOCK_SYMBOL_ACCESSOR(getClassParentId) + MOCK_SYMBOL_ACCESSOR(getCompilerName) + MOCK_SYMBOL_ACCESSOR(getCount) + MOCK_SYMBOL_ACCESSOR(getCountLiveRanges) + MOCK_SYMBOL_ACCESSOR(getLanguage) + MOCK_SYMBOL_ACCESSOR(getLexicalParentId) + MOCK_SYMBOL_ACCESSOR(getLibraryName) + MOCK_SYMBOL_ACCESSOR(getLiveRangeStartAddressOffset) + MOCK_SYMBOL_ACCESSOR(getLiveRangeStartAddressSection) + MOCK_SYMBOL_ACCESSOR(getLiveRangeStartRelativeVirtualAddress) + MOCK_SYMBOL_ACCESSOR(getLocalBasePointerRegisterId) + MOCK_SYMBOL_ACCESSOR(getLowerBoundId) + MOCK_SYMBOL_ACCESSOR(getMemorySpaceKind) + MOCK_SYMBOL_ACCESSOR(getName) + MOCK_SYMBOL_ACCESSOR(getNumberOfAcceleratorPointerTags) + MOCK_SYMBOL_ACCESSOR(getNumberOfColumns) + MOCK_SYMBOL_ACCESSOR(getNumberOfModifiers) + MOCK_SYMBOL_ACCESSOR(getNumberOfRegisterIndices) + MOCK_SYMBOL_ACCESSOR(getNumberOfRows) + MOCK_SYMBOL_ACCESSOR(getObjectFileName) + MOCK_SYMBOL_ACCESSOR(getOemId) + MOCK_SYMBOL_ACCESSOR(getOemSymbolId) + MOCK_SYMBOL_ACCESSOR(getOffsetInUdt) + MOCK_SYMBOL_ACCESSOR(getPlatform) + MOCK_SYMBOL_ACCESSOR(getRank) + MOCK_SYMBOL_ACCESSOR(getRegisterId) + MOCK_SYMBOL_ACCESSOR(getRegisterType) + MOCK_SYMBOL_ACCESSOR(getRelativeVirtualAddress) + MOCK_SYMBOL_ACCESSOR(getSamplerSlot) + MOCK_SYMBOL_ACCESSOR(getSignature) + MOCK_SYMBOL_ACCESSOR(getSizeInUdt) + MOCK_SYMBOL_ACCESSOR(getSlot) + MOCK_SYMBOL_ACCESSOR(getSourceFileName) + MOCK_SYMBOL_ACCESSOR(getStride) + MOCK_SYMBOL_ACCESSOR(getSubTypeId) + MOCK_SYMBOL_ACCESSOR(getSymbolsFileName) + MOCK_SYMBOL_ACCESSOR(getSymIndexId) + MOCK_SYMBOL_ACCESSOR(getTargetOffset) + MOCK_SYMBOL_ACCESSOR(getTargetRelativeVirtualAddress) + MOCK_SYMBOL_ACCESSOR(getTargetVirtualAddress) + MOCK_SYMBOL_ACCESSOR(getTargetSection) + MOCK_SYMBOL_ACCESSOR(getTextureSlot) + MOCK_SYMBOL_ACCESSOR(getTimeStamp) + MOCK_SYMBOL_ACCESSOR(getToken) + MOCK_SYMBOL_ACCESSOR(getTypeId) + MOCK_SYMBOL_ACCESSOR(getUavSlot) + MOCK_SYMBOL_ACCESSOR(getUndecoratedName) + MOCK_SYMBOL_ACCESSOR(getUnmodifiedTypeId) + MOCK_SYMBOL_ACCESSOR(getUpperBoundId) + MOCK_SYMBOL_ACCESSOR(getVirtualBaseDispIndex) + MOCK_SYMBOL_ACCESSOR(getVirtualBaseOffset) + MOCK_SYMBOL_ACCESSOR(getVirtualTableShapeId) + MOCK_SYMBOL_ACCESSOR(getDataKind) + MOCK_SYMBOL_ACCESSOR(getGuid) + MOCK_SYMBOL_ACCESSOR(getOffset) + MOCK_SYMBOL_ACCESSOR(getThisAdjust) + MOCK_SYMBOL_ACCESSOR(getVirtualBasePointerOffset) + MOCK_SYMBOL_ACCESSOR(getLocationType) + MOCK_SYMBOL_ACCESSOR(getMachineType) + MOCK_SYMBOL_ACCESSOR(getThunkOrdinal) + MOCK_SYMBOL_ACCESSOR(getLength) + MOCK_SYMBOL_ACCESSOR(getLiveRangeLength) + MOCK_SYMBOL_ACCESSOR(getVirtualAddress) + MOCK_SYMBOL_ACCESSOR(getUdtKind) + MOCK_SYMBOL_ACCESSOR(hasConstructor) + MOCK_SYMBOL_ACCESSOR(hasCustomCallingConvention) + MOCK_SYMBOL_ACCESSOR(hasFarReturn) + MOCK_SYMBOL_ACCESSOR(isCode) + MOCK_SYMBOL_ACCESSOR(isCompilerGenerated) + MOCK_SYMBOL_ACCESSOR(isConstType) + MOCK_SYMBOL_ACCESSOR(isEditAndContinueEnabled) + MOCK_SYMBOL_ACCESSOR(isFunction) + MOCK_SYMBOL_ACCESSOR(getAddressTaken) + MOCK_SYMBOL_ACCESSOR(getNoStackOrdering) + MOCK_SYMBOL_ACCESSOR(hasAlloca) + MOCK_SYMBOL_ACCESSOR(hasAssignmentOperator) + MOCK_SYMBOL_ACCESSOR(hasCTypes) + MOCK_SYMBOL_ACCESSOR(hasCastOperator) + MOCK_SYMBOL_ACCESSOR(hasDebugInfo) + MOCK_SYMBOL_ACCESSOR(hasEH) + MOCK_SYMBOL_ACCESSOR(hasEHa) + MOCK_SYMBOL_ACCESSOR(hasFramePointer) + MOCK_SYMBOL_ACCESSOR(hasInlAsm) + MOCK_SYMBOL_ACCESSOR(hasInlineAttribute) + MOCK_SYMBOL_ACCESSOR(hasInterruptReturn) + MOCK_SYMBOL_ACCESSOR(hasLongJump) + MOCK_SYMBOL_ACCESSOR(hasManagedCode) + MOCK_SYMBOL_ACCESSOR(hasNestedTypes) + MOCK_SYMBOL_ACCESSOR(hasNoInlineAttribute) + MOCK_SYMBOL_ACCESSOR(hasNoReturnAttribute) + MOCK_SYMBOL_ACCESSOR(hasOptimizedCodeDebugInfo) + MOCK_SYMBOL_ACCESSOR(hasOverloadedOperator) + MOCK_SYMBOL_ACCESSOR(hasSEH) + MOCK_SYMBOL_ACCESSOR(hasSecurityChecks) + MOCK_SYMBOL_ACCESSOR(hasSetJump) + MOCK_SYMBOL_ACCESSOR(hasStrictGSCheck) + MOCK_SYMBOL_ACCESSOR(isAcceleratorGroupSharedLocal) + MOCK_SYMBOL_ACCESSOR(isAcceleratorPointerTagLiveRange) + MOCK_SYMBOL_ACCESSOR(isAcceleratorStubFunction) + MOCK_SYMBOL_ACCESSOR(isAggregated) + MOCK_SYMBOL_ACCESSOR(isIntroVirtualFunction) + MOCK_SYMBOL_ACCESSOR(isCVTCIL) + MOCK_SYMBOL_ACCESSOR(isConstructorVirtualBase) + MOCK_SYMBOL_ACCESSOR(isCxxReturnUdt) + MOCK_SYMBOL_ACCESSOR(isDataAligned) + MOCK_SYMBOL_ACCESSOR(isHLSLData) + MOCK_SYMBOL_ACCESSOR(isHotpatchable) + MOCK_SYMBOL_ACCESSOR(isIndirectVirtualBaseClass) + MOCK_SYMBOL_ACCESSOR(isInterfaceUdt) + MOCK_SYMBOL_ACCESSOR(isIntrinsic) + MOCK_SYMBOL_ACCESSOR(isLTCG) + MOCK_SYMBOL_ACCESSOR(isLocationControlFlowDependent) + MOCK_SYMBOL_ACCESSOR(isMSILNetmodule) + MOCK_SYMBOL_ACCESSOR(isMatrixRowMajor) + MOCK_SYMBOL_ACCESSOR(isManagedCode) + MOCK_SYMBOL_ACCESSOR(isMSILCode) + MOCK_SYMBOL_ACCESSOR(isMultipleInheritance) + MOCK_SYMBOL_ACCESSOR(isNaked) + MOCK_SYMBOL_ACCESSOR(isNested) + MOCK_SYMBOL_ACCESSOR(isOptimizedAway) + MOCK_SYMBOL_ACCESSOR(isPacked) + MOCK_SYMBOL_ACCESSOR(isPointerBasedOnSymbolValue) + MOCK_SYMBOL_ACCESSOR(isPointerToDataMember) + MOCK_SYMBOL_ACCESSOR(isPointerToMemberFunction) + MOCK_SYMBOL_ACCESSOR(isPureVirtual) + MOCK_SYMBOL_ACCESSOR(isRValueReference) + MOCK_SYMBOL_ACCESSOR(isRefUdt) + MOCK_SYMBOL_ACCESSOR(isReference) + MOCK_SYMBOL_ACCESSOR(isRestrictedType) + MOCK_SYMBOL_ACCESSOR(isReturnValue) + MOCK_SYMBOL_ACCESSOR(isSafeBuffers) + MOCK_SYMBOL_ACCESSOR(isScoped) + MOCK_SYMBOL_ACCESSOR(isSdl) + MOCK_SYMBOL_ACCESSOR(isSingleInheritance) + MOCK_SYMBOL_ACCESSOR(isSplitted) + MOCK_SYMBOL_ACCESSOR(isStatic) + MOCK_SYMBOL_ACCESSOR(hasPrivateSymbols) + MOCK_SYMBOL_ACCESSOR(isUnalignedType) + MOCK_SYMBOL_ACCESSOR(isUnreached) + MOCK_SYMBOL_ACCESSOR(isValueUdt) + MOCK_SYMBOL_ACCESSOR(isVirtual) + MOCK_SYMBOL_ACCESSOR(isVirtualBaseClass) + MOCK_SYMBOL_ACCESSOR(isVirtualInheritance) + MOCK_SYMBOL_ACCESSOR(isVolatileType) + MOCK_SYMBOL_ACCESSOR(getValue) + MOCK_SYMBOL_ACCESSOR(wasInlined) + MOCK_SYMBOL_ACCESSOR(getUnused) + +private: + PDB_SymType Type; +}; + +class PDBApiTest : public testing::Test { +public: + std::unordered_map<PDB_SymType, std::unique_ptr<PDBSymbol>> SymbolMap; + + void SetUp() override { + Session.reset(new MockSession()); + + InsertItemWithTag(PDB_SymType::None); + InsertItemWithTag(PDB_SymType::Exe); + InsertItemWithTag(PDB_SymType::Compiland); + InsertItemWithTag(PDB_SymType::CompilandDetails); + InsertItemWithTag(PDB_SymType::CompilandEnv); + InsertItemWithTag(PDB_SymType::Function); + InsertItemWithTag(PDB_SymType::Block); + InsertItemWithTag(PDB_SymType::Data); + InsertItemWithTag(PDB_SymType::Annotation); + InsertItemWithTag(PDB_SymType::Label); + InsertItemWithTag(PDB_SymType::PublicSymbol); + InsertItemWithTag(PDB_SymType::UDT); + InsertItemWithTag(PDB_SymType::Enum); + InsertItemWithTag(PDB_SymType::FunctionSig); + InsertItemWithTag(PDB_SymType::PointerType); + InsertItemWithTag(PDB_SymType::ArrayType); + InsertItemWithTag(PDB_SymType::BuiltinType); + InsertItemWithTag(PDB_SymType::Typedef); + InsertItemWithTag(PDB_SymType::BaseClass); + InsertItemWithTag(PDB_SymType::Friend); + InsertItemWithTag(PDB_SymType::FunctionArg); + InsertItemWithTag(PDB_SymType::FuncDebugStart); + InsertItemWithTag(PDB_SymType::FuncDebugEnd); + InsertItemWithTag(PDB_SymType::UsingNamespace); + InsertItemWithTag(PDB_SymType::VTableShape); + InsertItemWithTag(PDB_SymType::VTable); + InsertItemWithTag(PDB_SymType::Custom); + InsertItemWithTag(PDB_SymType::Thunk); + InsertItemWithTag(PDB_SymType::CustomType); + InsertItemWithTag(PDB_SymType::ManagedType); + InsertItemWithTag(PDB_SymType::Dimension); + InsertItemWithTag(PDB_SymType::Max); + } + + template <class ExpectedType> void VerifyDyncast(PDB_SymType Tag) { + for (auto item = SymbolMap.begin(); item != SymbolMap.end(); ++item) { + EXPECT_EQ(item->first == Tag, llvm::isa<ExpectedType>(*item->second)); + } + } + + void VerifyUnknownDyncasts() { + for (auto item = SymbolMap.begin(); item != SymbolMap.end(); ++item) { + bool should_match = false; + if (item->first == PDB_SymType::None || item->first >= PDB_SymType::Max) + should_match = true; + + EXPECT_EQ(should_match, llvm::isa<PDBSymbolUnknown>(*item->second)); + } + } + +private: + std::unique_ptr<IPDBSession> Session; + + void InsertItemWithTag(PDB_SymType Tag) { + auto RawSymbol = llvm::make_unique<MockRawSymbol>(Tag); + auto Symbol = PDBSymbol::create(*Session, std::move(RawSymbol)); + SymbolMap.insert(std::make_pair(Tag, std::move(Symbol))); + } +}; + +TEST_F(PDBApiTest, Dyncast) { + + // Most of the types have a one-to-one mapping between Tag and concrete type. + VerifyDyncast<PDBSymbolExe>(PDB_SymType::Exe); + VerifyDyncast<PDBSymbolCompiland>(PDB_SymType::Compiland); + VerifyDyncast<PDBSymbolCompilandDetails>(PDB_SymType::CompilandDetails); + VerifyDyncast<PDBSymbolCompilandEnv>(PDB_SymType::CompilandEnv); + VerifyDyncast<PDBSymbolFunc>(PDB_SymType::Function); + VerifyDyncast<PDBSymbolBlock>(PDB_SymType::Block); + VerifyDyncast<PDBSymbolData>(PDB_SymType::Data); + VerifyDyncast<PDBSymbolAnnotation>(PDB_SymType::Annotation); + VerifyDyncast<PDBSymbolLabel>(PDB_SymType::Label); + VerifyDyncast<PDBSymbolPublicSymbol>(PDB_SymType::PublicSymbol); + VerifyDyncast<PDBSymbolTypeUDT>(PDB_SymType::UDT); + VerifyDyncast<PDBSymbolTypeEnum>(PDB_SymType::Enum); + VerifyDyncast<PDBSymbolTypeFunctionSig>(PDB_SymType::FunctionSig); + VerifyDyncast<PDBSymbolTypePointer>(PDB_SymType::PointerType); + VerifyDyncast<PDBSymbolTypeArray>(PDB_SymType::ArrayType); + VerifyDyncast<PDBSymbolTypeBuiltin>(PDB_SymType::BuiltinType); + VerifyDyncast<PDBSymbolTypeTypedef>(PDB_SymType::Typedef); + VerifyDyncast<PDBSymbolTypeBaseClass>(PDB_SymType::BaseClass); + VerifyDyncast<PDBSymbolTypeFriend>(PDB_SymType::Friend); + VerifyDyncast<PDBSymbolTypeFunctionArg>(PDB_SymType::FunctionArg); + VerifyDyncast<PDBSymbolFuncDebugStart>(PDB_SymType::FuncDebugStart); + VerifyDyncast<PDBSymbolFuncDebugEnd>(PDB_SymType::FuncDebugEnd); + VerifyDyncast<PDBSymbolUsingNamespace>(PDB_SymType::UsingNamespace); + VerifyDyncast<PDBSymbolTypeVTableShape>(PDB_SymType::VTableShape); + VerifyDyncast<PDBSymbolTypeVTable>(PDB_SymType::VTable); + VerifyDyncast<PDBSymbolCustom>(PDB_SymType::Custom); + VerifyDyncast<PDBSymbolThunk>(PDB_SymType::Thunk); + VerifyDyncast<PDBSymbolTypeCustom>(PDB_SymType::CustomType); + VerifyDyncast<PDBSymbolTypeManaged>(PDB_SymType::ManagedType); + VerifyDyncast<PDBSymbolTypeDimension>(PDB_SymType::Dimension); + + VerifyUnknownDyncasts(); +} + +} // end anonymous namespace diff --git a/unittests/ExecutionEngine/CMakeLists.txt b/unittests/ExecutionEngine/CMakeLists.txt index 05e093e0c0b40..302de9943ffe4 100644 --- a/unittests/ExecutionEngine/CMakeLists.txt +++ b/unittests/ExecutionEngine/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS ExecutionEngine Interpreter MC + OrcJIT RuntimeDyld Support ) @@ -11,6 +12,8 @@ add_llvm_unittest(ExecutionEngineTests ExecutionEngineTest.cpp ) +add_subdirectory(Orc) + # Include MCJIT tests only if native arch is a built JIT target. list(FIND LLVM_TARGETS_TO_BUILD "${LLVM_NATIVE_ARCH}" build_idx) list(FIND LLVM_TARGETS_WITH_JIT "${LLVM_NATIVE_ARCH}" jit_idx) diff --git a/unittests/ExecutionEngine/ExecutionEngineTest.cpp b/unittests/ExecutionEngine/ExecutionEngineTest.cpp index 19917a41350c7..bb47c4c00304c 100644 --- a/unittests/ExecutionEngine/ExecutionEngineTest.cpp +++ b/unittests/ExecutionEngine/ExecutionEngineTest.cpp @@ -9,6 +9,7 @@ #include "llvm/ExecutionEngine/Interpreter.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" @@ -32,7 +33,7 @@ protected: Engine.reset(EngineBuilder(std::move(Owner)).setErrorStr(&Error).create()); } - virtual void SetUp() { + void SetUp() override { ASSERT_TRUE(Engine.get() != nullptr) << "EngineBuilder returned error: '" << Error << "'"; } @@ -53,6 +54,7 @@ TEST_F(ExecutionEngineTest, ForwardGlobalMapping) { int32_t Mem1 = 3; Engine->addGlobalMapping(G1, &Mem1); EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G1)); + EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable("Global1")); int32_t Mem2 = 4; Engine->updateGlobalMapping(G1, &Mem2); EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1)); diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index f2a3000906e32..a7c9ae02b384d 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -85,13 +85,11 @@ public: ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0), UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) { } - - virtual bool needsToReserveAllocationSpace() { - return true; - } - virtual void reserveAllocationSpace( - uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) { + bool needsToReserveAllocationSpace() override { return true; } + + void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO, + uintptr_t DataSizeRW) override { ReservedCodeSize = CodeSize; ReservedDataSizeRO = DataSizeRO; ReservedDataSizeRW = DataSizeRW; @@ -103,15 +101,17 @@ public: *UsedSize = AlignedBegin + AlignedSize; } - virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName, bool IsReadOnly) { + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) override { useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment); return SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly); } - uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName) { + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) override { useSpace(&UsedCodeSize, Size, Alignment); return SectionMemoryManager::allocateCodeSection(Size, Alignment, SectionID, SectionName); @@ -141,8 +141,8 @@ protected: // that they will fail the MCJIT C API tests. UnsupportedEnvironments.push_back(Triple::Cygnus); } - - virtual void SetUp() { + + void SetUp() override { didCallAllocateCodeSection = false; didAllocateCompactUnwindSection = false; didCallYield = false; @@ -151,8 +151,8 @@ protected: Engine = nullptr; Error = nullptr; } - - virtual void TearDown() { + + void TearDown() override { if (Engine) LLVMDisposeExecutionEngine(Engine); else if (Module) diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp index b0d1bb39c7f34..da6e25a3d516b 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp @@ -392,4 +392,23 @@ TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) { ptr = TheJIT->getFunctionAddress(FB2->getName().str()); checkAccumulate(ptr); } + +// Test that FindFunctionNamed finds the definition of +// a function in the correct module. We check two functions +// in two different modules, to make sure that for at least +// one of them MCJIT had to ignore the extern declaration. +TEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) { + SKIP_UNSUPPORTED_PLATFORM; + + std::unique_ptr<Module> A, B; + Function *FA, *FB1, *FB2; + createCrossModuleRecursiveCase(A, FA, B, FB1, FB2); + + createJIT(std::move(A)); + TheJIT->addModule(std::move(B)); + + EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data())); + EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data())); +} + } diff --git a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp index 2e38dd88b0fdc..ff5b6e3deccca 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp @@ -33,7 +33,7 @@ public: ObjMap[ModuleID] = copyBuffer(Obj); } - virtual std::unique_ptr<MemoryBuffer> getObject(const Module* M) override { + std::unique_ptr<MemoryBuffer> getObject(const Module *M) override { const MemoryBuffer* BufferFound = getObjectInternal(M); ModulesLookedUp.insert(M->getModuleIdentifier()); if (!BufferFound) @@ -84,7 +84,7 @@ protected: ReplacementRC = 7 }; - virtual void SetUp() { + void SetUp() override { M.reset(createEmptyModule("<main>")); Main = insertMainFunction(M.get(), OriginalRC); } diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index 64d8c2fca042a..f65ec96d944b9 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -22,7 +22,7 @@ namespace { class MCJITTest : public testing::Test, public MCJITTestBase { protected: - virtual void SetUp() { M.reset(createEmptyModule("<main>")); } + void SetUp() override { M.reset(createEmptyModule("<main>")); } }; // FIXME: Ensure creating an execution engine does not crash when constructed @@ -169,7 +169,7 @@ TEST_F(MCJITTest, multiple_functions) { std::stringstream funcName; funcName << "level_" << i; Outer = startFunction<int32_t(void)>(M.get(), funcName.str()); - Value *innerResult = Builder.CreateCall(Inner); + Value *innerResult = Builder.CreateCall(Inner, {}); endFunctionWithRet(Outer, innerResult); Inner = Outer; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h index 35af417bf1474..901f142d09cdf 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -308,11 +308,6 @@ protected: SupportedSubArchs.push_back("armv6"); SupportedSubArchs.push_back("armv7"); - // The operating systems below are known to be incompatible with MCJIT as - // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and - // should be kept in sync. - UnsupportedOSs.push_back(Triple::Darwin); - UnsupportedEnvironments.push_back(Triple::Cygnus); } diff --git a/unittests/ExecutionEngine/Makefile b/unittests/ExecutionEngine/Makefile index 8ecb883ba9d7d..c19f8d688d1bc 100644 --- a/unittests/ExecutionEngine/Makefile +++ b/unittests/ExecutionEngine/Makefile @@ -13,8 +13,10 @@ LINK_COMPONENTS :=interpreter include $(LEVEL)/Makefile.config +PARALLEL_DIRS = Orc + ifeq ($(TARGET_HAS_JIT),1) - PARALLEL_DIRS = MCJIT + PARALLEL_DIRS += MCJIT endif include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt new file mode 100644 index 0000000000000..67b215ebc6d4e --- /dev/null +++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_LINK_COMPONENTS + Core + OrcJIT + Support + ) + +add_llvm_unittest(OrcJITTests + IndirectionUtilsTest.cpp + LazyEmittingLayerTest.cpp + OrcTestCommon.cpp + ) diff --git a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp new file mode 100644 index 0000000000000..1a533b05838d9 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp @@ -0,0 +1,48 @@ +//===- LazyEmittingLayerTest.cpp - Unit tests for the lazy emitting layer -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OrcTestCommon.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(IndirectionUtilsTest, MakeStub) { + ModuleBuilder MB(getGlobalContext(), "x86_64-apple-macosx10.10", ""); + Function *F = MB.createFunctionDecl<void(DummyStruct, DummyStruct)>(MB.getModule(), ""); + SmallVector<AttributeSet, 4> Attrs; + Attrs.push_back( + AttributeSet::get(MB.getModule()->getContext(), 1U, + AttrBuilder().addAttribute(Attribute::StructRet))); + Attrs.push_back( + AttributeSet::get(MB.getModule()->getContext(), 2U, + AttrBuilder().addAttribute(Attribute::ByVal))); + Attrs.push_back( + AttributeSet::get(MB.getModule()->getContext(), ~0U, + AttrBuilder().addAttribute(Attribute::NoUnwind))); + F->setAttributes(AttributeSet::get(MB.getModule()->getContext(), Attrs)); + + auto ImplPtr = orc::createImplPointer(*F->getType(), *MB.getModule(), "", nullptr); + orc::makeStub(*F, *ImplPtr); + + auto II = F->getEntryBlock().begin(); + EXPECT_TRUE(isa<LoadInst>(*II)) << "First instruction of stub should be a load."; + auto *Call = dyn_cast<CallInst>(std::next(II)); + EXPECT_TRUE(Call != nullptr) << "Second instruction of stub should be a call."; + EXPECT_TRUE(Call->isTailCall()) << "Indirect call from stub should be tail call."; + EXPECT_TRUE(Call->hasStructRetAttr()) + << "makeStub should propagate sret attr on 1st argument."; + EXPECT_TRUE(Call->paramHasAttr(2U, Attribute::ByVal)) + << "makeStub should propagate byval attr on 2nd argument."; +} + +} diff --git a/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp new file mode 100644 index 0000000000000..a495766db91a0 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp @@ -0,0 +1,32 @@ +//===- LazyEmittingLayerTest.cpp - Unit tests for the lazy emitting layer -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" +#include "gtest/gtest.h" + +namespace { + +struct MockBaseLayer { + typedef int ModuleSetHandleT; + ModuleSetHandleT addModuleSet( + std::list<std::unique_ptr<llvm::Module>>, + std::unique_ptr<llvm::RuntimeDyld::MemoryManager> MemMgr, + std::unique_ptr<llvm::RuntimeDyld::SymbolResolver> Resolver) { + EXPECT_FALSE(MemMgr); + return 42; + } +}; + +TEST(LazyEmittingLayerTest, Empty) { + MockBaseLayer M; + llvm::orc::LazyEmittingLayer<MockBaseLayer> L(M); + L.addModuleSet(std::list<std::unique_ptr<llvm::Module>>(), nullptr, nullptr); +} + +} diff --git a/unittests/ExecutionEngine/Orc/Makefile b/unittests/ExecutionEngine/Orc/Makefile new file mode 100644 index 0000000000000..c899728e50789 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/Makefile @@ -0,0 +1,16 @@ +##===- unittests/ExecutionEngine/Orc/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TESTNAME = OrcJIT +LINK_COMPONENTS := core ipo mcjit orcjit native support + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest + diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp new file mode 100644 index 0000000000000..5fea3c89f86c2 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp @@ -0,0 +1,23 @@ +//===--------- OrcTestCommon.cpp - Utilities for Orc Unit Tests -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common utilities for Orc unit tests. +// +//===----------------------------------------------------------------------===// + +#include "OrcTestCommon.h" + +using namespace llvm; + +ModuleBuilder::ModuleBuilder(LLVMContext &Context, StringRef Triple, + StringRef Name) + : M(new Module(Name, Context)), + Builder(Context) { + M->setTargetTriple(Triple); +} diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h new file mode 100644 index 0000000000000..1b2859b51d094 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -0,0 +1,66 @@ +//===------ OrcTestCommon.h - Utilities for Orc Unit Tests ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common utilities for the Orc unit tests. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H +#define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/TypeBuilder.h" +#include <memory> + +namespace llvm { + + class ModuleBuilder { + public: + ModuleBuilder(LLVMContext &Context, StringRef Triple, + StringRef Name); + + template <typename FuncType> + Function* createFunctionDecl(Module *M, StringRef Name) { + return Function::Create( + TypeBuilder<FuncType, false>::get(M->getContext()), + GlobalValue::ExternalLinkage, Name, M); + } + + Module* getModule() { return M.get(); } + const Module* getModule() const { return M.get(); } + std::unique_ptr<Module> takeModule() { return std::move(M); } + + private: + std::unique_ptr<Module> M; + IRBuilder<> Builder; + }; + + // Dummy struct type. + struct DummyStruct { + int X[256]; + }; + + // TypeBuilder specialization for DummyStruct. + template <bool XCompile> + class TypeBuilder<DummyStruct, XCompile> { + public: + static StructType *get(LLVMContext &Context) { + return StructType::get( + TypeBuilder<types::i<32>[256], XCompile>::get(Context), nullptr); + } + }; + + +} // namespace llvm + +#endif diff --git a/unittests/IR/ConstantRangeTest.cpp b/unittests/IR/ConstantRangeTest.cpp index fa03302ad2bb3..de4eec4abf5d3 100644 --- a/unittests/IR/ConstantRangeTest.cpp +++ b/unittests/IR/ConstantRangeTest.cpp @@ -400,6 +400,13 @@ TEST_F(ConstantRangeTest, Multiply) { EXPECT_EQ(ConstantRange(APInt(4, 1), APInt(4, 6)).multiply( ConstantRange(APInt(4, 6), APInt(4, 2))), ConstantRange(4, /*isFullSet=*/true)); + + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 0)).multiply( + ConstantRange(APInt(8, 252), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 9))); + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 255)).multiply( + ConstantRange(APInt(8, 2), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 253))); } TEST_F(ConstantRangeTest, UMax) { @@ -502,11 +509,63 @@ TEST_F(ConstantRangeTest, Lshr) { EXPECT_EQ(Wrap.lshr(Wrap), Full); } -TEST(ConstantRange, MakeICmpRegion) { +TEST(ConstantRange, MakeAllowedICmpRegion) { // PR8250 ConstantRange SMax = ConstantRange(APInt::getSignedMaxValue(32)); - EXPECT_TRUE(ConstantRange::makeICmpRegion(ICmpInst::ICMP_SGT, - SMax).isEmptySet()); + EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(ICmpInst::ICMP_SGT, SMax) + .isEmptySet()); +} + +TEST(ConstantRange, MakeSatisfyingICmpRegion) { + ConstantRange LowHalf(APInt(8, 0), APInt(8, 128)); + ConstantRange HighHalf(APInt(8, 128), APInt(8, 0)); + ConstantRange EmptySet(8, /* isFullSet = */ false); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_NE, LowHalf), + HighHalf); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_NE, HighHalf), + LowHalf); + + EXPECT_TRUE(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_EQ, + HighHalf).isEmptySet()); + + ConstantRange UnsignedSample(APInt(8, 5), APInt(8, 200)); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_ULT, + UnsignedSample), + ConstantRange(APInt(8, 0), APInt(8, 5))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_ULE, + UnsignedSample), + ConstantRange(APInt(8, 0), APInt(8, 6))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_UGT, + UnsignedSample), + ConstantRange(APInt(8, 200), APInt(8, 0))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_UGE, + UnsignedSample), + ConstantRange(APInt(8, 199), APInt(8, 0))); + + ConstantRange SignedSample(APInt(8, -5), APInt(8, 5)); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SLT, SignedSample), + ConstantRange(APInt(8, -128), APInt(8, -5))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SLE, SignedSample), + ConstantRange(APInt(8, -128), APInt(8, -4))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SGT, SignedSample), + ConstantRange(APInt(8, 5), APInt(8, -128))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SGE, SignedSample), + ConstantRange(APInt(8, 4), APInt(8, -128))); } } // anonymous namespace diff --git a/unittests/IR/ConstantsTest.cpp b/unittests/IR/ConstantsTest.cpp index 5414b25ca3adf..2df008a78ccd7 100644 --- a/unittests/IR/ConstantsTest.cpp +++ b/unittests/IR/ConstantsTest.cpp @@ -7,12 +7,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" namespace llvm { @@ -185,6 +187,13 @@ TEST(ConstantsTest, AsInstructionsTest) { Constant *P6 = ConstantExpr::getBitCast(P4, VectorType::get(Int16Ty, 2)); Constant *One = ConstantInt::get(Int32Ty, 1); + Constant *Two = ConstantInt::get(Int64Ty, 2); + Constant *Big = ConstantInt::get(getGlobalContext(), + APInt{256, uint64_t(-1), true}); + Constant *Elt = ConstantInt::get(Int16Ty, 2015); + Constant *Undef16 = UndefValue::get(Int16Ty); + Constant *Undef64 = UndefValue::get(Int64Ty); + Constant *UndefV16 = UndefValue::get(P6->getType()); #define P0STR "ptrtoint (i32** @dummy to i32)" #define P1STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to float)" @@ -246,12 +255,23 @@ TEST(ConstantsTest, AsInstructionsTest) { // FIXME: getGetElementPtr() actually creates an inbounds ConstantGEP, // not a normal one! //CHECK(ConstantExpr::getGetElementPtr(Global, V, false), - // "getelementptr i32** @dummy, i32 1"); - CHECK(ConstantExpr::getInBoundsGetElementPtr(Global, V), - "getelementptr inbounds i32** @dummy, i32 1"); + // "getelementptr i32*, i32** @dummy, i32 1"); + CHECK(ConstantExpr::getInBoundsGetElementPtr(PointerType::getUnqual(Int32Ty), + Global, V), + "getelementptr inbounds i32*, i32** @dummy, i32 1"); CHECK(ConstantExpr::getExtractElement(P6, One), "extractelement <2 x i16> " P6STR ", i32 1"); + + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Two)); + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Big)); + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Undef64)); + + EXPECT_EQ(Elt, ConstantExpr::getExtractElement( + ConstantExpr::getInsertElement(P6, Elt, One), One)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Two)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Big)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Undef64)); } #ifdef GTEST_HAS_DEATH_TEST @@ -264,7 +284,8 @@ TEST(ConstantsTest, ReplaceWithConstantTest) { Constant *Global = M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty)); - Constant *GEP = ConstantExpr::getGetElementPtr(Global, One); + Constant *GEP = ConstantExpr::getGetElementPtr( + PointerType::getUnqual(Int32Ty), Global, One); EXPECT_DEATH(Global->replaceAllUsesWith(GEP), "this->replaceAllUsesWith\\(expr\\(this\\)\\) is NOT valid!"); } @@ -327,11 +348,11 @@ TEST(ConstantsTest, GEPReplaceWithConstant) { std::unique_ptr<Module> M(new Module("MyModule", Context)); Type *IntTy = Type::getInt32Ty(Context); - Type *PtrTy = PointerType::get(IntTy, 0); + auto *PtrTy = PointerType::get(IntTy, 0); auto *C1 = ConstantInt::get(IntTy, 1); auto *Placeholder = new GlobalVariable( *M, IntTy, false, GlobalValue::ExternalWeakLinkage, nullptr); - auto *GEP = ConstantExpr::getGetElementPtr(Placeholder, C1); + auto *GEP = ConstantExpr::getGetElementPtr(IntTy, Placeholder, C1); ASSERT_EQ(GEP->getOperand(0), Placeholder); auto *Ref = @@ -340,12 +361,26 @@ TEST(ConstantsTest, GEPReplaceWithConstant) { auto *Global = new GlobalVariable(*M, PtrTy, false, GlobalValue::ExternalLinkage, nullptr); - auto *Alias = GlobalAlias::create(IntTy, 0, GlobalValue::ExternalLinkage, + auto *Alias = GlobalAlias::create(PtrTy, GlobalValue::ExternalLinkage, "alias", Global, M.get()); Placeholder->replaceAllUsesWith(Alias); ASSERT_EQ(GEP, Ref->getInitializer()); ASSERT_EQ(GEP->getOperand(0), Alias); } +TEST(ConstantsTest, AliasCAPI) { + LLVMContext Context; + SMDiagnostic Error; + std::unique_ptr<Module> M = + parseAssemblyString("@g = global i32 42", Error, Context); + GlobalVariable *G = M->getGlobalVariable("g"); + Type *I16Ty = Type::getInt16Ty(Context); + Type *I16PTy = PointerType::get(I16Ty, 0); + Constant *Aliasee = ConstantExpr::getBitCast(G, I16PTy); + LLVMValueRef AliasRef = + LLVMAddAlias(wrap(M.get()), wrap(I16PTy), wrap(Aliasee), "a"); + ASSERT_EQ(unwrap<GlobalAlias>(AliasRef)->getAliasee(), Aliasee); +} + } // end anonymous namespace } // end namespace llvm diff --git a/unittests/IR/DebugInfoTest.cpp b/unittests/IR/DebugInfoTest.cpp index 1fa851e39ae98..f633782b37995 100644 --- a/unittests/IR/DebugInfoTest.cpp +++ b/unittests/IR/DebugInfoTest.cpp @@ -7,62 +7,75 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "gtest/gtest.h" using namespace llvm; -namespace llvm { - -static void PrintTo(const StringRef &S, ::std::ostream *os) { - *os << "(" << (const void *)S.data() << "," << S.size() << ") = '"; - for (auto C : S) - if (C) - *os << C; - else - *os << "\\00"; - *os << "'"; -} -static void PrintTo(const DIHeaderFieldIterator &I, ::std::ostream *os) { - PrintTo(I.getCurrent(), os); - *os << " in "; - PrintTo(I.getHeader(), os); -} - -} // end namespace llvm - namespace { -#define MAKE_FIELD_ITERATOR(S) \ - DIHeaderFieldIterator(StringRef(S, sizeof(S) - 1)) -TEST(DebugInfoTest, DIHeaderFieldIterator) { - ASSERT_EQ(DIHeaderFieldIterator(), DIHeaderFieldIterator()); +TEST(DINodeTest, getFlag) { + // Some valid flags. + EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic")); + EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected")); + EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate")); + EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector")); + EXPECT_EQ(DINode::FlagRValueReference, + DINode::getFlag("DIFlagRValueReference")); + + // FlagAccessibility shouldn't work. + EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility")); - ASSERT_NE(DIHeaderFieldIterator(), MAKE_FIELD_ITERATOR("")); - ASSERT_EQ(DIHeaderFieldIterator(), ++MAKE_FIELD_ITERATOR("")); - ASSERT_EQ("", *DIHeaderFieldIterator("")); + // Some other invalid strings. + EXPECT_EQ(0u, DINode::getFlag("FlagVector")); + EXPECT_EQ(0u, DINode::getFlag("Vector")); + EXPECT_EQ(0u, DINode::getFlag("other things")); + EXPECT_EQ(0u, DINode::getFlag("DIFlagOther")); +} - ASSERT_NE(DIHeaderFieldIterator(), MAKE_FIELD_ITERATOR("stuff")); - ASSERT_EQ(DIHeaderFieldIterator(), ++MAKE_FIELD_ITERATOR("stuff")); - ASSERT_EQ("stuff", *DIHeaderFieldIterator("stuff")); +TEST(DINodeTest, getFlagString) { + // Some valid flags. + EXPECT_EQ(StringRef("DIFlagPublic"), + DINode::getFlagString(DINode::FlagPublic)); + EXPECT_EQ(StringRef("DIFlagProtected"), + DINode::getFlagString(DINode::FlagProtected)); + EXPECT_EQ(StringRef("DIFlagPrivate"), + DINode::getFlagString(DINode::FlagPrivate)); + EXPECT_EQ(StringRef("DIFlagVector"), + DINode::getFlagString(DINode::FlagVector)); + EXPECT_EQ(StringRef("DIFlagRValueReference"), + DINode::getFlagString(DINode::FlagRValueReference)); - ASSERT_NE(DIHeaderFieldIterator(), MAKE_FIELD_ITERATOR("st\0uff")); - ASSERT_NE(DIHeaderFieldIterator(), ++MAKE_FIELD_ITERATOR("st\0uff")); - ASSERT_EQ(DIHeaderFieldIterator(), ++++MAKE_FIELD_ITERATOR("st\0uff")); - ASSERT_EQ("st", *MAKE_FIELD_ITERATOR("st\0uff")); - ASSERT_EQ("uff", *++MAKE_FIELD_ITERATOR("st\0uff")); + // FlagAccessibility actually equals FlagPublic. + EXPECT_EQ(StringRef("DIFlagPublic"), + DINode::getFlagString(DINode::FlagAccessibility)); - ASSERT_NE(DIHeaderFieldIterator(), MAKE_FIELD_ITERATOR("stuff\0")); - ASSERT_NE(DIHeaderFieldIterator(), ++MAKE_FIELD_ITERATOR("stuff\0")); - ASSERT_EQ(DIHeaderFieldIterator(), ++++MAKE_FIELD_ITERATOR("stuff\0")); - ASSERT_EQ("stuff", *MAKE_FIELD_ITERATOR("stuff\0")); - ASSERT_EQ("", *++MAKE_FIELD_ITERATOR("stuff\0")); + // Some other invalid flags. + EXPECT_EQ(StringRef(), + DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector)); + EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl | + DINode::FlagArtificial)); + EXPECT_EQ(StringRef(), DINode::getFlagString(0xffff)); +} - ASSERT_NE(DIHeaderFieldIterator(), MAKE_FIELD_ITERATOR("\0stuff")); - ASSERT_NE(DIHeaderFieldIterator(), ++MAKE_FIELD_ITERATOR("\0stuff")); - ASSERT_EQ(DIHeaderFieldIterator(), ++++MAKE_FIELD_ITERATOR("\0stuff")); - ASSERT_EQ("", *MAKE_FIELD_ITERATOR("\0stuff")); - ASSERT_EQ("stuff", *++MAKE_FIELD_ITERATOR("\0stuff")); +TEST(DINodeTest, splitFlags) { +// Some valid flags. +#define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \ + { \ + SmallVector<unsigned, 8> V; \ + EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \ + EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \ + } + CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, 0u); + CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, 0u); + CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, 0u); + CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, 0u); + CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 0u); + unsigned Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector}; + CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 0u); + CHECK_SPLIT(0x100000u, {}, 0x100000u); + CHECK_SPLIT(0x100000u | DINode::FlagVector, {DINode::FlagVector}, 0x100000u); +#undef CHECK_SPLIT } } // end namespace diff --git a/unittests/IR/DominatorTreeTest.cpp b/unittests/IR/DominatorTreeTest.cpp index 6c43d6fe7c7bc..6a5838e693acf 100644 --- a/unittests/IR/DominatorTreeTest.cpp +++ b/unittests/IR/DominatorTreeTest.cpp @@ -10,10 +10,11 @@ #include "llvm/IR/Dominators.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" @@ -25,7 +26,7 @@ namespace llvm { namespace { struct DPass : public FunctionPass { static char ID; - virtual bool runOnFunction(Function &F) { + bool runOnFunction(Function &F) override { DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); PostDominatorTree *PDT = &getAnalysis<PostDominatorTree>(); @@ -174,9 +175,36 @@ namespace llvm { EXPECT_EQ(DominatedBBs.size(), 0UL); EXPECT_EQ(PostDominatedBBs.size(), 0UL); + // Check DFS Numbers before + EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL); + EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 7UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 2UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 5UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 6UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL); + + // Reattach block 3 to block 1 and recalculate + BB1->getTerminator()->eraseFromParent(); + BranchInst::Create(BB4, BB3, ConstantInt::getTrue(F.getContext()), BB1); + DT->recalculate(F); + + // Check DFS Numbers after + EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL); + EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 9UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 4UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 7UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 8UL); + EXPECT_EQ(DT->getNode(BB3)->getDFSNumIn(), 2UL); + EXPECT_EQ(DT->getNode(BB3)->getDFSNumOut(), 3UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 5UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 6UL); + return false; } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<DominatorTreeWrapperPass>(); AU.addRequired<PostDominatorTree>(); } @@ -218,7 +246,7 @@ namespace llvm { TEST(DominatorTree, Unreachable) { DPass *P = new DPass(); std::unique_ptr<Module> M = makeLLVMModule(P); - PassManager Passes; + legacy::PassManager Passes; Passes.add(P); Passes.run(*M); } diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp index df5c840647798..e8aaaea077554 100644 --- a/unittests/IR/IRBuilderTest.cpp +++ b/unittests/IR/IRBuilderTest.cpp @@ -10,12 +10,14 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" +#include "llvm/IR/Verifier.h" #include "gtest/gtest.h" using namespace llvm; @@ -24,7 +26,7 @@ namespace { class IRBuilderTest : public testing::Test { protected: - virtual void SetUp() { + void SetUp() override { M.reset(new Module("MyModule", Ctx)); FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), /*isVarArg=*/false); @@ -34,7 +36,7 @@ protected: GlobalValue::ExternalLinkage, nullptr); } - virtual void TearDown() { + void TearDown() override { BB = nullptr; M.reset(); } @@ -110,9 +112,9 @@ TEST_F(IRBuilderTest, LandingPadName) { TEST_F(IRBuilderTest, DataLayout) { std::unique_ptr<Module> M(new Module("test", Ctx)); M->setDataLayout("e-n32"); - EXPECT_TRUE(M->getDataLayout()->isLegalInteger(32)); + EXPECT_TRUE(M->getDataLayout().isLegalInteger(32)); M->setDataLayout("e"); - EXPECT_FALSE(M->getDataLayout()->isLegalInteger(32)); + EXPECT_FALSE(M->getDataLayout().isLegalInteger(32)); } TEST_F(IRBuilderTest, GetIntTy) { @@ -121,7 +123,7 @@ TEST_F(IRBuilderTest, GetIntTy) { EXPECT_EQ(Ty1, IntegerType::get(Ctx, 1)); DataLayout* DL = new DataLayout(M.get()); - IntegerType *IntPtrTy = Builder.getIntPtrTy(DL); + IntegerType *IntPtrTy = Builder.getIntPtrTy(*DL); unsigned IntPtrBitSize = DL->getPointerSizeInBits(0); EXPECT_EQ(IntPtrTy, IntegerType::get(Ctx, IntPtrBitSize)); delete DL; @@ -287,5 +289,37 @@ TEST_F(IRBuilderTest, RAIIHelpersTest) { EXPECT_EQ(BB, Builder.GetInsertBlock()); } +TEST_F(IRBuilderTest, DIBuilder) { + IRBuilder<> Builder(BB); + DIBuilder DIB(*M); + auto File = DIB.createFile("F.CBL", "/"); + auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/", + "llvm-cobol74", true, "", 0); + auto Type = DIB.createSubroutineType(File, DIB.getOrCreateTypeArray(None)); + DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1, 0, true, F); + AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty()); + auto BarSP = DIB.createFunction(CU, "bar", "", File, 1, Type, false, true, 1, + 0, true, nullptr); + auto BadScope = DIB.createLexicalBlockFile(BarSP, File, 0); + I->setDebugLoc(DebugLoc::get(2, 0, BadScope)); + DIB.finalize(); + EXPECT_TRUE(verifyModule(*M)); +} + +TEST_F(IRBuilderTest, InsertExtractElement) { + IRBuilder<> Builder(BB); + + auto VecTy = VectorType::get(Builder.getInt64Ty(), 4); + auto Elt1 = Builder.getInt64(-1); + auto Elt2 = Builder.getInt64(-2); + Value *Vec = UndefValue::get(VecTy); + Vec = Builder.CreateInsertElement(Vec, Elt1, Builder.getInt8(1)); + Vec = Builder.CreateInsertElement(Vec, Elt2, 2); + auto X1 = Builder.CreateExtractElement(Vec, 1); + auto X2 = Builder.CreateExtractElement(Vec, Builder.getInt32(2)); + EXPECT_EQ(Elt1, X1); + EXPECT_EQ(Elt2, X2); +} + } diff --git a/unittests/IR/InstructionsTest.cpp b/unittests/IR/InstructionsTest.cpp index 7ec9b62207fbc..3ca3ad2b6e837 100644 --- a/unittests/IR/InstructionsTest.cpp +++ b/unittests/IR/InstructionsTest.cpp @@ -291,8 +291,10 @@ TEST(InstructionsTest, VectorGep) { LLVMContext &C(getGlobalContext()); // Type Definitions - PointerType *Ptri8Ty = PointerType::get(IntegerType::get(C, 8), 0); - PointerType *Ptri32Ty = PointerType::get(IntegerType::get(C, 32), 0); + Type *I8Ty = IntegerType::get(C, 8); + Type *I32Ty = IntegerType::get(C, 32); + PointerType *Ptri8Ty = PointerType::get(I8Ty, 0); + PointerType *Ptri32Ty = PointerType::get(I32Ty, 0); VectorType *V2xi8PTy = VectorType::get(Ptri8Ty, 2); VectorType *V2xi32PTy = VectorType::get(Ptri32Ty, 2); @@ -318,10 +320,10 @@ TEST(InstructionsTest, VectorGep) { ICmpInst *ICmp2 = new ICmpInst(*BB0, ICmpInst::ICMP_SGE, PtrVecA, PtrVecB); EXPECT_NE(ICmp0, ICmp2); // suppress warning. - GetElementPtrInst *Gep0 = GetElementPtrInst::Create(PtrVecA, C2xi32a); - GetElementPtrInst *Gep1 = GetElementPtrInst::Create(PtrVecA, C2xi32b); - GetElementPtrInst *Gep2 = GetElementPtrInst::Create(PtrVecB, C2xi32a); - GetElementPtrInst *Gep3 = GetElementPtrInst::Create(PtrVecB, C2xi32b); + GetElementPtrInst *Gep0 = GetElementPtrInst::Create(I32Ty, PtrVecA, C2xi32a); + GetElementPtrInst *Gep1 = GetElementPtrInst::Create(I32Ty, PtrVecA, C2xi32b); + GetElementPtrInst *Gep2 = GetElementPtrInst::Create(I32Ty, PtrVecB, C2xi32a); + GetElementPtrInst *Gep3 = GetElementPtrInst::Create(I32Ty, PtrVecB, C2xi32b); CastInst *BTC0 = new BitCastInst(Gep0, V2xi8PTy); CastInst *BTC1 = new BitCastInst(Gep1, V2xi8PTy); @@ -343,16 +345,16 @@ TEST(InstructionsTest, VectorGep) { "2:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-s:64:64-f80" ":128:128-n8:16:32:64-S128"); // Make sure we don't crash - GetPointerBaseWithConstantOffset(Gep0, Offset, &TD); - GetPointerBaseWithConstantOffset(Gep1, Offset, &TD); - GetPointerBaseWithConstantOffset(Gep2, Offset, &TD); - GetPointerBaseWithConstantOffset(Gep3, Offset, &TD); + GetPointerBaseWithConstantOffset(Gep0, Offset, TD); + GetPointerBaseWithConstantOffset(Gep1, Offset, TD); + GetPointerBaseWithConstantOffset(Gep2, Offset, TD); + GetPointerBaseWithConstantOffset(Gep3, Offset, TD); // Gep of Geps - GetElementPtrInst *GepII0 = GetElementPtrInst::Create(Gep0, C2xi32b); - GetElementPtrInst *GepII1 = GetElementPtrInst::Create(Gep1, C2xi32a); - GetElementPtrInst *GepII2 = GetElementPtrInst::Create(Gep2, C2xi32b); - GetElementPtrInst *GepII3 = GetElementPtrInst::Create(Gep3, C2xi32a); + GetElementPtrInst *GepII0 = GetElementPtrInst::Create(I32Ty, Gep0, C2xi32b); + GetElementPtrInst *GepII1 = GetElementPtrInst::Create(I32Ty, Gep1, C2xi32a); + GetElementPtrInst *GepII2 = GetElementPtrInst::Create(I32Ty, Gep2, C2xi32b); + GetElementPtrInst *GepII3 = GetElementPtrInst::Create(I32Ty, Gep3, C2xi32a); EXPECT_EQ(GepII0->getNumIndices(), 1u); EXPECT_EQ(GepII1->getNumIndices(), 1u); diff --git a/unittests/IR/LegacyPassManagerTest.cpp b/unittests/IR/LegacyPassManagerTest.cpp index 4efc2f5b80574..66fd1ccd7f209 100644 --- a/unittests/IR/LegacyPassManagerTest.cpp +++ b/unittests/IR/LegacyPassManagerTest.cpp @@ -8,13 +8,12 @@ //===----------------------------------------------------------------------===// // // This unit test exercises the legacy pass manager infrastructure. We use the -// old names as well to ensure that the source-level compatibility wrapper -// works for out-of-tree code that expects to include llvm/PassManager.h and -// subclass the core pass classes. +// old names as well to ensure that the source-level compatibility is preserved +// where possible. // //===----------------------------------------------------------------------===// -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/LoopInfo.h" @@ -99,7 +98,6 @@ namespace llvm { initializeModuleNDMPass(*PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayoutPass>()); run++; return false; } @@ -176,7 +174,6 @@ namespace llvm { initializeCGPassPass(*PassRegistry::getPassRegistry()); } bool runOnSCC(CallGraphSCC &SCMM) override { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayoutPass>()); run(); return false; } @@ -215,7 +212,6 @@ namespace llvm { return false; } bool runOnLoop(Loop *L, LPPassManager &LPM) override { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayoutPass>()); run(); return false; } @@ -252,7 +248,6 @@ namespace llvm { return false; } bool runOnBasicBlock(BasicBlock &BB) override { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayoutPass>()); run(); return false; } @@ -277,7 +272,6 @@ namespace llvm { initializeFPassPass(*PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayoutPass>()); for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) { Function &F = *I; { @@ -302,8 +296,7 @@ namespace llvm { mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; - PassManager Passes; - Passes.add(new DataLayoutPass()); + legacy::PassManager Passes; Passes.add(mNDM2); Passes.add(mNDM); Passes.add(mNDNM); @@ -326,8 +319,7 @@ namespace llvm { mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; - PassManager Passes; - Passes.add(new DataLayoutPass()); + legacy::PassManager Passes; Passes.add(mNDM); Passes.add(mNDNM); Passes.add(mNDM2);// invalidates mNDM needed by mDNM @@ -348,8 +340,7 @@ namespace llvm { void MemoryTestHelper(int run) { std::unique_ptr<Module> M(makeLLVMModule()); T *P = new T(); - PassManager Passes; - Passes.add(new DataLayoutPass()); + legacy::PassManager Passes; Passes.add(P); Passes.run(*M); T::finishedOK(run); @@ -359,8 +350,7 @@ namespace llvm { void MemoryTestHelper(int run, int N) { Module *M = makeLLVMModule(); T *P = new T(); - PassManager Passes; - Passes.add(new DataLayoutPass()); + legacy::PassManager Passes; Passes.add(P); Passes.run(*M); T::finishedOK(run, N); @@ -397,8 +387,7 @@ namespace llvm { { SCOPED_TRACE("Running OnTheFlyTest"); struct OnTheFlyTest *O = new OnTheFlyTest(); - PassManager Passes; - Passes.add(new DataLayoutPass()); + legacy::PassManager Passes; Passes.add(O); Passes.run(*M); @@ -554,6 +543,6 @@ INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false) INITIALIZE_PASS(FPass, "fp","fp", false, false) INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false) -INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(LPass, "lp","lp", false, false) INITIALIZE_PASS(BPass, "bp","bp", false, false) diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index f862f049fccc3..6994e2133f6f0 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -1,4 +1,4 @@ -//===- llvm/unittest/IR/Metadata.cpp - Metadata unit tests ----------------===// +//===- unittests/IR/MetadataTest.cpp - Metadata unit tests ----------------===// // // The LLVM Compiler Infrastructure // @@ -9,26 +9,113 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace llvm; namespace { +TEST(ContextAndReplaceableUsesTest, FromContext) { + LLVMContext Context; + ContextAndReplaceableUses CRU(Context); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_FALSE(CRU.hasReplaceableUses()); + EXPECT_FALSE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) { + LLVMContext Context; + ContextAndReplaceableUses CRU(make_unique<ReplaceableMetadataImpl>(Context)); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_TRUE(CRU.hasReplaceableUses()); + EXPECT_TRUE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, makeReplaceable) { + LLVMContext Context; + ContextAndReplaceableUses CRU(Context); + CRU.makeReplaceable(make_unique<ReplaceableMetadataImpl>(Context)); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_TRUE(CRU.hasReplaceableUses()); + EXPECT_TRUE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, takeReplaceableUses) { + LLVMContext Context; + auto ReplaceableUses = make_unique<ReplaceableMetadataImpl>(Context); + auto *Ptr = ReplaceableUses.get(); + ContextAndReplaceableUses CRU(std::move(ReplaceableUses)); + ReplaceableUses = CRU.takeReplaceableUses(); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_FALSE(CRU.hasReplaceableUses()); + EXPECT_FALSE(CRU.getReplaceableUses()); + EXPECT_EQ(Ptr, ReplaceableUses.get()); +} + class MetadataTest : public testing::Test { +public: + MetadataTest() : M("test", Context), Counter(0) {} + protected: LLVMContext Context; + Module M; + int Counter; + MDNode *getNode() { return MDNode::get(Context, None); } MDNode *getNode(Metadata *MD) { return MDNode::get(Context, MD); } MDNode *getNode(Metadata *MD1, Metadata *MD2) { Metadata *MDs[] = {MD1, MD2}; return MDNode::get(Context, MDs); } + + MDTuple *getTuple() { return MDTuple::getDistinct(Context, None); } + DISubroutineType *getSubroutineType() { + return DISubroutineType::getDistinct(Context, 0, getNode(nullptr)); + } + DISubprogram *getSubprogram() { + return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0, + nullptr, false, false, 0, nullptr, 0, 0, 0, + 0); + } + DIScopeRef getSubprogramRef() { return getSubprogram()->getRef(); } + DIFile *getFile() { + return DIFile::getDistinct(Context, "file.c", "/path/to/dir"); + } + DITypeRef getBasicType(StringRef Name) { + return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name) + ->getRef(); + } + DITypeRef getDerivedType() { + return DIDerivedType::getDistinct(Context, dwarf::DW_TAG_pointer_type, "", + nullptr, 0, nullptr, + getBasicType("basictype"), 1, 2, 0, 0) + ->getRef(); + } + Constant *getConstant() { + return ConstantInt::get(Type::getInt32Ty(Context), Counter++); + } + ConstantAsMetadata *getConstantAsMetadata() { + return ConstantAsMetadata::get(getConstant()); + } + DITypeRef getCompositeType() { + return DICompositeType::getDistinct( + Context, dwarf::DW_TAG_structure_type, "", nullptr, 0, nullptr, + nullptr, 32, 32, 0, 0, nullptr, 0, nullptr, nullptr, "") + ->getRef(); + } + Function *getFunction(StringRef Name) { + return cast<Function>(M.getOrInsertFunction( + Name, FunctionType::get(Type::getVoidTy(Context), None, false))); + } }; typedef MetadataTest MDStringTest; @@ -130,19 +217,14 @@ TEST_F(MDNodeTest, Delete) { delete I; } -TEST_F(MDNodeTest, DeleteMDNodeFwdDecl) { - delete MDNode::getTemporary(Context, None); -} - TEST_F(MDNodeTest, SelfReference) { // !0 = !{!0} // !1 = !{!0} { - MDNode *Temp = MDNode::getTemporary(Context, None); - Metadata *Args[] = {Temp}; + auto Temp = MDNode::getTemporary(Context, None); + Metadata *Args[] = {Temp.get()}; MDNode *Self = MDNode::get(Context, Args); Self->replaceOperandWith(0, Self); - MDNode::deleteTemporary(Temp); ASSERT_EQ(Self, Self->getOperand(0)); // Self-references should be distinct, so MDNode::get() should grab a @@ -157,11 +239,10 @@ TEST_F(MDNodeTest, SelfReference) { // !0 = !{!0, !{}} // !1 = !{!0, !{}} { - MDNode *Temp = MDNode::getTemporary(Context, None); - Metadata *Args[] = {Temp, MDNode::get(Context, None)}; + auto Temp = MDNode::getTemporary(Context, None); + Metadata *Args[] = {Temp.get(), MDNode::get(Context, None)}; MDNode *Self = MDNode::get(Context, Args); Self->replaceOperandWith(0, Self); - MDNode::deleteTemporary(Temp); ASSERT_EQ(Self, Self->getOperand(0)); // Self-references should be distinct, so MDNode::get() should grab a @@ -187,7 +268,7 @@ TEST_F(MDNodeTest, Print) { std::string Expected; { raw_string_ostream OS(Expected); - OS << "!{"; + OS << "<" << (void *)N << "> = !{"; C->printAsOperand(OS); OS << ", "; S->printAsOperand(OS); @@ -195,7 +276,7 @@ TEST_F(MDNodeTest, Print) { MDNode *Nodes[] = {N0, N1, N2}; for (auto *Node : Nodes) OS << ", <" << (void *)Node << ">"; - OS << "}\n"; + OS << "}"; } std::string Actual; @@ -207,6 +288,105 @@ TEST_F(MDNodeTest, Print) { EXPECT_EQ(Expected, Actual); } +#define EXPECT_PRINTER_EQ(EXPECTED, PRINT) \ + do { \ + std::string Actual_; \ + raw_string_ostream OS(Actual_); \ + PRINT; \ + OS.flush(); \ + std::string Expected_(EXPECTED); \ + EXPECT_EQ(Expected_, Actual_); \ + } while (false) + +TEST_F(MDNodeTest, PrintTemporary) { + MDNode *Arg = getNode(); + TempMDNode Temp = MDNode::getTemporary(Context, Arg); + MDNode *N = getNode(Temp.get()); + Module M("test", Context); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("named"); + NMD->addOperand(N); + + EXPECT_PRINTER_EQ("!0 = !{!1}", N->print(OS, &M)); + EXPECT_PRINTER_EQ("!1 = <temporary!> !{!2}", Temp->print(OS, &M)); + EXPECT_PRINTER_EQ("!2 = !{}", Arg->print(OS, &M)); + + // Cleanup. + Temp->replaceAllUsesWith(Arg); +} + +TEST_F(MDNodeTest, PrintFromModule) { + Constant *C = ConstantInt::get(Type::getInt32Ty(Context), 7); + MDString *S = MDString::get(Context, "foo"); + MDNode *N0 = getNode(); + MDNode *N1 = getNode(N0); + MDNode *N2 = getNode(N0, N1); + + Metadata *Args[] = {ConstantAsMetadata::get(C), S, nullptr, N0, N1, N2}; + MDNode *N = MDNode::get(Context, Args); + Module M("test", Context); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("named"); + NMD->addOperand(N); + + std::string Expected; + { + raw_string_ostream OS(Expected); + OS << "!0 = !{"; + C->printAsOperand(OS); + OS << ", "; + S->printAsOperand(OS); + OS << ", null, !1, !2, !3}"; + } + + EXPECT_PRINTER_EQ(Expected, N->print(OS, &M)); +} + +TEST_F(MDNodeTest, PrintFromFunction) { + Module M("test", Context); + auto *FTy = FunctionType::get(Type::getVoidTy(Context), false); + auto *F0 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F0", &M); + auto *F1 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F1", &M); + auto *BB0 = BasicBlock::Create(Context, "entry", F0); + auto *BB1 = BasicBlock::Create(Context, "entry", F1); + auto *R0 = ReturnInst::Create(Context, BB0); + auto *R1 = ReturnInst::Create(Context, BB1); + auto *N0 = MDNode::getDistinct(Context, None); + auto *N1 = MDNode::getDistinct(Context, None); + R0->setMetadata("md", N0); + R1->setMetadata("md", N1); + + EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, &M)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, &M)); +} + +TEST_F(MDNodeTest, PrintFromMetadataAsValue) { + Module M("test", Context); + + auto *Intrinsic = + Function::Create(FunctionType::get(Type::getVoidTy(Context), + Type::getMetadataTy(Context), false), + GlobalValue::ExternalLinkage, "llvm.intrinsic", &M); + + auto *FTy = FunctionType::get(Type::getVoidTy(Context), false); + auto *F0 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F0", &M); + auto *F1 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F1", &M); + auto *BB0 = BasicBlock::Create(Context, "entry", F0); + auto *BB1 = BasicBlock::Create(Context, "entry", F1); + auto *N0 = MDNode::getDistinct(Context, None); + auto *N1 = MDNode::getDistinct(Context, None); + auto *MAV0 = MetadataAsValue::get(Context, N0); + auto *MAV1 = MetadataAsValue::get(Context, N1); + CallInst::Create(Intrinsic, MAV0, "", BB0); + CallInst::Create(Intrinsic, MAV1, "", BB1); + + EXPECT_PRINTER_EQ("!0 = distinct !{}", MAV0->print(OS)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", MAV1->print(OS)); + EXPECT_PRINTER_EQ("!0", MAV0->printAsOperand(OS, false)); + EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false)); + EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true)); + EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true)); +} +#undef EXPECT_PRINTER_EQ + TEST_F(MDNodeTest, NullOperand) { // metadata !{} MDNode *Empty = MDNode::get(Context, None); @@ -274,27 +454,47 @@ TEST_F(MDNodeTest, getDistinct) { ASSERT_EQ(Empty, MDNode::get(Context, None)); } -TEST_F(MDNodeTest, TempIsDistinct) { - MDNode *T = MDNode::getTemporary(Context, None); - EXPECT_TRUE(T->isDistinct()); - MDNode::deleteTemporary(T); +TEST_F(MDNodeTest, isUniqued) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_TRUE(U->isUniqued()); + EXPECT_FALSE(D->isUniqued()); + EXPECT_FALSE(T->isUniqued()); +} + +TEST_F(MDNodeTest, isDistinct) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_FALSE(U->isDistinct()); + EXPECT_TRUE(D->isDistinct()); + EXPECT_FALSE(T->isDistinct()); +} + +TEST_F(MDNodeTest, isTemporary) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_FALSE(U->isTemporary()); + EXPECT_FALSE(D->isTemporary()); + EXPECT_TRUE(T->isTemporary()); } TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) { // temporary !{} - MDNodeFwdDecl *Temp = MDNode::getTemporary(Context, None); + auto Temp = MDTuple::getTemporary(Context, None); ASSERT_FALSE(Temp->isResolved()); // distinct !{temporary !{}} - Metadata *Ops[] = {Temp}; + Metadata *Ops[] = {Temp.get()}; MDNode *Distinct = MDNode::getDistinct(Context, Ops); EXPECT_TRUE(Distinct->isResolved()); - EXPECT_EQ(Temp, Distinct->getOperand(0)); + EXPECT_EQ(Temp.get(), Distinct->getOperand(0)); // temporary !{} => !{} MDNode *Empty = MDNode::get(Context, None); Temp->replaceAllUsesWith(Empty); - MDNode::deleteTemporary(Temp); EXPECT_EQ(Empty, Distinct->getOperand(0)); } @@ -303,7 +503,7 @@ TEST_F(MDNodeTest, handleChangedOperandRecursion) { MDNode *N0 = MDNode::get(Context, None); // !1 = !{!3, null} - std::unique_ptr<MDNodeFwdDecl> Temp3(MDNode::getTemporary(Context, None)); + auto Temp3 = MDTuple::getTemporary(Context, None); Metadata *Ops1[] = {Temp3.get(), nullptr}; MDNode *N1 = MDNode::get(Context, Ops1); @@ -367,7 +567,7 @@ TEST_F(MDNodeTest, replaceResolvedOperand) { // a global value that gets RAUW'ed. // // Use a temporary node to keep N from being resolved. - std::unique_ptr<MDNodeFwdDecl> Temp(MDNodeFwdDecl::get(Context, None)); + auto Temp = MDTuple::getTemporary(Context, None); Metadata *Ops[] = {nullptr, Temp.get()}; MDNode *Empty = MDTuple::get(Context, ArrayRef<Metadata *>()); @@ -387,41 +587,1432 @@ TEST_F(MDNodeTest, replaceResolvedOperand) { Temp->replaceAllUsesWith(nullptr); } -typedef MetadataTest MDLocationTest; +TEST_F(MDNodeTest, replaceWithUniqued) { + auto *Empty = MDTuple::get(Context, None); + MDTuple *FirstUniqued; + { + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); -TEST_F(MDLocationTest, Overflow) { - MDNode *N = MDNode::get(Context, None); + // Don't expect a collision. + auto *Current = Temp.get(); + FirstUniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(FirstUniqued->isUniqued()); + EXPECT_TRUE(FirstUniqued->isResolved()); + EXPECT_EQ(Current, FirstUniqued); + } + { + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Should collide with Uniqued above this time. + auto *Uniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(Uniqued->isUniqued()); + EXPECT_TRUE(Uniqued->isResolved()); + EXPECT_EQ(FirstUniqued, Uniqued); + } { - MDLocation *L = MDLocation::get(Context, 2, 7, N); + auto Unresolved = MDTuple::getTemporary(Context, None); + Metadata *Ops[] = {Unresolved.get()}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Shouldn't be resolved. + auto *Uniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(Uniqued->isUniqued()); + EXPECT_FALSE(Uniqued->isResolved()); + + // Should be a different node. + EXPECT_NE(FirstUniqued, Uniqued); + + // Should resolve when we update its node (note: be careful to avoid a + // collision with any other nodes above). + Uniqued->replaceOperandWith(0, nullptr); + EXPECT_TRUE(Uniqued->isResolved()); + } +} + +TEST_F(MDNodeTest, replaceWithUniquedResolvingOperand) { + // temp !{} + MDTuple *Op = MDTuple::getTemporary(Context, None).release(); + EXPECT_FALSE(Op->isResolved()); + + // temp !{temp !{}} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + EXPECT_FALSE(N->isResolved()); + + // temp !{temp !{}} => !{temp !{}} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + EXPECT_FALSE(N->isResolved()); + + // !{temp !{}} => !{!{}} + ASSERT_EQ(Op, MDNode::replaceWithUniqued(TempMDTuple(Op))); + EXPECT_TRUE(Op->isResolved()); + EXPECT_TRUE(N->isResolved()); +} + +TEST_F(MDNodeTest, replaceWithUniquedChangingOperand) { + // i1* @GV + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr<GlobalVariable> GV( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get()); + + // temp !{i1* @GV} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + + // temp !{i1* @GV} => !{i1* @GV} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + ASSERT_TRUE(N->isUniqued()); + + // !{i1* @GV} => !{null} + GV.reset(); + ASSERT_TRUE(N->isUniqued()); + Metadata *NullOps[] = {nullptr}; + ASSERT_EQ(N, MDTuple::get(Context, NullOps)); +} + +TEST_F(MDNodeTest, replaceWithDistinct) { + { + auto *Empty = MDTuple::get(Context, None); + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Don't expect a collision. + auto *Current = Temp.get(); + auto *Distinct = MDNode::replaceWithDistinct(std::move(Temp)); + EXPECT_TRUE(Distinct->isDistinct()); + EXPECT_TRUE(Distinct->isResolved()); + EXPECT_EQ(Current, Distinct); + } + { + auto Unresolved = MDTuple::getTemporary(Context, None); + Metadata *Ops[] = {Unresolved.get()}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Don't expect a collision. + auto *Current = Temp.get(); + auto *Distinct = MDNode::replaceWithDistinct(std::move(Temp)); + EXPECT_TRUE(Distinct->isDistinct()); + EXPECT_TRUE(Distinct->isResolved()); + EXPECT_EQ(Current, Distinct); + + // Cleanup; required for teardown. + Unresolved->replaceAllUsesWith(nullptr); + } +} + +TEST_F(MDNodeTest, replaceWithPermanent) { + Metadata *Ops[] = {nullptr}; + auto Temp = MDTuple::getTemporary(Context, Ops); + auto *T = Temp.get(); + + // U is a normal, uniqued node that references T. + auto *U = MDTuple::get(Context, T); + EXPECT_TRUE(U->isUniqued()); + + // Make Temp self-referencing. + Temp->replaceOperandWith(0, T); + + // Try to uniquify Temp. This should, despite the name in the API, give a + // 'distinct' node, since self-references aren't allowed to be uniqued. + // + // Since it's distinct, N should have the same address as when it was a + // temporary (i.e., be equal to T not U). + auto *N = MDNode::replaceWithPermanent(std::move(Temp)); + EXPECT_EQ(N, T); + EXPECT_TRUE(N->isDistinct()); + + // U should be the canonical unique node with N as the argument. + EXPECT_EQ(U, MDTuple::get(Context, N)); + EXPECT_TRUE(U->isUniqued()); + + // This temporary should collide with U when replaced, but it should still be + // uniqued. + EXPECT_EQ(U, MDNode::replaceWithPermanent(MDTuple::getTemporary(Context, N))); + EXPECT_TRUE(U->isUniqued()); + + // This temporary should become a new uniqued node. + auto Temp2 = MDTuple::getTemporary(Context, U); + auto *V = Temp2.get(); + EXPECT_EQ(V, MDNode::replaceWithPermanent(std::move(Temp2))); + EXPECT_TRUE(V->isUniqued()); + EXPECT_EQ(U, V->getOperand(0)); +} + +TEST_F(MDNodeTest, deleteTemporaryWithTrackingRef) { + TrackingMDRef Ref; + EXPECT_EQ(nullptr, Ref.get()); + { + auto Temp = MDTuple::getTemporary(Context, None); + Ref.reset(Temp.get()); + EXPECT_EQ(Temp.get(), Ref.get()); + } + EXPECT_EQ(nullptr, Ref.get()); +} + +typedef MetadataTest DILocationTest; + +TEST_F(DILocationTest, Overflow) { + DISubprogram *N = getSubprogram(); + { + DILocation *L = DILocation::get(Context, 2, 7, N); EXPECT_EQ(2u, L->getLine()); EXPECT_EQ(7u, L->getColumn()); } - unsigned U24 = 1u << 24; - unsigned U8 = 1u << 8; + unsigned U16 = 1u << 16; { - MDLocation *L = MDLocation::get(Context, U24 - 1, U8 - 1, N); - EXPECT_EQ(U24 - 1, L->getLine()); - EXPECT_EQ(U8 - 1, L->getColumn()); + DILocation *L = DILocation::get(Context, UINT32_MAX, U16 - 1, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); + EXPECT_EQ(U16 - 1, L->getColumn()); } { - MDLocation *L = MDLocation::get(Context, U24, U8, N); - EXPECT_EQ(0u, L->getLine()); + DILocation *L = DILocation::get(Context, UINT32_MAX, U16, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); EXPECT_EQ(0u, L->getColumn()); } { - MDLocation *L = MDLocation::get(Context, U24 + 1, U8 + 1, N); - EXPECT_EQ(0u, L->getLine()); + DILocation *L = DILocation::get(Context, UINT32_MAX, U16 + 1, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); EXPECT_EQ(0u, L->getColumn()); } } -TEST_F(MDLocationTest, getDistinct) { - MDNode *N = MDNode::get(Context, None); - MDLocation *L0 = MDLocation::getDistinct(Context, 2, 7, N); +TEST_F(DILocationTest, getDistinct) { + MDNode *N = getSubprogram(); + DILocation *L0 = DILocation::getDistinct(Context, 2, 7, N); EXPECT_TRUE(L0->isDistinct()); - MDLocation *L1 = MDLocation::get(Context, 2, 7, N); + DILocation *L1 = DILocation::get(Context, 2, 7, N); EXPECT_FALSE(L1->isDistinct()); - EXPECT_EQ(L1, MDLocation::get(Context, 2, 7, N)); + EXPECT_EQ(L1, DILocation::get(Context, 2, 7, N)); +} + +TEST_F(DILocationTest, getTemporary) { + MDNode *N = MDNode::get(Context, None); + auto L = DILocation::getTemporary(Context, 2, 7, N); + EXPECT_TRUE(L->isTemporary()); + EXPECT_FALSE(L->isResolved()); +} + +typedef MetadataTest GenericDINodeTest; + +TEST_F(GenericDINodeTest, get) { + StringRef Header = "header"; + auto *Empty = MDNode::get(Context, None); + Metadata *Ops1[] = {Empty}; + auto *N = GenericDINode::get(Context, 15, Header, Ops1); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(2u, N->getNumOperands()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(MDString::get(Context, Header), N->getOperand(0)); + EXPECT_EQ(1u, N->getNumDwarfOperands()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + EXPECT_EQ(Empty, N->getOperand(1)); + ASSERT_TRUE(N->isUniqued()); + + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); + + N->replaceOperandWith(1, nullptr); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(nullptr, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + + Metadata *Ops2[] = {nullptr}; + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops2)); + + N->replaceDwarfOperandWith(0, Empty); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); + + TempGenericDINode Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(GenericDINodeTest, getEmptyHeader) { + // Canonicalize !"" to null. + auto *N = GenericDINode::get(Context, 15, StringRef(), None); + EXPECT_EQ(StringRef(), N->getHeader()); + EXPECT_EQ(nullptr, N->getOperand(0)); +} + +typedef MetadataTest DISubrangeTest; + +TEST_F(DISubrangeTest, get) { + auto *N = DISubrange::get(Context, 5, 7); + EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); + EXPECT_EQ(5, N->getCount()); + EXPECT_EQ(7, N->getLowerBound()); + EXPECT_EQ(N, DISubrange::get(Context, 5, 7)); + EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5)); + + TempDISubrange Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DISubrangeTest, getEmptyArray) { + auto *N = DISubrange::get(Context, -1, 0); + EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); + EXPECT_EQ(-1, N->getCount()); + EXPECT_EQ(0, N->getLowerBound()); + EXPECT_EQ(N, DISubrange::get(Context, -1, 0)); +} + +typedef MetadataTest DIEnumeratorTest; + +TEST_F(DIEnumeratorTest, get) { + auto *N = DIEnumerator::get(Context, 7, "name"); + EXPECT_EQ(dwarf::DW_TAG_enumerator, N->getTag()); + EXPECT_EQ(7, N->getValue()); + EXPECT_EQ("name", N->getName()); + EXPECT_EQ(N, DIEnumerator::get(Context, 7, "name")); + + EXPECT_NE(N, DIEnumerator::get(Context, 8, "name")); + EXPECT_NE(N, DIEnumerator::get(Context, 7, "nam")); + + TempDIEnumerator Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIBasicTypeTest; + +TEST_F(DIBasicTypeTest, get) { + auto *N = + DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, 26, 7); + EXPECT_EQ(dwarf::DW_TAG_base_type, N->getTag()); + EXPECT_EQ("special", N->getName()); + EXPECT_EQ(33u, N->getSizeInBits()); + EXPECT_EQ(26u, N->getAlignInBits()); + EXPECT_EQ(7u, N->getEncoding()); + EXPECT_EQ(0u, N->getLine()); + EXPECT_EQ(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 26, 7)); + + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, + "special", 33, 26, 7)); + EXPECT_NE(N, + DIBasicType::get(Context, dwarf::DW_TAG_base_type, "s", 33, 26, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 32, + 26, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 25, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 26, 6)); + + TempDIBasicType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIBasicTypeTest, getWithLargeValues) { + auto *N = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", + UINT64_MAX, UINT64_MAX - 1, 7); + EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); + EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits()); +} + +TEST_F(DIBasicTypeTest, getUnspecified) { + auto *N = + DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, "unspecified"); + EXPECT_EQ(dwarf::DW_TAG_unspecified_type, N->getTag()); + EXPECT_EQ("unspecified", N->getName()); + EXPECT_EQ(0u, N->getSizeInBits()); + EXPECT_EQ(0u, N->getAlignInBits()); + EXPECT_EQ(0u, N->getEncoding()); + EXPECT_EQ(0u, N->getLine()); +} + +typedef MetadataTest DITypeTest; + +TEST_F(DITypeTest, clone) { + // Check that DIType has a specialized clone that returns TempDIType. + DIType *N = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, 32, + dwarf::DW_ATE_signed); + + TempDIType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DITypeTest, setFlags) { + // void (void) + Metadata *TypesOps[] = {nullptr}; + Metadata *Types = MDTuple::get(Context, TypesOps); + + DIType *D = DISubroutineType::getDistinct(Context, 0u, Types); + EXPECT_EQ(0u, D->getFlags()); + D->setFlags(DINode::FlagRValueReference); + EXPECT_EQ(DINode::FlagRValueReference, D->getFlags()); + D->setFlags(0u); + EXPECT_EQ(0u, D->getFlags()); + + TempDIType T = DISubroutineType::getTemporary(Context, 0u, Types); + EXPECT_EQ(0u, T->getFlags()); + T->setFlags(DINode::FlagRValueReference); + EXPECT_EQ(DINode::FlagRValueReference, T->getFlags()); + T->setFlags(0u); + EXPECT_EQ(0u, T->getFlags()); +} + +typedef MetadataTest DIDerivedTypeTest; + +TEST_F(DIDerivedTypeTest, get) { + DIFile *File = getFile(); + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getBasicType("basic"); + MDTuple *ExtraData = getTuple(); + + auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", + File, 1, Scope, BaseType, 2, 3, 4, 5, ExtraData); + EXPECT_EQ(dwarf::DW_TAG_pointer_type, N->getTag()); + EXPECT_EQ("something", N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(1u, N->getLine()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(BaseType, N->getBaseType()); + EXPECT_EQ(2u, N->getSizeInBits()); + EXPECT_EQ(3u, N->getAlignInBits()); + EXPECT_EQ(4u, N->getOffsetInBits()); + EXPECT_EQ(5u, N->getFlags()); + EXPECT_EQ(ExtraData, N->getExtraData()); + EXPECT_EQ(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_reference_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "else", + File, 1, Scope, BaseType, 2, 3, 4, 5, + ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", getFile(), 1, Scope, BaseType, 2, + 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 2, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, getSubprogramRef(), + BaseType, 2, 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get( + Context, dwarf::DW_TAG_pointer_type, "something", File, 1, + Scope, getBasicType("basic2"), 2, 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 3, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 2, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 5, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 4, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, getTuple())); + + TempDIDerivedType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIDerivedTypeTest, getWithLargeValues) { + DIFile *File = getFile(); + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getBasicType("basic"); + MDTuple *ExtraData = getTuple(); + + auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", + File, 1, Scope, BaseType, UINT64_MAX, + UINT64_MAX - 1, UINT64_MAX - 2, 5, ExtraData); + EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); + EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits()); + EXPECT_EQ(UINT64_MAX - 2, N->getOffsetInBits()); +} + +typedef MetadataTest DICompositeTypeTest; + +TEST_F(DICompositeTypeTest, get) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = 2; + uint64_t AlignInBits = 3; + uint64_t OffsetInBits = 4; + unsigned Flags = 5; + MDTuple *Elements = getTuple(); + unsigned RuntimeLang = 6; + DITypeRef VTableHolder = getCompositeType(); + MDTuple *TemplateParams = getTuple(); + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier); + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(BaseType, N->getBaseType()); + EXPECT_EQ(SizeInBits, N->getSizeInBits()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); + EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(Elements, N->getElements().get()); + EXPECT_EQ(RuntimeLang, N->getRuntimeLang()); + EXPECT_EQ(VTableHolder, N->getVTableHolder()); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + EXPECT_EQ(Identifier, N->getIdentifier()); + + EXPECT_EQ(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + + EXPECT_NE(N, DICompositeType::get(Context, Tag + 1, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, "abc", File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, getFile(), Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line + 1, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, getSubprogramRef(), BaseType, + SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, + RuntimeLang, VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, getBasicType("other"), + SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, + RuntimeLang, VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits + 1, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits + 1, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits + 1, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags + 1, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, getTuple(), RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang + 1, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, + getCompositeType(), TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, getTuple(), Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, "other")); + + // Be sure that missing identifiers get null pointers. + EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, "") + ->getRawIdentifier()); + EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams) + ->getRawIdentifier()); + + TempDICompositeType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DICompositeTypeTest, getWithLargeValues) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = UINT64_MAX; + uint64_t AlignInBits = UINT64_MAX - 1; + uint64_t OffsetInBits = UINT64_MAX - 2; + unsigned Flags = 5; + MDTuple *Elements = getTuple(); + unsigned RuntimeLang = 6; + DITypeRef VTableHolder = getCompositeType(); + MDTuple *TemplateParams = getTuple(); + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier); + EXPECT_EQ(SizeInBits, N->getSizeInBits()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); + EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); +} + +TEST_F(DICompositeTypeTest, replaceOperands) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = 2; + uint64_t AlignInBits = 3; + uint64_t OffsetInBits = 4; + unsigned Flags = 5; + unsigned RuntimeLang = 6; + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier); + + auto *Elements = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getElements().get()); + N->replaceElements(Elements); + EXPECT_EQ(Elements, N->getElements().get()); + N->replaceElements(nullptr); + EXPECT_EQ(nullptr, N->getElements().get()); + + DITypeRef VTableHolder = getCompositeType(); + EXPECT_EQ(nullptr, N->getVTableHolder()); + N->replaceVTableHolder(VTableHolder); + EXPECT_EQ(VTableHolder, N->getVTableHolder()); + N->replaceVTableHolder(nullptr); + EXPECT_EQ(nullptr, N->getVTableHolder()); + + auto *TemplateParams = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getTemplateParams().get()); + N->replaceTemplateParams(TemplateParams); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + N->replaceTemplateParams(nullptr); + EXPECT_EQ(nullptr, N->getTemplateParams().get()); +} + +typedef MetadataTest DISubroutineTypeTest; + +TEST_F(DISubroutineTypeTest, get) { + unsigned Flags = 1; + MDTuple *TypeArray = getTuple(); + + auto *N = DISubroutineType::get(Context, Flags, TypeArray); + EXPECT_EQ(dwarf::DW_TAG_subroutine_type, N->getTag()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(TypeArray, N->getTypeArray().get()); + EXPECT_EQ(N, DISubroutineType::get(Context, Flags, TypeArray)); + + EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, TypeArray)); + EXPECT_NE(N, DISubroutineType::get(Context, Flags, getTuple())); + + TempDISubroutineType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); + + // Test always-empty operands. + EXPECT_EQ(nullptr, N->getScope()); + EXPECT_EQ(nullptr, N->getFile()); + EXPECT_EQ("", N->getName()); + EXPECT_EQ(nullptr, N->getBaseType()); + EXPECT_EQ(nullptr, N->getVTableHolder()); + EXPECT_EQ(nullptr, N->getTemplateParams().get()); + EXPECT_EQ("", N->getIdentifier()); +} + +typedef MetadataTest DIFileTest; + +TEST_F(DIFileTest, get) { + StringRef Filename = "file"; + StringRef Directory = "dir"; + auto *N = DIFile::get(Context, Filename, Directory); + + EXPECT_EQ(dwarf::DW_TAG_file_type, N->getTag()); + EXPECT_EQ(Filename, N->getFilename()); + EXPECT_EQ(Directory, N->getDirectory()); + EXPECT_EQ(N, DIFile::get(Context, Filename, Directory)); + + EXPECT_NE(N, DIFile::get(Context, "other", Directory)); + EXPECT_NE(N, DIFile::get(Context, Filename, "other")); + + TempDIFile Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIFileTest, ScopeGetFile) { + // Ensure that DIScope::getFile() returns itself. + DIScope *N = DIFile::get(Context, "file", "dir"); + EXPECT_EQ(N, N->getFile()); +} + +typedef MetadataTest DICompileUnitTest; + +TEST_F(DICompileUnitTest, get) { + unsigned SourceLanguage = 1; + DIFile *File = getFile(); + StringRef Producer = "some producer"; + bool IsOptimized = false; + StringRef Flags = "flag after flag"; + unsigned RuntimeVersion = 2; + StringRef SplitDebugFilename = "another/file"; + unsigned EmissionKind = 3; + MDTuple *EnumTypes = getTuple(); + MDTuple *RetainedTypes = getTuple(); + MDTuple *Subprograms = getTuple(); + MDTuple *GlobalVariables = getTuple(); + MDTuple *ImportedEntities = getTuple(); + uint64_t DWOId = 0xc0ffee; + auto *N = DICompileUnit::get( + Context, SourceLanguage, File, Producer, IsOptimized, Flags, + RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, DWOId); + + EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); + EXPECT_EQ(SourceLanguage, N->getSourceLanguage()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Producer, N->getProducer()); + EXPECT_EQ(IsOptimized, N->isOptimized()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(RuntimeVersion, N->getRuntimeVersion()); + EXPECT_EQ(SplitDebugFilename, N->getSplitDebugFilename()); + EXPECT_EQ(EmissionKind, N->getEmissionKind()); + EXPECT_EQ(EnumTypes, N->getEnumTypes().get()); + EXPECT_EQ(RetainedTypes, N->getRetainedTypes().get()); + EXPECT_EQ(Subprograms, N->getSubprograms().get()); + EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); + EXPECT_EQ(ImportedEntities, N->getImportedEntities().get()); + EXPECT_EQ(DWOId, N->getDWOId()); + EXPECT_EQ(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage + 1, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, getFile(), Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, "other", + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + !IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, "other", RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion + 1, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, "other", + EmissionKind, EnumTypes, RetainedTypes, + Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind + 1, + EnumTypes, RetainedTypes, Subprograms, + GlobalVariables, ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, getTuple(), + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + getTuple(), Subprograms, GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, getTuple(), GlobalVariables, + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, getTuple(), + ImportedEntities, DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + getTuple(), DWOId)); + EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, + IsOptimized, Flags, RuntimeVersion, + SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, + ImportedEntities, DWOId + 1)); + + TempDICompileUnit Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DICompileUnitTest, replaceArrays) { + unsigned SourceLanguage = 1; + DIFile *File = getFile(); + StringRef Producer = "some producer"; + bool IsOptimized = false; + StringRef Flags = "flag after flag"; + unsigned RuntimeVersion = 2; + StringRef SplitDebugFilename = "another/file"; + unsigned EmissionKind = 3; + MDTuple *EnumTypes = MDTuple::getDistinct(Context, None); + MDTuple *RetainedTypes = MDTuple::getDistinct(Context, None); + MDTuple *ImportedEntities = MDTuple::getDistinct(Context, None); + uint64_t DWOId = 0xc0ffee; + auto *N = DICompileUnit::get( + Context, SourceLanguage, File, Producer, IsOptimized, Flags, + RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, nullptr, nullptr, ImportedEntities, DWOId); + + auto *Subprograms = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getSubprograms().get()); + N->replaceSubprograms(Subprograms); + EXPECT_EQ(Subprograms, N->getSubprograms().get()); + N->replaceSubprograms(nullptr); + EXPECT_EQ(nullptr, N->getSubprograms().get()); + + auto *GlobalVariables = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getGlobalVariables().get()); + N->replaceGlobalVariables(GlobalVariables); + EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); + N->replaceGlobalVariables(nullptr); + EXPECT_EQ(nullptr, N->getGlobalVariables().get()); +} + +typedef MetadataTest DISubprogramTest; + +TEST_F(DISubprogramTest, get) { + DIScopeRef Scope = getCompositeType(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 2; + DISubroutineType *Type = getSubroutineType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + unsigned ScopeLine = 3; + DITypeRef ContainingType = getCompositeType(); + unsigned Virtuality = 4; + unsigned VirtualIndex = 5; + unsigned Flags = 6; + bool IsOptimized = false; + llvm::Function *Function = getFunction("foo"); + MDTuple *TemplateParams = getTuple(); + DISubprogram *Declaration = getSubprogram(); + MDTuple *Variables = getTuple(); + + auto *N = DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, + IsOptimized, Function, TemplateParams, Declaration, Variables); + + EXPECT_EQ(dwarf::DW_TAG_subprogram, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(LinkageName, N->getLinkageName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); + EXPECT_EQ(IsDefinition, N->isDefinition()); + EXPECT_EQ(ScopeLine, N->getScopeLine()); + EXPECT_EQ(ContainingType, N->getContainingType()); + EXPECT_EQ(Virtuality, N->getVirtuality()); + EXPECT_EQ(VirtualIndex, N->getVirtualIndex()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(IsOptimized, N->isOptimized()); + EXPECT_EQ(Function, N->getFunction()); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + EXPECT_EQ(Declaration, N->getDeclaration()); + EXPECT_EQ(Variables, N->getVariables().get()); + EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + + EXPECT_NE(N, DISubprogram::get(Context, getCompositeType(), Name, LinkageName, + File, Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, "other", LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other", File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, getFile(), + Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, + Line + 1, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, + getSubroutineType(), IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, + Function, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, !IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, !IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, + ScopeLine + 1, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + getCompositeType(), Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality + 1, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex + 1, + Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + ~Flags, IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, !IsOptimized, Function, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, getFunction("bar"), + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, getTuple(), + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + getSubprogram(), Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, Function, TemplateParams, + Declaration, getTuple())); + + TempDISubprogram Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DISubprogramTest, replaceFunction) { + DIScopeRef Scope = getCompositeType(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 2; + DISubroutineType *Type = getSubroutineType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + unsigned ScopeLine = 3; + DITypeRef ContainingType = getCompositeType(); + unsigned Virtuality = 4; + unsigned VirtualIndex = 5; + unsigned Flags = 6; + bool IsOptimized = false; + MDTuple *TemplateParams = getTuple(); + DISubprogram *Declaration = getSubprogram(); + MDTuple *Variables = getTuple(); + + auto *N = DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, + IsOptimized, nullptr, TemplateParams, Declaration, Variables); + + EXPECT_EQ(nullptr, N->getFunction()); + + std::unique_ptr<Function> F( + Function::Create(FunctionType::get(Type::getVoidTy(Context), false), + GlobalValue::ExternalLinkage)); + N->replaceFunction(F.get()); + EXPECT_EQ(F.get(), N->getFunction()); + + N->replaceFunction(nullptr); + EXPECT_EQ(nullptr, N->getFunction()); +} + +typedef MetadataTest DILexicalBlockTest; + +TEST_F(DILexicalBlockTest, get) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + unsigned Line = 5; + unsigned Column = 8; + + auto *N = DILexicalBlock::get(Context, Scope, File, Line, Column); + + EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Column, N->getColumn()); + EXPECT_EQ(N, DILexicalBlock::get(Context, Scope, File, Line, Column)); + + EXPECT_NE(N, + DILexicalBlock::get(Context, getSubprogram(), File, Line, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, getFile(), Line, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line + 1, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line, Column + 1)); + + TempDILexicalBlock Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DILexicalBlockFileTest; + +TEST_F(DILexicalBlockFileTest, get) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + unsigned Discriminator = 5; + + auto *N = DILexicalBlockFile::get(Context, Scope, File, Discriminator); + + EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Discriminator, N->getDiscriminator()); + EXPECT_EQ(N, DILexicalBlockFile::get(Context, Scope, File, Discriminator)); + + EXPECT_NE(N, DILexicalBlockFile::get(Context, getSubprogram(), File, + Discriminator)); + EXPECT_NE(N, + DILexicalBlockFile::get(Context, Scope, getFile(), Discriminator)); + EXPECT_NE(N, + DILexicalBlockFile::get(Context, Scope, File, Discriminator + 1)); + + TempDILexicalBlockFile Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DINamespaceTest; + +TEST_F(DINamespaceTest, get) { + DIScope *Scope = getFile(); + DIFile *File = getFile(); + StringRef Name = "namespace"; + unsigned Line = 5; + + auto *N = DINamespace::get(Context, Scope, File, Name, Line); + + EXPECT_EQ(dwarf::DW_TAG_namespace, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(N, DINamespace::get(Context, Scope, File, Name, Line)); + + EXPECT_NE(N, DINamespace::get(Context, getFile(), File, Name, Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, getFile(), Name, Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, File, "other", Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, File, Name, Line + 1)); + + TempDINamespace Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DITemplateTypeParameterTest; + +TEST_F(DITemplateTypeParameterTest, get) { + StringRef Name = "template"; + DITypeRef Type = getBasicType("basic"); + + auto *N = DITemplateTypeParameter::get(Context, Name, Type); + + EXPECT_EQ(dwarf::DW_TAG_template_type_parameter, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(N, DITemplateTypeParameter::get(Context, Name, Type)); + + EXPECT_NE(N, DITemplateTypeParameter::get(Context, "other", Type)); + EXPECT_NE(N, + DITemplateTypeParameter::get(Context, Name, getBasicType("other"))); + + TempDITemplateTypeParameter Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DITemplateValueParameterTest; + +TEST_F(DITemplateValueParameterTest, get) { + unsigned Tag = dwarf::DW_TAG_template_value_parameter; + StringRef Name = "template"; + DITypeRef Type = getBasicType("basic"); + Metadata *Value = getConstantAsMetadata(); + + auto *N = DITemplateValueParameter::get(Context, Tag, Name, Type, Value); + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(Value, N->getValue()); + EXPECT_EQ(N, DITemplateValueParameter::get(Context, Tag, Name, Type, Value)); + + EXPECT_NE(N, DITemplateValueParameter::get( + Context, dwarf::DW_TAG_GNU_template_template_param, Name, + Type, Value)); + EXPECT_NE(N, + DITemplateValueParameter::get(Context, Tag, "other", Type, Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, + getBasicType("other"), Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, Type, + getConstantAsMetadata())); + + TempDITemplateValueParameter Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIGlobalVariableTest; + +TEST_F(DIGlobalVariableTest, get) { + DIScope *Scope = getSubprogram(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 5; + DITypeRef Type = getDerivedType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + Constant *Variable = getConstant(); + DIDerivedType *StaticDataMemberDeclaration = + cast<DIDerivedType>(getDerivedType()); + + auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, Variable, + StaticDataMemberDeclaration); + EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(LinkageName, N->getLinkageName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); + EXPECT_EQ(IsDefinition, N->isDefinition()); + EXPECT_EQ(Variable, N->getVariable()); + EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); + EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + + EXPECT_NE(N, + DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, + File, Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, + Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line + 1, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + getDerivedType(), IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, !IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, !IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, + getConstant(), StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, Variable, + cast<DIDerivedType>(getDerivedType()))); + + TempDIGlobalVariable Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DILocalVariableTest; + +TEST_F(DILocalVariableTest, get) { + unsigned Tag = dwarf::DW_TAG_arg_variable; + DILocalScope *Scope = getSubprogram(); + StringRef Name = "name"; + DIFile *File = getFile(); + unsigned Line = 5; + DITypeRef Type = getDerivedType(); + unsigned Arg = 6; + unsigned Flags = 7; + + auto *N = DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + Arg, Flags); + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(Arg, N->getArg()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + Arg, Flags)); + + EXPECT_NE(N, DILocalVariable::get(Context, dwarf::DW_TAG_auto_variable, Scope, + Name, File, Line, Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, getSubprogram(), Name, File, + Line, Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, "other", File, Line, + Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, getFile(), Line, + Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line + 1, + Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, + getDerivedType(), Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + Arg + 1, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + Arg, ~Flags)); + + TempDILocalVariable Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DILocalVariableTest, getArg256) { + EXPECT_EQ(255u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, + getSubprogram(), "", getFile(), 0, + nullptr, 255, 0) + ->getArg()); + EXPECT_EQ(256u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, + getSubprogram(), "", getFile(), 0, + nullptr, 256, 0) + ->getArg()); + EXPECT_EQ(257u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, + getSubprogram(), "", getFile(), 0, + nullptr, 257, 0) + ->getArg()); + unsigned Max = UINT16_MAX; + EXPECT_EQ(Max, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, + getSubprogram(), "", getFile(), 0, + nullptr, Max, 0) + ->getArg()); +} + +typedef MetadataTest DIExpressionTest; + +TEST_F(DIExpressionTest, get) { + uint64_t Elements[] = {2, 6, 9, 78, 0}; + auto *N = DIExpression::get(Context, Elements); + EXPECT_EQ(makeArrayRef(Elements), N->getElements()); + EXPECT_EQ(N, DIExpression::get(Context, Elements)); + + EXPECT_EQ(5u, N->getNumElements()); + EXPECT_EQ(2u, N->getElement(0)); + EXPECT_EQ(6u, N->getElement(1)); + EXPECT_EQ(9u, N->getElement(2)); + EXPECT_EQ(78u, N->getElement(3)); + EXPECT_EQ(0u, N->getElement(4)); + + TempDIExpression Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIExpressionTest, isValid) { +#define EXPECT_VALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_TRUE(DIExpression::get(Context, Elements)->isValid()); \ + } while (false) +#define EXPECT_INVALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_FALSE(DIExpression::get(Context, Elements)->isValid()); \ + } while (false) + + // Empty expression should be valid. + EXPECT_TRUE(DIExpression::get(Context, None)); + + // Valid constructions. + EXPECT_VALID(dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_plus, 6, dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6, dwarf::DW_OP_bit_piece, 3, 7); + + // Invalid constructions. + EXPECT_INVALID(~0u); + EXPECT_INVALID(dwarf::DW_OP_plus); + EXPECT_INVALID(dwarf::DW_OP_bit_piece); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_plus, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_deref); + +#undef EXPECT_VALID +#undef EXPECT_INVALID +} + +typedef MetadataTest DIObjCPropertyTest; + +TEST_F(DIObjCPropertyTest, get) { + StringRef Name = "name"; + DIFile *File = getFile(); + unsigned Line = 5; + StringRef GetterName = "getter"; + StringRef SetterName = "setter"; + unsigned Attributes = 7; + DIType *Type = cast<DIBasicType>(getBasicType("basic")); + + auto *N = DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, Type); + + EXPECT_EQ(dwarf::DW_TAG_APPLE_property, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(GetterName, N->getGetterName()); + EXPECT_EQ(SetterName, N->getSetterName()); + EXPECT_EQ(Attributes, N->getAttributes()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, Type)); + + EXPECT_NE(N, DIObjCProperty::get(Context, "other", File, Line, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, getFile(), Line, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line + 1, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, "other", + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + "other", Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes + 1, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, + cast<DIBasicType>(getBasicType("other")))); + + TempDIObjCProperty Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIImportedEntityTest; + +TEST_F(DIImportedEntityTest, get) { + unsigned Tag = dwarf::DW_TAG_imported_module; + DIScope *Scope = getSubprogram(); + DINodeRef Entity = getCompositeType(); + unsigned Line = 5; + StringRef Name = "name"; + + auto *N = DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name); + + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Entity, N->getEntity()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(N, DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name)); + + EXPECT_NE(N, + DIImportedEntity::get(Context, dwarf::DW_TAG_imported_declaration, + Scope, Entity, Line, Name)); + EXPECT_NE(N, DIImportedEntity::get(Context, Tag, getSubprogram(), Entity, + Line, Name)); + EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, getCompositeType(), + Line, Name)); + EXPECT_NE(N, + DIImportedEntity::get(Context, Tag, Scope, Entity, Line + 1, Name)); + EXPECT_NE(N, + DIImportedEntity::get(Context, Tag, Scope, Entity, Line, "other")); + + TempDIImportedEntity Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); } typedef MetadataTest MetadataAsValueTest; @@ -490,7 +2081,7 @@ TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) { ConstantInt::get(getGlobalContext(), APInt(8, 0))); // Create a temporary to prevent nodes from resolving. - std::unique_ptr<MDNodeFwdDecl> Temp(MDNode::getTemporary(Context, None)); + auto Temp = MDTuple::getTemporary(Context, None); // When the first operand of N1 gets reset to nullptr, it'll collide with N2. Metadata *Ops1[] = {CI, CI, Temp.get()}; @@ -567,4 +2158,137 @@ TEST(NamedMDNodeTest, Search) { EXPECT_STREQ("!llvm.NMD1 = !{!0, !1}\n", oss.str().c_str()); } + +typedef MetadataTest FunctionAttachmentTest; +TEST_F(FunctionAttachmentTest, setMetadata) { + Function *F = getFunction("foo"); + ASSERT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + DISubprogram *SP1 = getSubprogram(); + DISubprogram *SP2 = getSubprogram(); + ASSERT_NE(SP1, SP2); + + F->setMetadata("dbg", SP1); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(SP1, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(SP1, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + F->setMetadata(LLVMContext::MD_dbg, SP2); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(SP2, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(SP2, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + F->setMetadata("dbg", nullptr); + EXPECT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + ASSERT_NE(T1, T2); + + F->setMetadata("other1", T1); + F->setMetadata("other2", T2); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(T1, F->getMetadata("other1")); + EXPECT_EQ(T2, F->getMetadata("other2")); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + + F->setMetadata("other1", T2); + F->setMetadata("other2", T1); + EXPECT_EQ(T2, F->getMetadata("other1")); + EXPECT_EQ(T1, F->getMetadata("other2")); + + F->setMetadata("other1", nullptr); + F->setMetadata("other2", nullptr); + EXPECT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata("other1")); + EXPECT_EQ(nullptr, F->getMetadata("other2")); +} + +TEST_F(FunctionAttachmentTest, getAll) { + Function *F = getFunction("foo"); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + MDTuple *P = getTuple(); + DISubprogram *SP = getSubprogram(); + + F->setMetadata("other1", T2); + F->setMetadata(LLVMContext::MD_dbg, SP); + F->setMetadata("other2", T1); + F->setMetadata(LLVMContext::MD_prof, P); + F->setMetadata("other2", T2); + F->setMetadata("other1", T1); + + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + F->getAllMetadata(MDs); + ASSERT_EQ(4u, MDs.size()); + EXPECT_EQ(LLVMContext::MD_dbg, MDs[0].first); + EXPECT_EQ(LLVMContext::MD_prof, MDs[1].first); + EXPECT_EQ(Context.getMDKindID("other1"), MDs[2].first); + EXPECT_EQ(Context.getMDKindID("other2"), MDs[3].first); + EXPECT_EQ(SP, MDs[0].second); + EXPECT_EQ(P, MDs[1].second); + EXPECT_EQ(T1, MDs[2].second); + EXPECT_EQ(T2, MDs[3].second); +} + +TEST_F(FunctionAttachmentTest, dropUnknownMetadata) { + Function *F = getFunction("foo"); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + MDTuple *P = getTuple(); + DISubprogram *SP = getSubprogram(); + + F->setMetadata("other1", T1); + F->setMetadata(LLVMContext::MD_dbg, SP); + F->setMetadata("other2", T2); + F->setMetadata(LLVMContext::MD_prof, P); + + unsigned Known[] = {Context.getMDKindID("other2"), LLVMContext::MD_prof}; + F->dropUnknownMetadata(Known); + + EXPECT_EQ(T2, F->getMetadata("other2")); + EXPECT_EQ(P, F->getMetadata(LLVMContext::MD_prof)); + EXPECT_EQ(nullptr, F->getMetadata("other1")); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + + F->setMetadata("other2", nullptr); + F->setMetadata(LLVMContext::MD_prof, nullptr); + EXPECT_FALSE(F->hasMetadata()); +} + +TEST_F(FunctionAttachmentTest, Verifier) { + Function *F = getFunction("foo"); + F->setMetadata("attach", getTuple()); + + // Confirm this has no body. + ASSERT_TRUE(F->empty()); + + // Functions without a body cannot have metadata attachments (they also can't + // be verified directly, so check that the module fails to verify). + EXPECT_TRUE(verifyModule(*F->getParent())); + + // Functions with a body can. + (void)new UnreachableInst(Context, BasicBlock::Create(Context, "bb", F)); + EXPECT_FALSE(verifyModule(*F->getParent())); + EXPECT_FALSE(verifyFunction(*F)); +} + +TEST_F(FunctionAttachmentTest, EntryCount) { + Function *F = getFunction("foo"); + EXPECT_FALSE(F->getEntryCount().hasValue()); + F->setEntryCount(12304); + EXPECT_TRUE(F->getEntryCount().hasValue()); + EXPECT_EQ(12304u, *F->getEntryCount()); +} + } diff --git a/unittests/IR/UseTest.cpp b/unittests/IR/UseTest.cpp index b575a59784085..d9d20af941d64 100644 --- a/unittests/IR/UseTest.cpp +++ b/unittests/IR/UseTest.cpp @@ -50,7 +50,7 @@ TEST(UseTest, sort) { }); unsigned I = 0; for (User *U : X.users()) { - snprintf(vnbuf, sizeof(vnbuf), "v%u", I++); + format("v%u", I++).snprint(vnbuf, sizeof(vnbuf)); EXPECT_EQ(vnbuf, U->getName()); } ASSERT_EQ(8u, I); @@ -60,7 +60,7 @@ TEST(UseTest, sort) { }); I = 0; for (User *U : X.users()) { - snprintf(vnbuf, sizeof(vnbuf), "v%u", (7 - I++)); + format("v%u", (7 - I++)).snprint(vnbuf, sizeof(vnbuf)); EXPECT_EQ(vnbuf, U->getName()); } ASSERT_EQ(8u, I); @@ -95,7 +95,7 @@ TEST(UseTest, reverse) { }); unsigned I = 0; for (User *U : X.users()) { - snprintf(vnbuf, sizeof(vnbuf), "v%u", I++); + format("v%u", I++).snprint(vnbuf, sizeof(vnbuf)); EXPECT_EQ(vnbuf, U->getName()); } ASSERT_EQ(8u, I); @@ -103,7 +103,7 @@ TEST(UseTest, reverse) { X.reverseUseList(); I = 0; for (User *U : X.users()) { - snprintf(vnbuf, sizeof(vnbuf), "v%u", (7 - I++)); + format("v%u", (7 - I++)).snprint(vnbuf, sizeof(vnbuf)); EXPECT_EQ(vnbuf, U->getName()); } ASSERT_EQ(8u, I); diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp index 403d2bcbda16e..e6eb7cbedc681 100644 --- a/unittests/IR/ValueHandleTest.cpp +++ b/unittests/IR/ValueHandleTest.cpp @@ -21,7 +21,7 @@ namespace { class ValueHandle : public testing::Test { protected: Constant *ConstantV; - std::auto_ptr<BitCastInst> BitcastV; + std::unique_ptr<BitCastInst> BitcastV; ValueHandle() : ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), @@ -244,8 +244,11 @@ TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) { RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {} private: - virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } - virtual void allUsesReplacedWith(Value *) { AURWCalls++; } + void deleted() override { + DeletedCalls++; + CallbackVH::deleted(); + } + void allUsesReplacedWith(Value *) override { AURWCalls++; } }; RecordingVH RVH; @@ -268,8 +271,11 @@ TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) { : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr) {} private: - virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } - virtual void allUsesReplacedWith(Value *new_value) { + void deleted() override { + DeletedCalls++; + CallbackVH::deleted(); + } + void allUsesReplacedWith(Value *new_value) override { EXPECT_EQ(nullptr, AURWArgument); AURWArgument = new_value; } @@ -298,11 +304,11 @@ TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { Context(&getGlobalContext()) {} private: - virtual void deleted() { + void deleted() override { getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))); setValPtr(nullptr); } - virtual void allUsesReplacedWith(Value *new_value) { + void allUsesReplacedWith(Value *new_value) override { ASSERT_TRUE(nullptr != getValPtr()); EXPECT_EQ(1U, getValPtr()->getNumUses()); EXPECT_EQ(nullptr, AURWArgument); @@ -314,7 +320,7 @@ TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { // a CallbackVH to remove the uses before the check for no uses. RecoveringVH RVH; RVH = BitcastV.get(); - std::auto_ptr<BinaryOperator> BitcastUser( + std::unique_ptr<BinaryOperator> BitcastUser( BinaryOperator::CreateAdd(RVH, Constant::getNullValue(Type::getInt32Ty(getGlobalContext())))); EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); @@ -341,12 +347,12 @@ TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) { setValPtr(V); ToClear[1].reset(new WeakVH(V)); } - virtual void deleted() { + void deleted() override { ToClear[0].reset(); ToClear[1].reset(); CallbackVH::deleted(); } - virtual void allUsesReplacedWith(Value *) { + void allUsesReplacedWith(Value *) override { ToClear[0].reset(); ToClear[1].reset(); } @@ -388,7 +394,7 @@ TEST_F(ValueHandle, AssertingVHCheckedLast) { ToClear[1] = &A1; } - virtual void deleted() { + void deleted() override { *ToClear[0] = nullptr; *ToClear[1] = nullptr; CallbackVH::deleted(); diff --git a/unittests/IR/ValueMapTest.cpp b/unittests/IR/ValueMapTest.cpp index a6bad71cf630f..1431a8d87de4a 100644 --- a/unittests/IR/ValueMapTest.cpp +++ b/unittests/IR/ValueMapTest.cpp @@ -194,7 +194,8 @@ struct LockMutex : ValueMapConfig<KeyT, MutexT> { } static MutexT *getMutex(const ExtraData &Data) { return Data.M; } }; -#if LLVM_ENABLE_THREADS +// FIXME: These tests started failing on Windows. +#if LLVM_ENABLE_THREADS && !defined(LLVM_ON_WIN32) TYPED_TEST(ValueMapTest, LocksMutex) { sys::Mutex M(false); // Not recursive. bool CalledRAUW = false, CalledDeleted = false; diff --git a/unittests/LineEditor/LineEditor.cpp b/unittests/LineEditor/LineEditor.cpp index 26053c0ede241..4d9081fd5c201 100644 --- a/unittests/LineEditor/LineEditor.cpp +++ b/unittests/LineEditor/LineEditor.cpp @@ -29,7 +29,7 @@ public: LE = new LineEditor("test", HistPath); } - ~LineEditorTest() { + ~LineEditorTest() override { delete LE; sys::fs::remove(HistPath.str()); } diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp index 91f97d76c9edb..b4689cba560e8 100644 --- a/unittests/Linker/LinkModulesTest.cpp +++ b/unittests/Linker/LinkModulesTest.cpp @@ -23,7 +23,7 @@ namespace { class LinkModuleTest : public testing::Test { protected: - virtual void SetUp() { + void SetUp() override { M.reset(new Module("MyModule", Ctx)); FunctionType *FTy = FunctionType::get( Type::getInt8PtrTy(Ctx), Type::getInt32Ty(Ctx), false /*=isVarArg*/); @@ -35,7 +35,7 @@ protected: SwitchCase2BB = BasicBlock::Create(Ctx, "switch.case.2", F); ExitBB = BasicBlock::Create(Ctx, "exit", F); - ArrayType *AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3); + AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3); GV = new GlobalVariable(*M.get(), AT, false /*=isConstant*/, GlobalValue::InternalLinkage, nullptr,"switch.bas"); @@ -56,11 +56,12 @@ protected: GV->setInitializer(ConstantArray::get(AT, Init)); } - virtual void TearDown() { M.reset(); } + void TearDown() override { M.reset(); } LLVMContext Ctx; std::unique_ptr<Module> M; Function *F; + ArrayType *AT; GlobalVariable *GV; BasicBlock *EntryBB; BasicBlock *SwitchCase1BB; @@ -75,7 +76,7 @@ TEST_F(LinkModuleTest, BlockAddress) { GEPIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0)); GEPIndices.push_back(F->arg_begin()); - Value *GEP = Builder.CreateGEP(GV, GEPIndices, "switch.gep"); + Value *GEP = Builder.CreateGEP(AT, GV, GEPIndices, "switch.gep"); Value *Load = Builder.CreateLoad(GEP, "switch.load"); Builder.CreateRet(Load); diff --git a/unittests/Makefile b/unittests/Makefile index 603e7d58f8c70..bf2ed22efea78 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -9,8 +9,9 @@ LEVEL = .. -PARALLEL_DIRS = ADT Analysis Bitcode CodeGen DebugInfo ExecutionEngine IR \ - LineEditor Linker MC Option Support Transforms +PARALLEL_DIRS = ADT Analysis AsmParser Bitcode CodeGen DebugInfo \ + ExecutionEngine IR LineEditor Linker MC Option ProfileData \ + Support Transforms include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Option/OptionParsingTest.cpp b/unittests/Option/OptionParsingTest.cpp index aa32da3a595fd..521009a9e663f 100644 --- a/unittests/Option/OptionParsingTest.cpp +++ b/unittests/Option/OptionParsingTest.cpp @@ -209,3 +209,17 @@ TEST(Option, Slurp) { EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[1], "--"); EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[2], "foo"); } + +TEST(Option, FlagAliasToJoined) { + TestOptTable T; + unsigned MAI, MAC; + + // Check that a flag alias provides an empty argument to a joined option. + const char *MyArgs[] = { "-K" }; + std::unique_ptr<InputArgList> AL( + T.ParseArgs(std::begin(MyArgs), std::end(MyArgs), MAI, MAC)); + EXPECT_EQ(AL->size(), 1U); + EXPECT_TRUE(AL->hasArg(OPT_B)); + EXPECT_EQ(AL->getAllArgValues(OPT_B).size(), 1U); + EXPECT_EQ(AL->getAllArgValues(OPT_B)[0], ""); +} diff --git a/unittests/Option/Opts.td b/unittests/Option/Opts.td index aaed6b2101e00..c96774a68e0b0 100644 --- a/unittests/Option/Opts.td +++ b/unittests/Option/Opts.td @@ -23,4 +23,6 @@ def I : Flag<["-"], "I">, Alias<H>, Group<my_group>; def J : Flag<["-"], "J">, Alias<B>, AliasArgs<["foo"]>; def Joo : Flag<["-"], "Joo">, Alias<B>, AliasArgs<["bar"]>; +def K : Flag<["-"], "K">, Alias<B>; + def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>; diff --git a/unittests/ProfileData/CMakeLists.txt b/unittests/ProfileData/CMakeLists.txt new file mode 100644 index 0000000000000..79137c9510aee --- /dev/null +++ b/unittests/ProfileData/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LLVM_LINK_COMPONENTS + Core + ProfileData + Support + ) + +add_llvm_unittest(ProfileDataTests + CoverageMappingTest.cpp + InstrProfTest.cpp + ) diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp new file mode 100644 index 0000000000000..a0995fbbc0287 --- /dev/null +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -0,0 +1,291 @@ +//===- unittest/ProfileData/CoverageMappingTest.cpp -------------------------=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ProfileData/CoverageMappingReader.h" +#include "llvm/ProfileData/CoverageMappingWriter.h" +#include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ProfileData/InstrProfWriter.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +#include <sstream> + +using namespace llvm; +using namespace coverage; + +static ::testing::AssertionResult NoError(std::error_code EC) { + if (!EC) + return ::testing::AssertionSuccess(); + return ::testing::AssertionFailure() << "error " << EC.value() + << ": " << EC.message(); +} + +namespace llvm { +namespace coverage { +void PrintTo(const Counter &C, ::std::ostream *os) { + if (C.isZero()) + *os << "Zero"; + else if (C.isExpression()) + *os << "Expression " << C.getExpressionID(); + else + *os << "Counter " << C.getCounterID(); +} + +void PrintTo(const CoverageSegment &S, ::std::ostream *os) { + *os << "CoverageSegment(" << S.Line << ", " << S.Col << ", "; + if (S.HasCount) + *os << S.Count << ", "; + *os << (S.IsRegionEntry ? "true" : "false") << ")"; +} +} +} + +namespace { + +struct OneFunctionCoverageReader : CoverageMappingReader { + StringRef Name; + uint64_t Hash; + std::vector<StringRef> Filenames; + ArrayRef<CounterMappingRegion> Regions; + bool Done; + + OneFunctionCoverageReader(StringRef Name, uint64_t Hash, + ArrayRef<StringRef> Filenames, + ArrayRef<CounterMappingRegion> Regions) + : Name(Name), Hash(Hash), Filenames(Filenames), Regions(Regions), + Done(false) {} + + std::error_code readNextRecord(CoverageMappingRecord &Record) override { + if (Done) + return instrprof_error::eof; + Done = true; + + Record.FunctionName = Name; + Record.FunctionHash = Hash; + Record.Filenames = Filenames; + Record.Expressions = {}; + Record.MappingRegions = Regions; + return instrprof_error::success; + } +}; + +struct CoverageMappingTest : ::testing::Test { + StringMap<unsigned> Files; + unsigned NextFile; + std::vector<CounterMappingRegion> InputCMRs; + + std::vector<StringRef> OutputFiles; + std::vector<CounterExpression> OutputExpressions; + std::vector<CounterMappingRegion> OutputCMRs; + + InstrProfWriter ProfileWriter; + std::unique_ptr<IndexedInstrProfReader> ProfileReader; + + std::unique_ptr<CoverageMapping> LoadedCoverage; + + void SetUp() override { + NextFile = 0; + } + + unsigned getFile(StringRef Name) { + auto R = Files.find(Name); + if (R != Files.end()) + return R->second; + Files[Name] = NextFile; + return NextFile++; + } + + void addCMR(Counter C, StringRef File, unsigned LS, unsigned CS, unsigned LE, + unsigned CE) { + InputCMRs.push_back( + CounterMappingRegion::makeRegion(C, getFile(File), LS, CS, LE, CE)); + } + + void addExpansionCMR(StringRef File, StringRef ExpandedFile, unsigned LS, + unsigned CS, unsigned LE, unsigned CE) { + InputCMRs.push_back(CounterMappingRegion::makeExpansion( + getFile(File), getFile(ExpandedFile), LS, CS, LE, CE)); + } + + std::string writeCoverageRegions() { + SmallVector<unsigned, 8> FileIDs; + for (const auto &E : Files) + FileIDs.push_back(E.getValue()); + std::string Coverage; + llvm::raw_string_ostream OS(Coverage); + CoverageMappingWriter(FileIDs, None, InputCMRs).write(OS); + return OS.str(); + } + + void readCoverageRegions(std::string Coverage) { + SmallVector<StringRef, 8> Filenames; + for (const auto &E : Files) + Filenames.push_back(E.getKey()); + RawCoverageMappingReader Reader(Coverage, Filenames, OutputFiles, + OutputExpressions, OutputCMRs); + ASSERT_TRUE(NoError(Reader.read())); + } + + void readProfCounts() { + auto Profile = ProfileWriter.writeBuffer(); + auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); + ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ProfileReader = std::move(ReaderOrErr.get()); + } + + void loadCoverageMapping(StringRef FuncName, uint64_t Hash) { + std::string Regions = writeCoverageRegions(); + readCoverageRegions(Regions); + + SmallVector<StringRef, 8> Filenames; + for (const auto &E : Files) + Filenames.push_back(E.getKey()); + OneFunctionCoverageReader CovReader(FuncName, Hash, Filenames, OutputCMRs); + auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader); + ASSERT_TRUE(NoError(CoverageOrErr.getError())); + LoadedCoverage = std::move(CoverageOrErr.get()); + } +}; + +TEST_F(CoverageMappingTest, basic_write_read) { + addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1); + addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2); + addCMR(Counter::getZero(), "foo", 3, 1, 3, 4); + addCMR(Counter::getCounter(2), "foo", 4, 1, 4, 8); + addCMR(Counter::getCounter(3), "bar", 1, 2, 3, 4); + std::string Coverage = writeCoverageRegions(); + readCoverageRegions(Coverage); + + size_t N = makeArrayRef(InputCMRs).size(); + ASSERT_EQ(N, OutputCMRs.size()); + for (size_t I = 0; I < N; ++I) { + ASSERT_EQ(InputCMRs[I].Count, OutputCMRs[I].Count); + ASSERT_EQ(InputCMRs[I].FileID, OutputCMRs[I].FileID); + ASSERT_EQ(InputCMRs[I].startLoc(), OutputCMRs[I].startLoc()); + ASSERT_EQ(InputCMRs[I].endLoc(), OutputCMRs[I].endLoc()); + ASSERT_EQ(InputCMRs[I].Kind, OutputCMRs[I].Kind); + } +} + +TEST_F(CoverageMappingTest, expansion_gets_first_counter) { + addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2); + // This starts earlier in "foo", so the expansion should get its counter. + addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1); + addExpansionCMR("bar", "foo", 3, 3, 3, 3); + std::string Coverage = writeCoverageRegions(); + readCoverageRegions(Coverage); + + ASSERT_EQ(CounterMappingRegion::ExpansionRegion, OutputCMRs[2].Kind); + ASSERT_EQ(Counter::getCounter(2), OutputCMRs[2].Count); + ASSERT_EQ(3U, OutputCMRs[2].LineStart); +} + +TEST_F(CoverageMappingTest, basic_coverage_iteration) { + ProfileWriter.addFunctionCounts("func", 0x1234, {30, 20, 10, 0}); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); + addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1); + addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); + ASSERT_EQ(7U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 20, true), Segments[0]); + ASSERT_EQ(CoverageSegment(4, 7, 30, false), Segments[1]); + ASSERT_EQ(CoverageSegment(5, 8, 10, true), Segments[2]); + ASSERT_EQ(CoverageSegment(9, 1, 30, false), Segments[3]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[4]); + ASSERT_EQ(CoverageSegment(10, 10, 0, true), Segments[5]); + ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]); +} + +TEST_F(CoverageMappingTest, uncovered_function) { + readProfCounts(); + + addCMR(Counter::getZero(), "file1", 1, 2, 3, 4); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); + ASSERT_EQ(2U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 2, 0, true), Segments[0]); + ASSERT_EQ(CoverageSegment(3, 4, false), Segments[1]); +} + +TEST_F(CoverageMappingTest, uncovered_function_with_mapping) { + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); + ASSERT_EQ(3U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 0, true), Segments[0]); + ASSERT_EQ(CoverageSegment(4, 7, 0, false), Segments[1]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[2]); +} + +TEST_F(CoverageMappingTest, combine_regions) { + ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20, 30}); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); + addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); + ASSERT_EQ(4U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); + ASSERT_EQ(CoverageSegment(3, 3, 50, true), Segments[1]); + ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); +} + +TEST_F(CoverageMappingTest, dont_combine_expansions) { + ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20}); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); + addCMR(Counter::getCounter(1), "include1", 6, 6, 7, 7); + addExpansionCMR("file1", "include1", 3, 3, 4, 4); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); + ASSERT_EQ(4U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); + ASSERT_EQ(CoverageSegment(3, 3, 20, true), Segments[1]); + ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); +} + +TEST_F(CoverageMappingTest, strip_filename_prefix) { + ProfileWriter.addFunctionCounts("file1:func", 0x1234, {10}); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + loadCoverageMapping("file1:func", 0x1234); + + std::vector<std::string> Names; + for (const auto &Func : LoadedCoverage->getCoveredFunctions()) + Names.push_back(Func.Name); + ASSERT_EQ(1U, Names.size()); + ASSERT_EQ("func", Names[0]); +} + +} // end anonymous namespace diff --git a/unittests/ProfileData/InstrProfTest.cpp b/unittests/ProfileData/InstrProfTest.cpp new file mode 100644 index 0000000000000..26ea0e44ca42e --- /dev/null +++ b/unittests/ProfileData/InstrProfTest.cpp @@ -0,0 +1,98 @@ +//===- unittest/ProfileData/InstrProfTest.cpp -------------------------------=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ProfileData/InstrProfWriter.h" +#include "gtest/gtest.h" + +#include <cstdarg> + +using namespace llvm; + +static ::testing::AssertionResult NoError(std::error_code EC) { + if (!EC) + return ::testing::AssertionSuccess(); + return ::testing::AssertionFailure() << "error " << EC.value() + << ": " << EC.message(); +} + +static ::testing::AssertionResult ErrorEquals(std::error_code Expected, + std::error_code Found) { + if (Expected == Found) + return ::testing::AssertionSuccess(); + return ::testing::AssertionFailure() << "error " << Found.value() + << ": " << Found.message(); +} + +namespace { + +struct InstrProfTest : ::testing::Test { + InstrProfWriter Writer; + std::unique_ptr<IndexedInstrProfReader> Reader; + + void readProfile(std::unique_ptr<MemoryBuffer> Profile) { + auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); + ASSERT_TRUE(NoError(ReaderOrErr.getError())); + Reader = std::move(ReaderOrErr.get()); + } +}; + +TEST_F(InstrProfTest, write_and_read_empty_profile) { + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + ASSERT_TRUE(Reader->begin() == Reader->end()); +} + +TEST_F(InstrProfTest, write_and_read_one_function) { + Writer.addFunctionCounts("foo", 0x1234, {1, 2, 3, 4}); + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + + auto I = Reader->begin(), E = Reader->end(); + ASSERT_TRUE(I != E); + ASSERT_EQ(StringRef("foo"), I->Name); + ASSERT_EQ(0x1234U, I->Hash); + ASSERT_EQ(4U, I->Counts.size()); + ASSERT_EQ(1U, I->Counts[0]); + ASSERT_EQ(2U, I->Counts[1]); + ASSERT_EQ(3U, I->Counts[2]); + ASSERT_EQ(4U, I->Counts[3]); + ASSERT_TRUE(++I == E); +} + +TEST_F(InstrProfTest, get_function_counts) { + Writer.addFunctionCounts("foo", 0x1234, {1, 2}); + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + + std::vector<uint64_t> Counts; + ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1234, Counts))); + ASSERT_EQ(2U, Counts.size()); + ASSERT_EQ(1U, Counts[0]); + ASSERT_EQ(2U, Counts[1]); + + std::error_code EC; + EC = Reader->getFunctionCounts("foo", 0x5678, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, EC)); + + EC = Reader->getFunctionCounts("bar", 0x1234, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC)); +} + +TEST_F(InstrProfTest, get_max_function_count) { + Writer.addFunctionCounts("foo", 0x1234, {1ULL << 31, 2}); + Writer.addFunctionCounts("bar", 0, {1ULL << 63}); + Writer.addFunctionCounts("baz", 0x5678, {0, 0, 0, 0}); + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + + ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount()); +} + +} // end anonymous namespace diff --git a/unittests/ProfileData/Makefile b/unittests/ProfileData/Makefile new file mode 100644 index 0000000000000..d017c15c00adc --- /dev/null +++ b/unittests/ProfileData/Makefile @@ -0,0 +1,15 @@ +##===- unittests/ProfileData/Makefile ----------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = ProfileData +LINK_COMPONENTS := ProfileData Core Support + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Support/AlignOfTest.cpp b/unittests/Support/AlignOfTest.cpp index 40f729585728c..e0859fc747f4c 100644 --- a/unittests/Support/AlignOfTest.cpp +++ b/unittests/Support/AlignOfTest.cpp @@ -7,6 +7,12 @@ // //===----------------------------------------------------------------------===// +#ifdef _MSC_VER +// Disable warnings about alignment-based structure padding. +// This must be above the includes to suppress warnings in included templates. +#pragma warning(disable:4324) +#endif + #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" #include "gtest/gtest.h" @@ -22,35 +28,21 @@ namespace { // Suppress direct base '{anonymous}::S1' inaccessible in '{anonymous}::D9' // due to ambiguity warning. -// +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Winaccessible-base" +#elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 // Pragma based warning suppression was introduced in GGC 4.2. Additionally // this warning is "enabled by default". The warning still appears if -Wall is // suppressed. Apparently GCC suppresses it when -w is specifed, which is odd. -// At any rate, clang on the other hand gripes about -Wunknown-pragma, so -// leaving it out of this. -#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 && !defined(__clang__) #pragma GCC diagnostic warning "-w" #endif // Define some fixed alignment types to use in these tests. -#if __has_feature(cxx_alignas) -struct alignas(1) A1 { }; -struct alignas(2) A2 { }; -struct alignas(4) A4 { }; -struct alignas(8) A8 { }; -#elif defined(__GNUC__) -struct A1 { } __attribute__((aligned(1))); -struct A2 { } __attribute__((aligned(2))); -struct A4 { } __attribute__((aligned(4))); -struct A8 { } __attribute__((aligned(8))); -#elif defined(_MSC_VER) -__declspec(align(1)) struct A1 { }; -__declspec(align(2)) struct A2 { }; -__declspec(align(4)) struct A4 { }; -__declspec(align(8)) struct A8 { }; -#else -# error No supported align as directive. -#endif +struct LLVM_ALIGNAS(1) A1 {}; +struct LLVM_ALIGNAS(2) A2 {}; +struct LLVM_ALIGNAS(4) A4 {}; +struct LLVM_ALIGNAS(8) A8 {}; struct S1 {}; struct S2 { char a; }; @@ -69,12 +61,22 @@ struct D8 : S1, D4, D5 { double x[2]; }; struct D9 : S1, D1 { S1 s1; }; struct V1 { virtual ~V1(); }; struct V2 { int x; virtual ~V2(); }; -struct V3 : V1 { virtual ~V3(); }; -struct V4 : virtual V2 { int y; virtual ~V4(); }; -struct V5 : V4, V3 { double z; virtual ~V5(); }; +struct V3 : V1 { + ~V3() override; +}; +struct V4 : virtual V2 { int y; + ~V4() override; +}; +struct V5 : V4, V3 { double z; + ~V5() override; +}; struct V6 : S1 { virtual ~V6(); }; -struct V7 : virtual V2, virtual V6 { virtual ~V7(); }; -struct V8 : V5, virtual V6, V7 { double zz; virtual ~V8(); }; +struct V7 : virtual V2, virtual V6 { + ~V7() override; +}; +struct V8 : V5, virtual V6, V7 { double zz; + ~V8() override; +}; double S6::f() { return 0.0; } float D2::g() { return 0.0f; } diff --git a/unittests/Support/AllocatorTest.cpp b/unittests/Support/AllocatorTest.cpp index 7f15776d6f007..38c7fcba8afd4 100644 --- a/unittests/Support/AllocatorTest.cpp +++ b/unittests/Support/AllocatorTest.cpp @@ -61,6 +61,13 @@ TEST(AllocatorTest, ThreeSlabs) { // again. TEST(AllocatorTest, TestReset) { BumpPtrAllocator Alloc; + + // Allocate something larger than the SizeThreshold=4096. + (void)Alloc.Allocate(5000, 1); + Alloc.Reset(); + // Calling Reset should free all CustomSizedSlabs. + EXPECT_EQ(0u, Alloc.GetNumSlabs()); + Alloc.Allocate(3000, 1); EXPECT_EQ(1U, Alloc.GetNumSlabs()); Alloc.Allocate(3000, 1); diff --git a/unittests/Support/BlockFrequencyTest.cpp b/unittests/Support/BlockFrequencyTest.cpp index f6e3537de91a9..0eac8bb8811bc 100644 --- a/unittests/Support/BlockFrequencyTest.cpp +++ b/unittests/Support/BlockFrequencyTest.cpp @@ -1,3 +1,12 @@ +//===- unittests/Support/BlockFrequencyTest.cpp - BlockFrequency tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Support/DataTypes.h" diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index dd270ccea42de..564d189d49c2b 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Support ) @@ -13,6 +14,8 @@ add_llvm_unittest(SupportTests CompressionTest.cpp ConvertUTFTest.cpp DataExtractorTest.cpp + DwarfTest.cpp + EndianStreamTest.cpp EndianTest.cpp ErrorOrTest.cpp FileOutputBufferTest.cpp @@ -35,6 +38,7 @@ add_llvm_unittest(SupportTests StreamingMemoryObject.cpp StringPool.cpp SwapByteOrderTest.cpp + TargetRegistry.cpp ThreadLocalTest.cpp TimeValueTest.cpp UnicodeTest.cpp @@ -42,6 +46,7 @@ add_llvm_unittest(SupportTests YAMLParserTest.cpp formatted_raw_ostream_test.cpp raw_ostream_test.cpp + raw_pwrite_stream_test.cpp ) # ManagedStatic.cpp uses <pthread>. diff --git a/unittests/Support/Casting.cpp b/unittests/Support/Casting.cpp index 3218189eeab6c..e6c35fc21eb7d 100644 --- a/unittests/Support/Casting.cpp +++ b/unittests/Support/Casting.cpp @@ -250,7 +250,7 @@ class PTy { Base *B; public: PTy(Base *B) : B(B) {} - LLVM_EXPLICIT operator bool() const { return get(); } + explicit operator bool() const { return get(); } Base *get() const { return B; } }; diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index ac8d3d8c9d633..328c4b7fcf300 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -35,6 +35,8 @@ class TempEnvVar { #if HAVE_SETENV // Assume setenv and unsetenv come together. unsetenv(name); +#else + (void)name; // Suppress -Wunused-private-field. #endif } @@ -63,21 +65,19 @@ public: StackOption(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) : Base(M0, M1, M2, M3) {} - ~StackOption() { - this->removeArgument(); - } + ~StackOption() override { this->removeArgument(); } }; cl::OptionCategory TestCategory("Test Options", "Description"); -cl::opt<int> TestOption("test-option", cl::desc("old description")); TEST(CommandLineTest, ModifyExisitingOption) { + StackOption<int> TestOption("test-option", cl::desc("old description")); + const char Description[] = "New description"; const char ArgString[] = "new-test-option"; const char ValueString[] = "Integer"; - StringMap<cl::Option*> Map; - cl::getRegisteredOptions(Map); + StringMap<cl::Option *> &Map = cl::getRegisteredOptions(); ASSERT_TRUE(Map.count("test-option") == 1) << "Could not find option in map."; @@ -230,5 +230,44 @@ TEST(CommandLineTest, AliasRequired) { testAliasRequired(array_lengthof(opts2), opts2); } +TEST(CommandLineTest, HideUnrelatedOptions) { + StackOption<int> TestOption1("hide-option-1"); + StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory)); + + cl::HideUnrelatedOptions(TestCategory); + + ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) + << "Failed to hide extra option."; + ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) + << "Hid extra option that should be visable."; + + StringMap<cl::Option *> &Map = cl::getRegisteredOptions(); + ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) + << "Hid default option that should be visable."; +} + +cl::OptionCategory TestCategory2("Test Options set 2", "Description"); + +TEST(CommandLineTest, HideUnrelatedOptionsMulti) { + StackOption<int> TestOption1("multi-hide-option-1"); + StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory)); + StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2)); + + const cl::OptionCategory *VisibleCategories[] = {&TestCategory, + &TestCategory2}; + + cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories)); + + ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) + << "Failed to hide extra option."; + ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) + << "Hid extra option that should be visable."; + ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag()) + << "Hid extra option that should be visable."; + + StringMap<cl::Option *> &Map = cl::getRegisteredOptions(); + ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) + << "Hid default option that should be visable."; +} } // anonymous namespace diff --git a/unittests/Support/ConvertUTFTest.cpp b/unittests/Support/ConvertUTFTest.cpp index 49748db4ae971..d436fc0228963 100644 --- a/unittests/Support/ConvertUTFTest.cpp +++ b/unittests/Support/ConvertUTFTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Format.h" #include "gtest/gtest.h" #include <string> #include <utility> @@ -37,6 +38,19 @@ TEST(ConvertUTFTest, ConvertUTF16BigEndianToUTF8String) { EXPECT_EQ(Expected, Result); } +TEST(ConvertUTFTest, ConvertUTF8ToUTF16String) { + // Src is the look of disapproval. + static const char Src[] = "\xe0\xb2\xa0_\xe0\xb2\xa0"; + StringRef Ref(Src, sizeof(Src) - 1); + SmallVector<UTF16, 5> Result; + bool Success = convertUTF8ToUTF16String(Ref, Result); + EXPECT_TRUE(Success); + static const UTF16 Expected[] = {0x0CA0, 0x005f, 0x0CA0, 0}; + ASSERT_EQ(3u, Result.size()); + for (int I = 0, E = 3; I != E; ++I) + EXPECT_EQ(Expected[I], Result[I]); +} + TEST(ConvertUTFTest, OddLengthInput) { std::string Result; bool Success = convertUTF16ToUTF8String(makeArrayRef("xxxxx", 5), Result); diff --git a/unittests/Support/DwarfTest.cpp b/unittests/Support/DwarfTest.cpp new file mode 100644 index 0000000000000..74fcc989b45a2 --- /dev/null +++ b/unittests/Support/DwarfTest.cpp @@ -0,0 +1,141 @@ +//===- unittest/Support/DwarfTest.cpp - Dwarf support tests ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Dwarf.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::dwarf; + +namespace { + +TEST(DwarfTest, TagStringOnInvalid) { + // This is invalid, so it shouldn't be stringified. + EXPECT_EQ(nullptr, TagString(DW_TAG_invalid)); + + // These aren't really tags: they describe ranges within tags. They + // shouldn't be stringified either. + EXPECT_EQ(nullptr, TagString(DW_TAG_lo_user)); + EXPECT_EQ(nullptr, TagString(DW_TAG_hi_user)); + EXPECT_EQ(nullptr, TagString(DW_TAG_user_base)); +} + +TEST(DwarfTest, getTag) { + // A couple of valid tags. + EXPECT_EQ(DW_TAG_array_type, getTag("DW_TAG_array_type")); + EXPECT_EQ(DW_TAG_module, getTag("DW_TAG_module")); + + // Invalid tags. + EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_invalid")); + EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_madeuptag")); + EXPECT_EQ(DW_TAG_invalid, getTag("something else")); + + // Tag range markers should not be recognized. + EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_lo_user")); + EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_hi_user")); + EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_user_base")); +} + +TEST(DwarfTest, getOperationEncoding) { + // Some valid ops. + EXPECT_EQ(DW_OP_deref, getOperationEncoding("DW_OP_deref")); + EXPECT_EQ(DW_OP_bit_piece, getOperationEncoding("DW_OP_bit_piece")); + + // Invalid ops. + EXPECT_EQ(0u, getOperationEncoding("DW_OP_otherthings")); + EXPECT_EQ(0u, getOperationEncoding("other")); + + // Markers shouldn't be recognized. + EXPECT_EQ(0u, getOperationEncoding("DW_OP_lo_user")); + EXPECT_EQ(0u, getOperationEncoding("DW_OP_hi_user")); +} + +TEST(DwarfTest, LanguageStringOnInvalid) { + // This is invalid, so it shouldn't be stringified. + EXPECT_EQ(nullptr, LanguageString(0)); + + // These aren't really tags: they describe ranges within tags. They + // shouldn't be stringified either. + EXPECT_EQ(nullptr, LanguageString(DW_LANG_lo_user)); + EXPECT_EQ(nullptr, LanguageString(DW_LANG_hi_user)); +} + +TEST(DwarfTest, getLanguage) { + // A couple of valid languages. + EXPECT_EQ(DW_LANG_C89, getLanguage("DW_LANG_C89")); + EXPECT_EQ(DW_LANG_C_plus_plus_11, getLanguage("DW_LANG_C_plus_plus_11")); + EXPECT_EQ(DW_LANG_OCaml, getLanguage("DW_LANG_OCaml")); + EXPECT_EQ(DW_LANG_Mips_Assembler, getLanguage("DW_LANG_Mips_Assembler")); + + // Invalid languages. + EXPECT_EQ(0u, getLanguage("DW_LANG_invalid")); + EXPECT_EQ(0u, getLanguage("DW_TAG_array_type")); + EXPECT_EQ(0u, getLanguage("something else")); + + // Language range markers should not be recognized. + EXPECT_EQ(0u, getLanguage("DW_LANG_lo_user")); + EXPECT_EQ(0u, getLanguage("DW_LANG_hi_user")); +} + +TEST(DwarfTest, AttributeEncodingStringOnInvalid) { + // This is invalid, so it shouldn't be stringified. + EXPECT_EQ(nullptr, AttributeEncodingString(0)); + + // These aren't really tags: they describe ranges within tags. They + // shouldn't be stringified either. + EXPECT_EQ(nullptr, AttributeEncodingString(DW_ATE_lo_user)); + EXPECT_EQ(nullptr, AttributeEncodingString(DW_ATE_hi_user)); +} + +TEST(DwarfTest, getAttributeEncoding) { + // A couple of valid languages. + EXPECT_EQ(DW_ATE_boolean, getAttributeEncoding("DW_ATE_boolean")); + EXPECT_EQ(DW_ATE_imaginary_float, + getAttributeEncoding("DW_ATE_imaginary_float")); + + // Invalid languages. + EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_invalid")); + EXPECT_EQ(0u, getAttributeEncoding("DW_TAG_array_type")); + EXPECT_EQ(0u, getAttributeEncoding("something else")); + + // AttributeEncoding range markers should not be recognized. + EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_lo_user")); + EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_hi_user")); +} + +TEST(DwarfTest, VirtualityString) { + EXPECT_EQ(StringRef("DW_VIRTUALITY_none"), + VirtualityString(DW_VIRTUALITY_none)); + EXPECT_EQ(StringRef("DW_VIRTUALITY_virtual"), + VirtualityString(DW_VIRTUALITY_virtual)); + EXPECT_EQ(StringRef("DW_VIRTUALITY_pure_virtual"), + VirtualityString(DW_VIRTUALITY_pure_virtual)); + + // DW_VIRTUALITY_max should be pure virtual. + EXPECT_EQ(StringRef("DW_VIRTUALITY_pure_virtual"), + VirtualityString(DW_VIRTUALITY_max)); + + // Invalid numbers shouldn't be stringified. + EXPECT_EQ(nullptr, VirtualityString(DW_VIRTUALITY_max + 1)); + EXPECT_EQ(nullptr, VirtualityString(DW_VIRTUALITY_max + 77)); +} + +TEST(DwarfTest, getVirtuality) { + EXPECT_EQ(DW_VIRTUALITY_none, getVirtuality("DW_VIRTUALITY_none")); + EXPECT_EQ(DW_VIRTUALITY_virtual, getVirtuality("DW_VIRTUALITY_virtual")); + EXPECT_EQ(DW_VIRTUALITY_pure_virtual, + getVirtuality("DW_VIRTUALITY_pure_virtual")); + + // Invalid strings. + EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("DW_VIRTUALITY_invalid")); + EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("DW_VIRTUALITY_max")); + EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("something else")); +} + +} // end namespace diff --git a/unittests/Support/EndianStreamTest.cpp b/unittests/Support/EndianStreamTest.cpp new file mode 100644 index 0000000000000..6a69be55f9266 --- /dev/null +++ b/unittests/Support/EndianStreamTest.cpp @@ -0,0 +1,157 @@ +//===- unittests/Support/EndianStreamTest.cpp - EndianStream.h tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/DataTypes.h" +#include "gtest/gtest.h" +using namespace llvm; +using namespace support; + +namespace { + +TEST(EndianStream, WriteInt32LE) { + SmallString<16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<little> LE(OS); + LE.write(static_cast<int32_t>(-1362446643)); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xCD); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xB6); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xCA); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xAE); +} + +TEST(EndianStream, WriteInt32BE) { + SmallVector<char, 16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<big> BE(OS); + BE.write(static_cast<int32_t>(-1362446643)); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xAE); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xCA); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xB6); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xCD); +} + + +TEST(EndianStream, WriteFloatLE) { + SmallString<16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<little> LE(OS); + LE.write(12345.0f); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x00); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xE4); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0x40); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x46); +} + +TEST(EndianStream, WriteFloatBE) { + SmallVector<char, 16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<big> BE(OS); + BE.write(12345.0f); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x46); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x40); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xE4); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x00); +} + +TEST(EndianStream, WriteInt64LE) { + SmallString<16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<little> LE(OS); + LE.write(static_cast<int64_t>(-136244664332342323)); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xCD); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xAB); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xED); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x1B); + EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x33); + EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xF6); + EXPECT_EQ(static_cast<uint8_t>(data[6]), 0x1B); + EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xFE); +} + +TEST(EndianStream, WriteInt64BE) { + SmallVector<char, 16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<big> BE(OS); + BE.write(static_cast<int64_t>(-136244664332342323)); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xFE); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x1B); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xF6); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x33); + EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x1B); + EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xED); + EXPECT_EQ(static_cast<uint8_t>(data[6]), 0xAB); + EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xCD); +} + +TEST(EndianStream, WriteDoubleLE) { + SmallString<16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<little> LE(OS); + LE.write(-2349214918.58107); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x20); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x98); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xD2); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x98); + EXPECT_EQ(static_cast<uint8_t>(data[4]), 0xC5); + EXPECT_EQ(static_cast<uint8_t>(data[5]), 0x80); + EXPECT_EQ(static_cast<uint8_t>(data[6]), 0xE1); + EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xC1); +} + +TEST(EndianStream, WriteDoubleBE) { + SmallVector<char, 16> data; + + { + raw_svector_ostream OS(data); + endian::Writer<big> BE(OS); + BE.write(-2349214918.58107); + } + + EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xC1); + EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xE1); + EXPECT_EQ(static_cast<uint8_t>(data[2]), 0x80); + EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xC5); + EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x98); + EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xD2); + EXPECT_EQ(static_cast<uint8_t>(data[6]), 0x98); + EXPECT_EQ(static_cast<uint8_t>(data[7]), 0x20); +} + + +} // end anon namespace diff --git a/unittests/Support/ErrorOrTest.cpp b/unittests/Support/ErrorOrTest.cpp index 82bbe090960ac..5e8d442a70394 100644 --- a/unittests/Support/ErrorOrTest.cpp +++ b/unittests/Support/ErrorOrTest.cpp @@ -66,6 +66,11 @@ TEST(ErrorOr, Covariant) { ErrorOr<std::unique_ptr<int>> b4(b3); } +TEST(ErrorOr, Comparison) { + ErrorOr<int> x(std::errc::no_such_file_or_directory); + EXPECT_EQ(x, std::errc::no_such_file_or_directory); +} + // ErrorOr<int*> x(nullptr); // ErrorOr<std::unique_ptr<int>> y = x; // invalid conversion static_assert( diff --git a/unittests/Support/Makefile b/unittests/Support/Makefile index 9c0a7f94d7725..21657f12e3dc1 100644 --- a/unittests/Support/Makefile +++ b/unittests/Support/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TESTNAME = Support -LINK_COMPONENTS := core support +LINK_COMPONENTS := all-targets core support include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Support/MathExtrasTest.cpp b/unittests/Support/MathExtrasTest.cpp index 93a38cb03fd93..5c95b500dd4c8 100644 --- a/unittests/Support/MathExtrasTest.cpp +++ b/unittests/Support/MathExtrasTest.cpp @@ -141,21 +141,18 @@ TEST(MathExtras, ByteSwap_64) { EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL)); } -TEST(MathExtras, CountLeadingOnes_32) { +TEST(MathExtras, countLeadingOnes) { for (int i = 30; i >= 0; --i) { // Start with all ones and unset some bit. - EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i))); + EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i))); } -} - -TEST(MathExtras, CountLeadingOnes_64) { for (int i = 62; i >= 0; --i) { // Start with all ones and unset some bit. - EXPECT_EQ(63u - i, CountLeadingOnes_64(0xFFFFFFFFFFFFFFFFLL ^ (1LL << i))); + EXPECT_EQ(63u - i, countLeadingOnes(0xFFFFFFFFFFFFFFFFULL ^ (1LL << i))); } for (int i = 30; i >= 0; --i) { // Start with all ones and unset some bit. - EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i))); + EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i))); } } diff --git a/unittests/Support/MemoryBufferTest.cpp b/unittests/Support/MemoryBufferTest.cpp index 1cdd6adbf8ba3..ffb809aa207b2 100644 --- a/unittests/Support/MemoryBufferTest.cpp +++ b/unittests/Support/MemoryBufferTest.cpp @@ -26,7 +26,7 @@ protected: : data("this is some data") { } - virtual void SetUp() { } + void SetUp() override {} /// Common testing for different modes of getOpenFileSlice. /// Creates a temporary file with known contents, and uses diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 0d661c8ae6c00..262d27260ce43 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -168,6 +168,26 @@ TEST(Support, RelativePathIterator) { } } +TEST(Support, RelativePathDotIterator) { + SmallString<64> Path(StringRef(".c/.d/../.")); + typedef SmallVector<StringRef, 4> PathComponents; + PathComponents ExpectedPathComponents; + PathComponents ActualPathComponents; + + StringRef(Path).split(ExpectedPathComponents, "/"); + + for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; + ++I) { + ActualPathComponents.push_back(*I); + } + + ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); + + for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { + EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); + } +} + TEST(Support, AbsolutePathIterator) { SmallString<64> Path(StringRef("/c/d/e/foo.txt")); typedef SmallVector<StringRef, 4> PathComponents; @@ -191,6 +211,29 @@ TEST(Support, AbsolutePathIterator) { } } +TEST(Support, AbsolutePathDotIterator) { + SmallString<64> Path(StringRef("/.c/.d/../.")); + typedef SmallVector<StringRef, 4> PathComponents; + PathComponents ExpectedPathComponents; + PathComponents ActualPathComponents; + + StringRef(Path).split(ExpectedPathComponents, "/"); + + // The root path will also be a component when iterating + ExpectedPathComponents[0] = "/"; + + for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; + ++I) { + ActualPathComponents.push_back(*I); + } + + ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); + + for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { + EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); + } +} + #ifdef LLVM_ON_WIN32 TEST(Support, AbsolutePathIteratorWin32) { SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); @@ -265,7 +308,7 @@ protected: /// be placed. It is removed at the end of each test (must be empty). SmallString<128> TestDirectory; - virtual void SetUp() { + void SetUp() override { ASSERT_NO_ERROR( fs::createUniqueDirectory("file-system-test", TestDirectory)); // We don't care about this specific file. @@ -273,9 +316,7 @@ protected: errs().flush(); } - virtual void TearDown() { - ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); - } + void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } }; TEST_F(FileSystemTest, Unique) { @@ -557,6 +598,7 @@ const char macho_dynamically_linked_shared_lib[] = const char macho_dynamic_linker[] = "\xfe\xed\xfa\xce..........\x00\x07"; const char macho_bundle[] = "\xfe\xed\xfa\xce..........\x00\x08"; const char macho_dsym_companion[] = "\xfe\xed\xfa\xce..........\x00\x0a"; +const char macho_kext_bundle[] = "\xfe\xed\xfa\xce..........\x00\x0b"; const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff"; const char macho_dynamically_linked_shared_lib_stub[] = "\xfe\xed\xfa\xce..........\x00\x09"; @@ -587,6 +629,7 @@ TEST_F(FileSystemTest, Magic) { DEFINE(macho_bundle), DEFINE(macho_dynamically_linked_shared_lib_stub), DEFINE(macho_dsym_companion), + DEFINE(macho_kext_bundle), DEFINE(windows_resource) #undef DEFINE }; diff --git a/unittests/Support/ScaledNumberTest.cpp b/unittests/Support/ScaledNumberTest.cpp index d8d6e310ff9fc..2f38b2a40fb8f 100644 --- a/unittests/Support/ScaledNumberTest.cpp +++ b/unittests/Support/ScaledNumberTest.cpp @@ -155,7 +155,7 @@ TEST(ScaledNumberHelpersTest, getQuotient) { EXPECT_EQ(SP32(0xaaaaaaab, -33), getQuotient32(1, 3)); EXPECT_EQ(SP32(0xd5555555, -31), getQuotient32(5, 3)); - // 64-bit division is hard to test, since divide64 doesn't canonicalized its + // 64-bit division is hard to test, since divide64 doesn't canonicalize its // output. However, this is the algorithm the implementation uses: // // - Shift divisor right. @@ -532,4 +532,33 @@ TEST(ScaledNumberHelpersTest, getDifference) { EXPECT_EQ(SP64(0, 0), getDifference64(1, -64, 1, -1)); } +TEST(ScaledNumberHelpersTest, arithmeticOperators) { + EXPECT_EQ(ScaledNumber<uint32_t>(10, 0), + ScaledNumber<uint32_t>(1, 3) + ScaledNumber<uint32_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint32_t>(6, 0), + ScaledNumber<uint32_t>(1, 3) - ScaledNumber<uint32_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint32_t>(2, 3), + ScaledNumber<uint32_t>(1, 3) * ScaledNumber<uint32_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint32_t>(1, 2), + ScaledNumber<uint32_t>(1, 3) / ScaledNumber<uint32_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint32_t>(1, 2), ScaledNumber<uint32_t>(1, 3) >> 1); + EXPECT_EQ(ScaledNumber<uint32_t>(1, 4), ScaledNumber<uint32_t>(1, 3) << 1); + + EXPECT_EQ(ScaledNumber<uint64_t>(10, 0), + ScaledNumber<uint64_t>(1, 3) + ScaledNumber<uint64_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint64_t>(6, 0), + ScaledNumber<uint64_t>(1, 3) - ScaledNumber<uint64_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint64_t>(2, 3), + ScaledNumber<uint64_t>(1, 3) * ScaledNumber<uint64_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint64_t>(1, 2), + ScaledNumber<uint64_t>(1, 3) / ScaledNumber<uint64_t>(1, 1)); + EXPECT_EQ(ScaledNumber<uint64_t>(1, 2), ScaledNumber<uint64_t>(1, 3) >> 1); + EXPECT_EQ(ScaledNumber<uint64_t>(1, 4), ScaledNumber<uint64_t>(1, 3) << 1); +} + +TEST(ScaledNumberHelpersTest, toIntBug) { + ScaledNumber<uint32_t> n(1, 0); + EXPECT_EQ(1u, (n * n).toInt<uint32_t>()); +} + } // end namespace diff --git a/unittests/Support/SpecialCaseListTest.cpp b/unittests/Support/SpecialCaseListTest.cpp index 740dbfef40447..0657f8003e8be 100644 --- a/unittests/Support/SpecialCaseListTest.cpp +++ b/unittests/Support/SpecialCaseListTest.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SpecialCaseList.h" #include "gtest/gtest.h" @@ -30,6 +31,16 @@ protected: assert(Error == ""); return SCL; } + + std::string makeSpecialCaseListFile(StringRef Contents) { + int FD; + SmallString<64> Path; + sys::fs::createTemporaryFile("SpecialCaseListTest", "temp", FD, Path); + raw_fd_ostream OF(FD, true, true); + OF << Contents; + OF.close(); + return Path.str(); + } }; TEST_F(SpecialCaseListTest, Basic) { @@ -86,17 +97,18 @@ TEST_F(SpecialCaseListTest, Substring) { TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) { std::string Error; EXPECT_EQ(nullptr, makeSpecialCaseList("badline", Error)); - EXPECT_EQ("Malformed line 1: 'badline'", Error); + EXPECT_EQ("malformed line 1: 'badline'", Error); EXPECT_EQ(nullptr, makeSpecialCaseList("src:bad[a-", Error)); - EXPECT_EQ("Malformed regex in line 1: 'bad[a-': invalid character range", + EXPECT_EQ("malformed regex in line 1: 'bad[a-': invalid character range", Error); EXPECT_EQ(nullptr, makeSpecialCaseList("src:a.c\n" "fun:fun(a\n", Error)); - EXPECT_EQ("Malformed regex in line 2: 'fun(a': parentheses not balanced", + EXPECT_EQ("malformed regex in line 2: 'fun(a': parentheses not balanced", Error); - EXPECT_EQ(nullptr, SpecialCaseList::create("unexisting", Error)); - EXPECT_EQ(0U, Error.find("Can't open file 'unexisting':")); + std::vector<std::string> Files(1, "unexisting"); + EXPECT_EQ(nullptr, SpecialCaseList::create(Files, Error)); + EXPECT_EQ(0U, Error.find("can't open file 'unexisting':")); } TEST_F(SpecialCaseListTest, EmptySpecialCaseList) { @@ -104,6 +116,20 @@ TEST_F(SpecialCaseListTest, EmptySpecialCaseList) { EXPECT_FALSE(SCL->inSection("foo", "bar")); } +TEST_F(SpecialCaseListTest, MultipleBlacklists) { + std::vector<std::string> Files; + Files.push_back(makeSpecialCaseListFile("src:bar\n" + "src:*foo*\n" + "src:ban=init\n")); + Files.push_back(makeSpecialCaseListFile("src:baz\n" + "src:*fog*\n")); + auto SCL = SpecialCaseList::createOrDie(Files); + EXPECT_TRUE(SCL->inSection("src", "bar")); + EXPECT_TRUE(SCL->inSection("src", "baz")); + EXPECT_FALSE(SCL->inSection("src", "ban")); + EXPECT_TRUE(SCL->inSection("src", "ban", "init")); + EXPECT_TRUE(SCL->inSection("src", "tomfoolery")); + EXPECT_TRUE(SCL->inSection("src", "tomfoglery")); } - +} diff --git a/unittests/Support/StreamingMemoryObject.cpp b/unittests/Support/StreamingMemoryObject.cpp index 20136491ab8bd..c043efbb5e473 100644 --- a/unittests/Support/StreamingMemoryObject.cpp +++ b/unittests/Support/StreamingMemoryObject.cpp @@ -27,3 +27,12 @@ TEST(StreamingMemoryObject, Test) { StreamingMemoryObject O(DS); EXPECT_TRUE(O.isValidAddress(32 * 1024)); } + +TEST(StreamingMemoryObject, TestSetKnownObjectSize) { + auto *DS = new NullDataStreamer(); + StreamingMemoryObject O(DS); + uint8_t Buf[32]; + EXPECT_EQ((uint64_t) 16, O.readBytes(Buf, 16, 0)); + O.setKnownObjectSize(24); + EXPECT_EQ((uint64_t) 8, O.readBytes(Buf, 16, 16)); +} diff --git a/unittests/Support/SwapByteOrderTest.cpp b/unittests/Support/SwapByteOrderTest.cpp index 525cfc1aea82c..4f2537c4d5dee 100644 --- a/unittests/Support/SwapByteOrderTest.cpp +++ b/unittests/Support/SwapByteOrderTest.cpp @@ -125,6 +125,19 @@ TEST(getSwappedBytes, int64_t) { sys::getSwappedBytes(int64_t(0x8877665544332211LL))); } +TEST(getSwappedBytes, float) { + EXPECT_EQ(1.79366203433576585078237386661e-43f, sys::getSwappedBytes(-0.0f)); + // 0x11223344 + EXPECT_EQ(7.1653228759765625e2f, sys::getSwappedBytes(1.2795344e-28f)); +} + +TEST(getSwappedBytes, double) { + EXPECT_EQ(6.32404026676795576546008054871e-322, sys::getSwappedBytes(-0.0)); + // 0x1122334455667788 + EXPECT_EQ(-7.08687663657301358331704585496e-268, + sys::getSwappedBytes(3.84141202447173065923064450234e-226)); +} + TEST(swapByteOrder, uint8_t) { uint8_t value = 0x11; sys::swapByteOrder(value); @@ -173,4 +186,16 @@ TEST(swapByteOrder, int64_t) { EXPECT_EQ(int64_t(0x1122334455667788LL), value); } +TEST(swapByteOrder, float) { + float value = 7.1653228759765625e2f; // 0x44332211 + sys::swapByteOrder(value); + EXPECT_EQ(1.2795344e-28f, value); +} + +TEST(swapByteOrder, double) { + double value = -7.08687663657301358331704585496e-268; // 0x8877665544332211 + sys::swapByteOrder(value); + EXPECT_EQ(3.84141202447173065923064450234e-226, value); +} + } diff --git a/unittests/Support/TargetRegistry.cpp b/unittests/Support/TargetRegistry.cpp new file mode 100644 index 0000000000000..ae89c8b649303 --- /dev/null +++ b/unittests/Support/TargetRegistry.cpp @@ -0,0 +1,42 @@ +//===- unittests/Support/TargetRegistry.cpp - -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(TargetRegistry, TargetHasArchType) { + // Presence of at least one target will be asserted when done with the loop, + // else this would pass by accident if InitializeAllTargetInfos were omitted. + int Count = 0; + + llvm::InitializeAllTargetInfos(); + + for (const Target &T : TargetRegistry::targets()) { + StringRef Name = T.getName(); + // There is really no way (at present) to ask a Target whether it targets + // a specific architecture, because the logic for that is buried in a + // predicate. + // We can't ask the predicate "Are you a function that always returns + // false?" + // So given that the cpp backend truly has no target arch, it is skipped. + if (Name != "cpp") { + Triple::ArchType Arch = Triple::getArchTypeForLLVMName(Name); + EXPECT_NE(Arch, Triple::UnknownArch); + ++Count; + } + } + ASSERT_NE(Count, 0); +} + +} // end namespace diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 074e27f8318dc..7248124992b4d 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -46,6 +46,9 @@ typedef std::vector<FooBar> FooBarSequence; LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar) +struct FooBarContainer { + FooBarSequence fbs; +}; namespace llvm { namespace yaml { @@ -56,6 +59,12 @@ namespace yaml { io.mapRequired("bar", fb.bar); } }; + + template <> struct MappingTraits<FooBarContainer> { + static void mapping(IO &io, FooBarContainer &fb) { + io.mapRequired("fbs", fb.fbs); + } + }; } } @@ -109,6 +118,83 @@ TEST(YAMLIO, TestSequenceMapRead) { EXPECT_EQ(map2.bar, 9); } +// +// Test the reading of a map containing a yaml sequence of mappings +// +TEST(YAMLIO, TestContainerSequenceMapRead) { + { + FooBarContainer cont; + Input yin2("---\nfbs:\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n"); + yin2 >> cont; + + EXPECT_FALSE(yin2.error()); + EXPECT_EQ(cont.fbs.size(), 2UL); + EXPECT_EQ(cont.fbs[0].foo, 3); + EXPECT_EQ(cont.fbs[0].bar, 5); + EXPECT_EQ(cont.fbs[1].foo, 7); + EXPECT_EQ(cont.fbs[1].bar, 9); + } + + { + FooBarContainer cont; + Input yin("---\nfbs:\n...\n"); + yin >> cont; + // Okay: Empty node represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: !!null null\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: ~\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: null\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } +} + +// +// Test the reading of a map containing a malformed yaml sequence +// +TEST(YAMLIO, TestMalformedContainerSequenceMapRead) { + { + FooBarContainer cont; + Input yin("---\nfbs:\n foo: 3\n bar: 5\n...\n", nullptr, + suppressErrorMessages); + yin >> cont; + // Error: fbs is not a sequence. + EXPECT_TRUE(!!yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages); + yin >> cont; + // This should be an error. + EXPECT_TRUE(!!yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } +} // // Test writing then reading back a sequence of mappings @@ -694,6 +780,146 @@ TEST(YAMLIO, TestReadWriteMyCustomType) { //===----------------------------------------------------------------------===// +// Test BlockScalarTraits +//===----------------------------------------------------------------------===// + +struct MultilineStringType { + std::string str; +}; + +struct MultilineStringTypeMap { + MultilineStringType name; + MultilineStringType description; + MultilineStringType ingredients; + MultilineStringType recipes; + MultilineStringType warningLabels; + MultilineStringType documentation; + int price; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<MultilineStringTypeMap> { + static void mapping(IO &io, MultilineStringTypeMap& s) { + io.mapRequired("name", s.name); + io.mapRequired("description", s.description); + io.mapRequired("ingredients", s.ingredients); + io.mapRequired("recipes", s.recipes); + io.mapRequired("warningLabels", s.warningLabels); + io.mapRequired("documentation", s.documentation); + io.mapRequired("price", s.price); + } + }; + + // MultilineStringType is formatted as a yaml block literal scalar. A value of + // "Hello\nWorld" would be represented in yaml as + // | + // Hello + // World + template <> + struct BlockScalarTraits<MultilineStringType> { + static void output(const MultilineStringType &value, void *ctxt, + llvm::raw_ostream &out) { + out << value.str; + } + static StringRef input(StringRef scalar, void *ctxt, + MultilineStringType &value) { + value.str = scalar.str(); + return StringRef(); + } + }; +} +} + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MultilineStringType) + +// +// Test writing then reading back custom values +// +TEST(YAMLIO, TestReadWriteMultilineStringType) { + std::string intermediate; + { + MultilineStringTypeMap map; + map.name.str = "An Item"; + map.description.str = "Hello\nWorld"; + map.ingredients.str = "SubItem 1\nSub Item 2\n\nSub Item 3\n"; + map.recipes.str = "\n\nTest 1\n\n\n"; + map.warningLabels.str = ""; + map.documentation.str = "\n\n"; + map.price = 350; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + } + { + Input yin(intermediate); + MultilineStringTypeMap map2; + yin >> map2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(map2.name.str, "An Item\n"); + EXPECT_EQ(map2.description.str, "Hello\nWorld\n"); + EXPECT_EQ(map2.ingredients.str, "SubItem 1\nSub Item 2\n\nSub Item 3\n"); + EXPECT_EQ(map2.recipes.str, "\n\nTest 1\n"); + EXPECT_TRUE(map2.warningLabels.str.empty()); + EXPECT_TRUE(map2.documentation.str.empty()); + EXPECT_EQ(map2.price, 350); + } +} + +// +// Test writing then reading back custom values +// +TEST(YAMLIO, TestReadWriteBlockScalarDocuments) { + std::string intermediate; + { + std::vector<MultilineStringType> documents; + MultilineStringType doc; + doc.str = "Hello\nWorld"; + documents.push_back(doc); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << documents; + + // Verify that the block scalar header was written out on the same line + // as the document marker. + EXPECT_NE(llvm::StringRef::npos, llvm::StringRef(ostr.str()).find("--- |")); + } + { + Input yin(intermediate); + std::vector<MultilineStringType> documents2; + yin >> documents2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(documents2.size(), size_t(1)); + EXPECT_EQ(documents2[0].str, "Hello\nWorld\n"); + } +} + +TEST(YAMLIO, TestReadWriteBlockScalarValue) { + std::string intermediate; + { + MultilineStringType doc; + doc.str = "Just a block\nscalar doc"; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << doc; + } + { + Input yin(intermediate); + MultilineStringType doc; + yin >> doc; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc.str, "Just a block\nscalar doc\n"); + } +} + +//===----------------------------------------------------------------------===// // Test flow sequences //===----------------------------------------------------------------------===// @@ -743,6 +969,26 @@ namespace yaml { } } +typedef std::vector<MyNumber> MyNumberFlowSequence; + +LLVM_YAML_IS_SEQUENCE_VECTOR(MyNumberFlowSequence) + +struct NameAndNumbersFlow { + llvm::StringRef name; + std::vector<MyNumberFlowSequence> sequenceOfNumbers; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<NameAndNumbersFlow> { + static void mapping(IO &io, NameAndNumbersFlow& nn) { + io.mapRequired("name", nn.name); + io.mapRequired("sequenceOfNumbers", nn.sequenceOfNumbers); + } + }; +} +} // // Test writing then reading back custom values @@ -790,6 +1036,51 @@ TEST(YAMLIO, TestReadWriteMyFlowSequence) { } +// +// Test writing then reading back a sequence of flow sequences. +// +TEST(YAMLIO, TestReadWriteSequenceOfMyFlowSequence) { + std::string intermediate; + { + NameAndNumbersFlow map; + map.name = "hello"; + MyNumberFlowSequence single = { 0 }; + MyNumberFlowSequence numbers = { 12, 1, -512 }; + map.sequenceOfNumbers.push_back(single); + map.sequenceOfNumbers.push_back(numbers); + map.sequenceOfNumbers.push_back(MyNumberFlowSequence()); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + + // Verify sequences were written in flow style + // and that the parent sequence used '-'. + ostr.flush(); + llvm::StringRef flowOut(intermediate); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 0 ]")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 12, 1, -512 ]")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ ]")); + } + + { + Input yin(intermediate); + NameAndNumbersFlow map2; + yin >> map2; + + EXPECT_FALSE(yin.error()); + EXPECT_TRUE(map2.name.equals("hello")); + EXPECT_EQ(map2.sequenceOfNumbers.size(), 3UL); + EXPECT_EQ(map2.sequenceOfNumbers[0].size(), 1UL); + EXPECT_EQ(0, map2.sequenceOfNumbers[0][0]); + EXPECT_EQ(map2.sequenceOfNumbers[1].size(), 3UL); + EXPECT_EQ(12, map2.sequenceOfNumbers[1][0]); + EXPECT_EQ(1, map2.sequenceOfNumbers[1][1]); + EXPECT_EQ(-512, map2.sequenceOfNumbers[1][2]); + EXPECT_TRUE(map2.sequenceOfNumbers[2].empty()); + } +} + //===----------------------------------------------------------------------===// // Test normalizing/denormalizing //===----------------------------------------------------------------------===// @@ -1216,6 +1507,91 @@ TEST(YAMLIO, TestValidatingInput) { EXPECT_TRUE(!!yin.error()); } +//===----------------------------------------------------------------------===// +// Test flow mapping +//===----------------------------------------------------------------------===// + +struct FlowFooBar { + int foo; + int bar; + + FlowFooBar() : foo(0), bar(0) {} + FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {} +}; + +typedef std::vector<FlowFooBar> FlowFooBarSequence; + +LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar) + +struct FlowFooBarDoc { + FlowFooBar attribute; + FlowFooBarSequence seq; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<FlowFooBar> { + static void mapping(IO &io, FlowFooBar &fb) { + io.mapRequired("foo", fb.foo); + io.mapRequired("bar", fb.bar); + } + + static const bool flow = true; + }; + + template <> + struct MappingTraits<FlowFooBarDoc> { + static void mapping(IO &io, FlowFooBarDoc &fb) { + io.mapRequired("attribute", fb.attribute); + io.mapRequired("seq", fb.seq); + } + }; +} +} + +// +// Test writing then reading back custom mappings +// +TEST(YAMLIO, TestReadWriteMyFlowMapping) { + std::string intermediate; + { + FlowFooBarDoc doc; + doc.attribute = FlowFooBar(42, 907); + doc.seq.push_back(FlowFooBar(1, 2)); + doc.seq.push_back(FlowFooBar(0, 0)); + doc.seq.push_back(FlowFooBar(-1, 1024)); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << doc; + + // Verify that mappings were written in flow style + ostr.flush(); + llvm::StringRef flowOut(intermediate); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }")); + } + + { + Input yin(intermediate); + FlowFooBarDoc doc2; + yin >> doc2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc2.attribute.foo, 42); + EXPECT_EQ(doc2.attribute.bar, 907); + EXPECT_EQ(doc2.seq.size(), 3UL); + EXPECT_EQ(doc2.seq[0].foo, 1); + EXPECT_EQ(doc2.seq[0].bar, 2); + EXPECT_EQ(doc2.seq[1].foo, 0); + EXPECT_EQ(doc2.seq[1].bar, 0); + EXPECT_EQ(doc2.seq[2].foo, -1); + EXPECT_EQ(doc2.seq[2].bar, 1024); + } +} //===----------------------------------------------------------------------===// // Test error handling diff --git a/unittests/Support/YAMLParserTest.cpp b/unittests/Support/YAMLParserTest.cpp index 823a0d6e3e03e..69b354a91d11e 100644 --- a/unittests/Support/YAMLParserTest.cpp +++ b/unittests/Support/YAMLParserTest.cpp @@ -130,6 +130,45 @@ TEST(YAMLParser, ParsesArrayOfArrays) { ExpectParseSuccess("Array of arrays", "[[]]"); } +TEST(YAMLParser, ParsesBlockLiteralScalars) { + ExpectParseSuccess("Block literal scalar", "test: |\n Hello\n World\n"); + ExpectParseSuccess("Block literal scalar EOF", "test: |\n Hello\n World"); + ExpectParseSuccess("Empty block literal scalar header EOF", "test: | "); + ExpectParseSuccess("Empty block literal scalar", "test: |\ntest2: 20"); + ExpectParseSuccess("Empty block literal scalar 2", "- | \n \n\n \n- 42"); + ExpectParseSuccess("Block literal scalar in sequence", + "- |\n Testing\n Out\n\n- 22"); + ExpectParseSuccess("Block literal scalar in document", + "--- |\n Document\n..."); + ExpectParseSuccess("Empty non indented lines still count", + "- |\n First line\n \n\n Another line\n\n- 2"); + ExpectParseSuccess("Comment in block literal scalar header", + "test: | # Comment \n No Comment\ntest 2: | # Void"); + ExpectParseSuccess("Chomping indicators in block literal scalar header", + "test: |- \n Hello\n\ntest 2: |+ \n\n World\n\n\n"); + ExpectParseSuccess("Indent indicators in block literal scalar header", + "test: |1 \n \n Hello \n World\n"); + ExpectParseSuccess("Chomping and indent indicators in block literals", + "test: |-1\n Hello\ntest 2: |9+\n World"); + ExpectParseSuccess("Trailing comments in block literals", + "test: |\n Content\n # Trailing\n #Comment\ntest 2: 3"); + ExpectParseError("Invalid block scalar header", "test: | failure"); + ExpectParseError("Invalid line indentation", "test: |\n First line\n Error"); + ExpectParseError("Long leading space line", "test: |\n \n Test\n"); +} + +TEST(YAMLParser, NullTerminatedBlockScalars) { + SourceMgr SM; + yaml::Stream Stream("test: |\n Hello\n World\n", SM); + yaml::Document &Doc = *Stream.begin(); + yaml::MappingNode *Map = cast<yaml::MappingNode>(Doc.getRoot()); + StringRef Value = + cast<yaml::BlockScalarNode>(Map->begin()->getValue())->getValue(); + + EXPECT_EQ(Value, "Hello\nWorld\n"); + EXPECT_EQ(Value.data()[Value.size()], '\0'); +} + TEST(YAMLParser, HandlesEndOfFileGracefully) { ExpectParseError("In string starting with EOF", "[\""); ExpectParseError("In string hitting EOF", "[\" "); @@ -141,6 +180,10 @@ TEST(YAMLParser, HandlesEndOfFileGracefully) { ExpectParseError("In object hitting EOF", "{\"\""); } +TEST(YAMLParser, HandlesNullValuesInKeyValueNodesGracefully) { + ExpectParseError("KeyValueNode with null value", "test: '"); +} + // Checks that the given string can be parsed into an identical string inside // of an array. static void ExpectCanParseString(StringRef String) { diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp index 39cfaf004c72b..ff986025b2ccb 100644 --- a/unittests/Support/raw_ostream_test.cpp +++ b/unittests/Support/raw_ostream_test.cpp @@ -162,6 +162,8 @@ TEST(raw_ostreamTest, FormatHex) { EXPECT_EQ("0x1", printToString(format_hex(1, 3), 3)); EXPECT_EQ("0x12", printToString(format_hex(0x12, 3), 4)); EXPECT_EQ("0x123", printToString(format_hex(0x123, 3), 5)); + EXPECT_EQ("FF", printToString(format_hex_no_prefix(0xFF, 2, true), 4)); + EXPECT_EQ("ABCD", printToString(format_hex_no_prefix(0xABCD, 2, true), 4)); EXPECT_EQ("0xffffffffffffffff", printToString(format_hex(UINT64_MAX, 18), 18)); EXPECT_EQ("0x8000000000000000", diff --git a/unittests/Support/raw_pwrite_stream_test.cpp b/unittests/Support/raw_pwrite_stream_test.cpp new file mode 100644 index 0000000000000..a62f6bacb0703 --- /dev/null +++ b/unittests/Support/raw_pwrite_stream_test.cpp @@ -0,0 +1,64 @@ +//===- raw_pwrite_stream_test.cpp - raw_pwrite_stream tests ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +TEST(raw_pwrite_ostreamTest, TestSVector) { + SmallVector<char, 0> Buffer; + raw_svector_ostream OS(Buffer); + OS << "abcd"; + StringRef Test = "test"; + OS.pwrite(Test.data(), Test.size(), 0); + EXPECT_EQ(Test, OS.str()); + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG + EXPECT_DEATH(OS.pwrite("12345", 5, 0), + "We don't support extending the stream"); +#endif +#endif +} + +TEST(raw_pwrite_ostreamTest, TestFD) { + SmallString<64> Path; + int FD; + sys::fs::createTemporaryFile("foo", "bar", FD, Path); + raw_fd_ostream OS(FD, true); + OS << "abcd"; + StringRef Test = "test"; + OS.pwrite(Test.data(), Test.size(), 0); + OS.pwrite(Test.data(), Test.size(), 0); + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG + EXPECT_DEATH(OS.pwrite("12345", 5, 0), + "We don't support extending the stream"); +#endif +#endif +} + +#ifdef LLVM_ON_UNIX +TEST(raw_pwrite_ostreamTest, TestDevNull) { + int FD; + sys::fs::openFileForWrite("/dev/null", FD, sys::fs::F_None); + raw_fd_ostream OS(FD, true); + OS << "abcd"; + StringRef Test = "test"; + OS.pwrite(Test.data(), Test.size(), 0); + OS.pwrite(Test.data(), Test.size(), 0); +} +#endif +} diff --git a/unittests/Transforms/CMakeLists.txt b/unittests/Transforms/CMakeLists.txt index e3ce185e0d5b4..5d3b29c94d72e 100644 --- a/unittests/Transforms/CMakeLists.txt +++ b/unittests/Transforms/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(IPO) add_subdirectory(Utils) diff --git a/unittests/Transforms/IPO/CMakeLists.txt b/unittests/Transforms/IPO/CMakeLists.txt new file mode 100644 index 0000000000000..58b71b2bce03f --- /dev/null +++ b/unittests/Transforms/IPO/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + Core + Support + IPO + ) + +add_llvm_unittest(IPOTests + LowerBitSets.cpp + ) diff --git a/unittests/Transforms/IPO/LowerBitSets.cpp b/unittests/Transforms/IPO/LowerBitSets.cpp new file mode 100644 index 0000000000000..49a42cd20d7a9 --- /dev/null +++ b/unittests/Transforms/IPO/LowerBitSets.cpp @@ -0,0 +1,155 @@ +//===- LowerBitSets.cpp - Unit tests for bitset lowering ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/LowerBitSets.h" +#include "gtest/gtest.h" + +using namespace llvm; + +TEST(LowerBitSets, BitSetBuilder) { + struct { + std::vector<uint64_t> Offsets; + std::set<uint64_t> Bits; + uint64_t ByteOffset; + uint64_t BitSize; + unsigned AlignLog2; + bool IsSingleOffset; + bool IsAllOnes; + } BSBTests[] = { + {{}, std::set<uint64_t>{}, 0, 1, 0, false, false}, + {{0}, {0}, 0, 1, 0, true, true}, + {{4}, {0}, 4, 1, 0, true, true}, + {{37}, {0}, 37, 1, 0, true, true}, + {{0, 1}, {0, 1}, 0, 2, 0, false, true}, + {{0, 4}, {0, 1}, 0, 2, 2, false, true}, + {{0, uint64_t(1) << 33}, {0, 1}, 0, 2, 33, false, true}, + {{3, 7}, {0, 1}, 3, 2, 2, false, true}, + {{0, 1, 7}, {0, 1, 7}, 0, 8, 0, false, false}, + {{0, 2, 14}, {0, 1, 7}, 0, 8, 1, false, false}, + {{0, 1, 8}, {0, 1, 8}, 0, 9, 0, false, false}, + {{0, 2, 16}, {0, 1, 8}, 0, 9, 1, false, false}, + {{0, 1, 2, 3, 4, 5, 6, 7}, + {0, 1, 2, 3, 4, 5, 6, 7}, + 0, + 8, + 0, + false, + true}, + {{0, 1, 2, 3, 4, 5, 6, 7, 8}, + {0, 1, 2, 3, 4, 5, 6, 7, 8}, + 0, + 9, + 0, + false, + true}, + }; + + for (auto &&T : BSBTests) { + BitSetBuilder BSB; + for (auto Offset : T.Offsets) + BSB.addOffset(Offset); + + BitSetInfo BSI = BSB.build(); + + EXPECT_EQ(T.Bits, BSI.Bits); + EXPECT_EQ(T.ByteOffset, BSI.ByteOffset); + EXPECT_EQ(T.BitSize, BSI.BitSize); + EXPECT_EQ(T.AlignLog2, BSI.AlignLog2); + EXPECT_EQ(T.IsSingleOffset, BSI.isSingleOffset()); + EXPECT_EQ(T.IsAllOnes, BSI.isAllOnes()); + + for (auto Offset : T.Offsets) + EXPECT_TRUE(BSI.containsGlobalOffset(Offset)); + + auto I = T.Offsets.begin(); + for (uint64_t NonOffset = 0; NonOffset != 256; ++NonOffset) { + if (I != T.Offsets.end() && *I == NonOffset) { + ++I; + continue; + } + + EXPECT_FALSE(BSI.containsGlobalOffset(NonOffset)); + } + } +} + +TEST(LowerBitSets, GlobalLayoutBuilder) { + struct { + uint64_t NumObjects; + std::vector<std::set<uint64_t>> Fragments; + std::vector<uint64_t> WantLayout; + } GLBTests[] = { + {0, {}, {}}, + {4, {{0, 1}, {2, 3}}, {0, 1, 2, 3}}, + {3, {{0, 1}, {1, 2}}, {0, 1, 2}}, + {4, {{0, 1}, {1, 2}, {2, 3}}, {0, 1, 2, 3}}, + {4, {{0, 1}, {2, 3}, {1, 2}}, {0, 1, 2, 3}}, + {6, {{2, 5}, {0, 1, 2, 3, 4, 5}}, {0, 1, 2, 5, 3, 4}}, + }; + + for (auto &&T : GLBTests) { + GlobalLayoutBuilder GLB(T.NumObjects); + for (auto &&F : T.Fragments) + GLB.addFragment(F); + + std::vector<uint64_t> ComputedLayout; + for (auto &&F : GLB.Fragments) + ComputedLayout.insert(ComputedLayout.end(), F.begin(), F.end()); + + EXPECT_EQ(T.WantLayout, ComputedLayout); + } +} + +TEST(LowerBitSets, ByteArrayBuilder) { + struct BABAlloc { + std::set<uint64_t> Bits; + uint64_t BitSize; + uint64_t WantByteOffset; + uint8_t WantMask; + }; + + struct { + std::vector<BABAlloc> Allocs; + std::vector<uint8_t> WantBytes; + } BABTests[] = { + {{{{0}, 1, 0, 1}, {{0}, 1, 0, 2}}, {3}}, + {{{{0}, 16, 0, 1}, + {{1}, 15, 0, 2}, + {{2}, 14, 0, 4}, + {{3}, 13, 0, 8}, + {{4}, 12, 0, 0x10}, + {{5}, 11, 0, 0x20}, + {{6}, 10, 0, 0x40}, + {{7}, 9, 0, 0x80}, + {{0}, 7, 9, 0x80}, + {{0}, 6, 10, 0x40}, + {{0}, 5, 11, 0x20}, + {{0}, 4, 12, 0x10}, + {{0}, 3, 13, 8}, + {{0}, 2, 14, 4}, + {{0}, 1, 15, 2}}, + {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0, 0x80, 0x40, 0x20, 0x10, 8, 4, + 2}}, + }; + + for (auto &&T : BABTests) { + ByteArrayBuilder BABuilder; + + for (auto &&A : T.Allocs) { + uint64_t GotByteOffset; + uint8_t GotMask; + + BABuilder.allocate(A.Bits, A.BitSize, GotByteOffset, GotMask); + EXPECT_EQ(A.WantByteOffset, GotByteOffset); + EXPECT_EQ(A.WantMask, GotMask); + } + + EXPECT_EQ(T.WantBytes, BABuilder.Bytes); + } +} diff --git a/unittests/Transforms/IPO/Makefile b/unittests/Transforms/IPO/Makefile new file mode 100644 index 0000000000000..f807879c2b5f6 --- /dev/null +++ b/unittests/Transforms/IPO/Makefile @@ -0,0 +1,15 @@ +##===- unittests/Transforms/IPO/Makefile -------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TESTNAME = IPO +LINK_COMPONENTS := IPO + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Transforms/Makefile b/unittests/Transforms/Makefile index 599b18a057dcf..3a2cdfc2c74a0 100644 --- a/unittests/Transforms/Makefile +++ b/unittests/Transforms/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. -PARALLEL_DIRS = Utils +PARALLEL_DIRS = IPO Utils include $(LEVEL)/Makefile.common diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt index ffa1d49d380bd..517ff99ea46bc 100644 --- a/unittests/Transforms/Utils/CMakeLists.txt +++ b/unittests/Transforms/Utils/CMakeLists.txt @@ -9,4 +9,5 @@ add_llvm_unittest(UtilsTests Cloning.cpp IntegerDivision.cpp Local.cpp + ValueMapperTest.cpp ) diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp index 1d22d5b15c9ba..18d3ca6267535 100644 --- a/unittests/Transforms/Utils/Cloning.cpp +++ b/unittests/Transforms/Utils/Cloning.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "gtest/gtest.h" using namespace llvm; @@ -30,9 +31,7 @@ namespace { class CloneInstruction : public ::testing::Test { protected: - virtual void SetUp() { - V = nullptr; - } + void SetUp() override { V = nullptr; } template <typename T> T *clone(T *V1) { @@ -46,7 +45,7 @@ protected: DeleteContainerPointers(Clones); } - virtual void TearDown() { + void TearDown() override { eraseClones(); DeleteContainerPointers(Orig); delete V; @@ -135,7 +134,8 @@ TEST_F(CloneInstruction, Inbounds) { Constant *Z = Constant::getNullValue(Type::getInt32Ty(context)); std::vector<Value *> ops; ops.push_back(Z); - GetElementPtrInst *GEP = GetElementPtrInst::Create(V, ops); + GetElementPtrInst *GEP = + GetElementPtrInst::Create(Type::getInt32Ty(context), V, ops); EXPECT_FALSE(this->clone(GEP)->isInBounds()); GEP->setIsInBounds(); @@ -204,16 +204,14 @@ TEST_F(CloneInstruction, CallingConvention) { class CloneFunc : public ::testing::Test { protected: - virtual void SetUp() { + void SetUp() override { SetupModule(); CreateOldFunc(); CreateNewFunc(); SetupFinder(); } - virtual void TearDown() { - delete Finder; - } + void TearDown() override { delete Finder; } void SetupModule() { M = new Module("", C); @@ -230,14 +228,16 @@ protected: IRBuilder<> IBuilder(C); // Function DI - DIFile File = DBuilder.createFile("filename.c", "/file/dir/"); - DITypeArray ParamTypes = DBuilder.getOrCreateTypeArray(None); - DICompositeType FuncType = DBuilder.createSubroutineType(File, ParamTypes); - DICompileUnit CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99, - "filename.c", "/file/dir", "CloneFunc", false, "", 0); + auto *File = DBuilder.createFile("filename.c", "/file/dir/"); + DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None); + DISubroutineType *FuncType = + DBuilder.createSubroutineType(File, ParamTypes); + auto *CU = + DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c", + "/file/dir", "CloneFunc", false, "", 0); - DISubprogram Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4, - FuncType, true, true, 3, 0, false, OldFunc); + auto *Subprogram = DBuilder.createFunction( + CU, "f", "f", File, 4, FuncType, true, true, 3, 0, false, OldFunc); // Function body BasicBlock* Entry = BasicBlock::Create(C, "", OldFunc); @@ -252,13 +252,15 @@ protected: Instruction* Terminator = IBuilder.CreateRetVoid(); // Create a local variable around the alloca - DIType IntType = DBuilder.createBasicType("int", 32, 0, - dwarf::DW_ATE_signed); - DIExpression E = DBuilder.createExpression(); - DIVariable Variable = DBuilder.createLocalVariable( - dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, true); - DBuilder.insertDeclare(Alloca, Variable, E, Store); - DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, Terminator); + auto *IntType = + DBuilder.createBasicType("int", 32, 0, dwarf::DW_ATE_signed); + auto *E = DBuilder.createExpression(); + auto *Variable = DBuilder.createLocalVariable( + dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, true); + auto *DL = DILocation::get(Subprogram->getContext(), 5, 0, Subprogram); + DBuilder.insertDeclare(Alloca, Variable, E, DL, Store); + DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL, + Terminator); // Finalize the debug info DBuilder.finalize(); @@ -296,38 +298,41 @@ TEST_F(CloneFunc, NewFunctionCreated) { // Test that a new subprogram entry was added and is pointing to the new // function, while the original subprogram still points to the old one. TEST_F(CloneFunc, Subprogram) { + EXPECT_FALSE(verifyModule(*M)); + unsigned SubprogramCount = Finder->subprogram_count(); EXPECT_EQ(2U, SubprogramCount); auto Iter = Finder->subprograms().begin(); - DISubprogram Sub1(*Iter); - EXPECT_TRUE(Sub1.Verify()); + auto *Sub1 = cast<DISubprogram>(*Iter); Iter++; - DISubprogram Sub2(*Iter); - EXPECT_TRUE(Sub2.Verify()); + auto *Sub2 = cast<DISubprogram>(*Iter); - EXPECT_TRUE((Sub1.getFunction() == OldFunc && Sub2.getFunction() == NewFunc) - || (Sub1.getFunction() == NewFunc && Sub2.getFunction() == OldFunc)); + EXPECT_TRUE( + (Sub1->getFunction() == OldFunc && Sub2->getFunction() == NewFunc) || + (Sub1->getFunction() == NewFunc && Sub2->getFunction() == OldFunc)); } // Test that the new subprogram entry was not added to the CU which doesn't // contain the old subprogram entry. TEST_F(CloneFunc, SubprogramInRightCU) { + EXPECT_FALSE(verifyModule(*M)); + EXPECT_EQ(2U, Finder->compile_unit_count()); auto Iter = Finder->compile_units().begin(); - DICompileUnit CU1(*Iter); - EXPECT_TRUE(CU1.Verify()); + auto *CU1 = cast<DICompileUnit>(*Iter); Iter++; - DICompileUnit CU2(*Iter); - EXPECT_TRUE(CU2.Verify()); - EXPECT_TRUE(CU1.getSubprograms().getNumElements() == 0 - || CU2.getSubprograms().getNumElements() == 0); + auto *CU2 = cast<DICompileUnit>(*Iter); + EXPECT_TRUE(CU1->getSubprograms().size() == 0 || + CU2->getSubprograms().size() == 0); } // Test that instructions in the old function still belong to it in the // metadata, while instruction in the new function belong to the new one. TEST_F(CloneFunc, InstructionOwnership) { + EXPECT_FALSE(verifyModule(*M)); + inst_iterator OldIter = inst_begin(OldFunc); inst_iterator OldEnd = inst_end(OldFunc); inst_iterator NewIter = inst_begin(NewFunc); @@ -345,14 +350,12 @@ TEST_F(CloneFunc, InstructionOwnership) { // Verify that the debug location data is the same EXPECT_EQ(OldDL.getLine(), NewDL.getLine()); EXPECT_EQ(OldDL.getCol(), NewDL.getCol()); - + // But that they belong to different functions - DISubprogram OldSubprogram(OldDL.getScope(C)); - DISubprogram NewSubprogram(NewDL.getScope(C)); - EXPECT_TRUE(OldSubprogram.Verify()); - EXPECT_TRUE(NewSubprogram.Verify()); - EXPECT_EQ(OldFunc, OldSubprogram.getFunction()); - EXPECT_EQ(NewFunc, NewSubprogram.getFunction()); + auto *OldSubprogram = cast<DISubprogram>(OldDL.getScope()); + auto *NewSubprogram = cast<DISubprogram>(NewDL.getScope()); + EXPECT_EQ(OldFunc, OldSubprogram->getFunction()); + EXPECT_EQ(NewFunc, NewSubprogram->getFunction()); } ++OldIter; @@ -365,6 +368,8 @@ TEST_F(CloneFunc, InstructionOwnership) { // Test that the arguments for debug intrinsics in the new function were // properly cloned TEST_F(CloneFunc, DebugIntrinsics) { + EXPECT_FALSE(verifyModule(*M)); + inst_iterator OldIter = inst_begin(OldFunc); inst_iterator OldEnd = inst_end(OldFunc); inst_iterator NewIter = inst_begin(NewFunc); @@ -384,21 +389,25 @@ TEST_F(CloneFunc, DebugIntrinsics) { getParent()->getParent()); // Old variable must belong to the old function - EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable()) - .getContext()).getFunction()); + EXPECT_EQ(OldFunc, + cast<DISubprogram>(OldIntrin->getVariable()->getScope()) + ->getFunction()); // New variable must belong to the New function - EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable()) - .getContext()).getFunction()); + EXPECT_EQ(NewFunc, + cast<DISubprogram>(NewIntrin->getVariable()->getScope()) + ->getFunction()); } else if (DbgValueInst* OldIntrin = dyn_cast<DbgValueInst>(&OldI)) { DbgValueInst* NewIntrin = dyn_cast<DbgValueInst>(&NewI); EXPECT_TRUE(NewIntrin); // Old variable must belong to the old function - EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable()) - .getContext()).getFunction()); + EXPECT_EQ(OldFunc, + cast<DISubprogram>(OldIntrin->getVariable()->getScope()) + ->getFunction()); // New variable must belong to the New function - EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable()) - .getContext()).getFunction()); + EXPECT_EQ(NewFunc, + cast<DISubprogram>(NewIntrin->getVariable()->getScope()) + ->getFunction()); } ++OldIter; diff --git a/unittests/Transforms/Utils/ValueMapperTest.cpp b/unittests/Transforms/Utils/ValueMapperTest.cpp new file mode 100644 index 0000000000000..137a2607c848b --- /dev/null +++ b/unittests/Transforms/Utils/ValueMapperTest.cpp @@ -0,0 +1,27 @@ +//===- ValueMapper.cpp - Unit tests for ValueMapper -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(ValueMapperTest, MapMetadataUnresolved) { + LLVMContext Context; + TempMDTuple T = MDTuple::getTemporary(Context, None); + + ValueToValueMapTy VM; + EXPECT_EQ(T.get(), MapMetadata(T.get(), VM, RF_NoModuleLevelChanges)); +} + +} |
