diff options
Diffstat (limited to 'unittests')
24 files changed, 1138 insertions, 345 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 338f2b8a5a661..69da089f172b4 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -552,7 +552,7 @@ TEST(APFloatTest, MaxNum) { EXPECT_EQ(2.0, maxnum(f1, f2).convertToDouble()); EXPECT_EQ(2.0, maxnum(f2, f1).convertToDouble()); EXPECT_EQ(1.0, maxnum(f1, nan).convertToDouble()); - EXPECT_EQ(1.0, minnum(nan, f1).convertToDouble()); + EXPECT_EQ(1.0, maxnum(nan, f1).convertToDouble()); } TEST(APFloatTest, Denormal) { @@ -745,7 +745,7 @@ TEST(APFloatTest, fromZeroDecimalLargeExponentString) { EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), "000.0000e1234").convertToDouble()); EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), "000.0000e-1234").convertToDouble()); - EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), StringRef("0e1234\02", 6)).convertToDouble()); + EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), StringRef("0e1234" "\0" "2", 6)).convertToDouble()); } TEST(APFloatTest, fromZeroHexadecimalString) { @@ -1059,11 +1059,11 @@ TEST(APFloatTest, StringDecimalDeath) { EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("\0", 1)), "Invalid character in significand"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\0", 2)), "Invalid character in significand"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\02", 3)), "Invalid character in significand"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\02e1", 5)), "Invalid character in significand"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1" "\0" "2", 3)), "Invalid character in significand"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1" "\0" "2e1", 5)), "Invalid character in significand"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e\0", 3)), "Invalid character in exponent"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1\0", 4)), "Invalid character in exponent"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1\02", 5)), "Invalid character in exponent"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1" "\0" "2", 5)), "Invalid character in exponent"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0f"), "Invalid character in significand"); @@ -1149,11 +1149,11 @@ TEST(APFloatTest, StringHexadecimalDeath) { EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x\0", 3)), "Invalid character in significand"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\0", 4)), "Invalid character in significand"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\02", 5)), "Invalid character in significand"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\02p1", 7)), "Invalid character in significand"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1" "\0" "2", 5)), "Invalid character in significand"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1" "\0" "2p1", 7)), "Invalid character in significand"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p\0", 5)), "Invalid character in exponent"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1\0", 6)), "Invalid character in exponent"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1\02", 7)), "Invalid character in exponent"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1" "\0" "2", 7)), "Invalid character in exponent"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p0f"), "Invalid character in exponent"); diff --git a/unittests/ADT/FunctionRefTest.cpp b/unittests/ADT/FunctionRefTest.cpp index 075d9a070df72..b7ef7d79e5f99 100644 --- a/unittests/ADT/FunctionRefTest.cpp +++ b/unittests/ADT/FunctionRefTest.cpp @@ -14,6 +14,20 @@ using namespace llvm; namespace { +// Ensure that there is a default constructor and we can test for a null +// function_ref. +TEST(FunctionRefTest, Null) { + function_ref<int()> F; + EXPECT_FALSE(F); + + auto L = [] { return 1; }; + F = L; + EXPECT_TRUE(F); + + F = {}; + EXPECT_FALSE(F); +} + // Ensure that copies of a function_ref copy the underlying state rather than // causing one function_ref to chain to the next. TEST(FunctionRefTest, Copy) { diff --git a/unittests/Analysis/AliasAnalysisTest.cpp b/unittests/Analysis/AliasAnalysisTest.cpp index 84a04257bc270..9a864b77a9d82 100644 --- a/unittests/Analysis/AliasAnalysisTest.cpp +++ b/unittests/Analysis/AliasAnalysisTest.cpp @@ -180,10 +180,11 @@ TEST_F(AliasAnalysisTest, getModRefInfo) { auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); auto *CmpXChg1 = new AtomicCmpXchgInst( Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1), - AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB); + AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, + SyncScope::System, BB); auto *AtomicRMW = new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), - AtomicOrdering::Monotonic, CrossThread, BB); + AtomicOrdering::Monotonic, SyncScope::System, BB); ReturnInst::Create(C, nullptr, BB); diff --git a/unittests/Analysis/CGSCCPassManagerTest.cpp b/unittests/Analysis/CGSCCPassManagerTest.cpp index ab5d1862c23e7..d46d9535fa4b9 100644 --- a/unittests/Analysis/CGSCCPassManagerTest.cpp +++ b/unittests/Analysis/CGSCCPassManagerTest.cpp @@ -680,6 +680,7 @@ TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) { LazyCallGraph &, CGSCCUpdateResult &) { PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<TestFunctionAnalysis>(); return PA; })); @@ -719,12 +720,14 @@ TEST_F(CGSCCPassManagerTest, CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); - // Now run a module pass that preserves the LazyCallGraph and proxy but not + // Now run a module pass that preserves the LazyCallGraph and proxies but not // the Function analysis. MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); PA.preserve<CGSCCAnalysisManagerModuleProxy>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<FunctionAnalysisManagerModuleProxy>(); return PA; })); @@ -741,7 +744,7 @@ TEST_F(CGSCCPassManagerTest, EXPECT_EQ(2 * 6, FunctionAnalysisRuns); } -// Check that by marking the function pass and FAM proxy as preserved, this +// Check that by marking the function pass and proxies as preserved, this // propagates all the way through. TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) { @@ -765,6 +768,7 @@ TEST_F(CGSCCPassManagerTest, PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); PA.preserve<CGSCCAnalysisManagerModuleProxy>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<FunctionAnalysisManagerModuleProxy>(); PA.preserve<TestFunctionAnalysis>(); return PA; @@ -1014,6 +1018,9 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); + // Next, invalidate // - both analyses for the (f) and (x) SCCs, // - just the underlying (indirect) analysis for (g) SCC, and @@ -1026,14 +1033,16 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { auto &IndirectResult = DoublyIndirectResult.IDep; FunctionCount += IndirectResult.SCCDep.FunctionCount; auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserveSet<AllAnalysesOn<Function>>(); if (C.getName() == "(g)") PA.preserve<TestSCCAnalysis>(); else if (C.getName() == "(h3, h1, h2)") PA.preserve<TestIndirectSCCAnalysis>(); return PA; })); - // Finally, use the analysis again on each function, forcing re-computation - // for all of them. + // Finally, use the analysis again on each SCC (and function), forcing + // re-computation for all of them. CGPM.addPass( LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &) { @@ -1043,6 +1052,8 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); // Create a second CGSCC pass manager. This will cause the module-level // invalidation to occur, which will force yet another invalidation of the @@ -1058,13 +1069,15 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM2.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); - // Add a requires pass to populate the module analysis and then our function + // Add a requires pass to populate the module analysis and then our CGSCC // pass pipeline. MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); // Now require the module analysis again (it will have been invalidated once) - // and then use it again from a function pass manager. + // and then use it again from our second CGSCC pipeline.. MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); MPM.run(*M, MAM); @@ -1080,7 +1093,180 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns); EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns); + // We run the indirect function analysis once per function the first time. + // Then we re-run it for every SCC but "(g)". Then we re-run it for every + // function again. + EXPECT_EQ(6 + 5 + 6, IndirectFunctionAnalysisRuns); + // Four passes count each of six functions once (via SCCs). EXPECT_EQ(4 * 6, FunctionCount); } + +TEST_F(CGSCCPassManagerTest, TestAnalysisInvalidationCGSCCUpdate) { + int ModuleAnalysisRuns = 0; + MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); + + int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0, + DoublyIndirectSCCAnalysisRuns = 0; + CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); + CGAM.registerPass( + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + CGAM.registerPass([&] { + return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); + }); + + int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; + FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); + FAM.registerPass([&] { + return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns); + }); + + ModulePassManager MPM(/*DebugLogging*/ true); + + CGSCCPassManager CGPM(/*DebugLogging*/ true); + // First just use the analysis to get the function count and preserve + // everything. + using RequireTestIndirectFunctionAnalysisPass = + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>; + using RequireTestDoublyIndirectSCCAnalysisPass = + RequireAnalysisPass<TestDoublyIndirectSCCAnalysis, LazyCallGraph::SCC, + CGSCCAnalysisManager, LazyCallGraph &, + CGSCCUpdateResult &>; + CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Next, we inject an SCC pass that invalidates everything for the `(h3, h1, + // h2)` SCC but also deletes the call edge from `h2` to `h3` and updates the + // CG. This should successfully invalidate (and force to be re-run) all the + // analyses for that SCC and for the functions. + CGPM.addPass( + LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, + LazyCallGraph &CG, CGSCCUpdateResult &UR) { + (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); + if (C.getName() != "(h3, h1, h2)") + return PreservedAnalyses::all(); + + // Build the preserved set. + auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<TestIndirectSCCAnalysis>(); + PA.preserve<TestDoublyIndirectSCCAnalysis>(); + + // Delete the call from `h2` to `h3`. + auto &H2N = *llvm::find_if( + C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); + auto &H2F = H2N.getFunction(); + auto &H3F = *cast<CallInst>(H2F.begin()->begin())->getCalledFunction(); + assert(H3F.getName() == "h3" && "Wrong called function!"); + H2F.begin()->begin()->eraseFromParent(); + // Insert a bitcast of `h3` so that we retain a ref edge to it. + (void)CastInst::CreatePointerCast(&H3F, + Type::getInt8PtrTy(H2F.getContext()), + "dummy", &*H2F.begin()->begin()); + + // Now update the call graph. + auto &NewC = updateCGAndAnalysisManagerForFunctionPass( + CG, C, H2N, AM, UR, /*DebugLogging*/ true); + assert(&NewC != &C && "Should get a new SCC due to update!"); + (void)&NewC; + + return PA; + })); + // Now use the analysis again on each SCC and function, forcing + // re-computation for all of them. + CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Create another CGSCC pipeline that requires all the analyses again. + CGSCCPassManager CGPM2(/*DebugLogging*/ true); + CGPM2.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM2.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Next we inject an SCC pass that finds the `(h2)` SCC, adds a call to `h3` + // back to `h2`, and then invalidates everything for what will then be the + // `(h3, h1, h2)` SCC again. + CGSCCPassManager CGPM3(/*DebugLogging*/ true); + CGPM3.addPass( + LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, + LazyCallGraph &CG, CGSCCUpdateResult &UR) { + (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); + if (C.getName() != "(h2)") + return PreservedAnalyses::all(); + + // Build the preserved set. + auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<TestIndirectSCCAnalysis>(); + PA.preserve<TestDoublyIndirectSCCAnalysis>(); + + // Delete the bitcast of `h3` that we added earlier. + auto &H2N = *C.begin(); + auto &H2F = H2N.getFunction(); + auto &H3F = *cast<Function>(cast<BitCastInst>(H2F.begin()->begin())->getOperand(0)); + assert(H3F.getName() == "h3" && "Wrong called function!"); + H2F.begin()->begin()->eraseFromParent(); + // And insert a call to `h3`. + (void)CallInst::Create(&H3F, {}, "", &*H2F.begin()->begin()); + + // Now update the call graph. + auto &NewC = updateCGAndAnalysisManagerForFunctionPass( + CG, C, H2N, AM, UR, /*DebugLogging*/ true); + assert(&NewC != &C && "Should get a new SCC due to update!"); + (void)&NewC; + + return PA; + })); + // Now use the analysis again on each SCC and function, forcing + // re-computation for all of them. + CGPM3.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM3.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Create a second CGSCC pass manager. This will cause the module-level + // invalidation to occur, which will force yet another invalidation of the + // indirect SCC-level analysis as the module analysis it depends on gets + // invalidated. + CGSCCPassManager CGPM4(/*DebugLogging*/ true); + CGPM4.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM4.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Add a requires pass to populate the module analysis and then one of our + // CGSCC pipelines. Repeat for all four CGSCC pipelines. + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM4))); + MPM.run(*M, MAM); + + // We run over four SCCs the first time. But then we split an SCC into three. + // And then we merge those three back into one. + EXPECT_EQ(4 + 3 + 1, SCCAnalysisRuns); + // The module analysis pass should be run three times. + EXPECT_EQ(3, ModuleAnalysisRuns); + // We run over four SCCs the first time. Then over the two new ones. Then the + // entire module is invalidated causing a full run over all seven. Then we + // fold three SCCs back to one, and then run over the whole module again. + EXPECT_EQ(4 + 2 + 7 + 1 + 4, IndirectSCCAnalysisRuns); + EXPECT_EQ(4 + 2 + 7 + 1 + 4, DoublyIndirectSCCAnalysisRuns); + + // First we run over all six functions. Then we re-run it over three when we + // split their SCCs. Then we re-run over the whole module. Then we re-run + // over three functions merged back into a single SCC, and then over the + // whole module again. + EXPECT_EQ(6 + 3 + 6 + 3 + 6, FunctionAnalysisRuns); + + // Re run the function analysis over the entire module, and then re-run it + // over the `(h3, h1, h2)` SCC due to invalidation. Then we re-run it over + // the entire module, then the three functions merged back into a single SCC, + // and then over the whole module. + EXPECT_EQ(6 + 3 + 6 + 3 + 6, IndirectFunctionAnalysisRuns); +} } diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp index 8c251cf043b8f..65730486cd758 100644 --- a/unittests/Analysis/LazyCallGraphTest.cpp +++ b/unittests/Analysis/LazyCallGraphTest.cpp @@ -1277,9 +1277,10 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) { // be invalidated. LazyCallGraph::SCC &AC = *CG.lookupSCC(A); LazyCallGraph::SCC &CC = *CG.lookupSCC(C); - auto InvalidatedSCCs = RC.switchInternalEdgeToCall(A, C); - ASSERT_EQ(1u, InvalidatedSCCs.size()); - EXPECT_EQ(&AC, InvalidatedSCCs[0]); + EXPECT_TRUE(RC.switchInternalEdgeToCall(A, C, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(1u, MergedCs.size()); + EXPECT_EQ(&AC, MergedCs[0]); + })); EXPECT_EQ(2, CC.size()); EXPECT_EQ(&CC, CG.lookupSCC(A)); EXPECT_EQ(&CC, CG.lookupSCC(C)); @@ -1586,8 +1587,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { // Switch the ref edge from A -> D to a call edge. This should have no // effect as it is already in postorder and no new cycles are formed. - auto MergedCs = RC.switchInternalEdgeToCall(A, D); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(A, D)); ASSERT_EQ(4, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&BC, &RC[1]); @@ -1596,8 +1596,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { // Switch B -> C to a call edge. This doesn't form any new cycles but does // require reordering the SCCs. - MergedCs = RC.switchInternalEdgeToCall(B, C); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(B, C)); ASSERT_EQ(4, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&CC, &RC[1]); @@ -1605,9 +1604,10 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { EXPECT_EQ(&AC, &RC[3]); // Switch C -> B to a call edge. This forms a cycle and forces merging SCCs. - MergedCs = RC.switchInternalEdgeToCall(C, B); - ASSERT_EQ(1u, MergedCs.size()); - EXPECT_EQ(&CC, MergedCs[0]); + EXPECT_TRUE(RC.switchInternalEdgeToCall(C, B, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(1u, MergedCs.size()); + EXPECT_EQ(&CC, MergedCs[0]); + })); ASSERT_EQ(3, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&BC, &RC[1]); @@ -1720,8 +1720,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) { // Switch C3 -> B1 to a call edge. This doesn't form any new cycles but does // require reordering the SCCs in the face of tricky internal node // structures. - auto MergedCs = RC.switchInternalEdgeToCall(C3, B1); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(C3, B1)); ASSERT_EQ(8, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&B3C, &RC[1]); @@ -1852,10 +1851,12 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) { // C F C | | // \ / \ / | // G G | - auto MergedCs = RC.switchInternalEdgeToCall(F, B); - ASSERT_EQ(2u, MergedCs.size()); - EXPECT_EQ(&FC, MergedCs[0]); - EXPECT_EQ(&DC, MergedCs[1]); + EXPECT_TRUE(RC.switchInternalEdgeToCall( + F, B, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(2u, MergedCs.size()); + EXPECT_EQ(&FC, MergedCs[0]); + EXPECT_EQ(&DC, MergedCs[1]); + })); EXPECT_EQ(3, BC.size()); // And make sure the postorder was updated. diff --git a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp index 13693381c006c..844746f28c060 100644 --- a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp @@ -50,13 +50,14 @@ public: TEST(CompileOnDemandLayerTest, FindSymbol) { auto MockBaseLayer = createMockBaseLayer<int>( - DoNothingAndReturn<int>(0), DoNothingAndReturn<void>(), + DoNothingAndReturn<int>(0), + [](int Handle) { return Error::success(); }, [](const std::string &Name, bool) { if (Name == "foo") return JITSymbol(1, JITSymbolFlags::Exported); return JITSymbol(nullptr); }, - DoNothingAndReturn<JITSymbol>(nullptr)); + ReturnNullJITSymbol()); typedef decltype(MockBaseLayer) MockBaseLayerT; DummyCallbackManager CallbackMgr; diff --git a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp index 25b6c891c6220..2756999c21608 100644 --- a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp @@ -17,7 +17,7 @@ namespace { struct MockBaseLayer { - typedef int ModuleSetHandleT; + typedef int ModuleHandleT; JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { if (Name == "bar") @@ -37,13 +37,15 @@ TEST(GlobalMappingLayerTest, Empty) { // Test fall-through for symbol in base layer. auto BarSym = L.findSymbol("bar", true); - EXPECT_EQ(BarSym.getAddress(), static_cast<JITTargetAddress>(0x4567)) + EXPECT_EQ(cantFail(BarSym.getAddress()), + static_cast<JITTargetAddress>(0x4567)) << "Symbol lookup fall-through failed."; // Test setup of a global mapping. L.setGlobalMapping("foo", 0x0123); auto FooSym2 = L.findSymbol("foo", true); - EXPECT_EQ(FooSym2.getAddress(), static_cast<JITTargetAddress>(0x0123)) + EXPECT_EQ(cantFail(FooSym2.getAddress()), + static_cast<JITTargetAddress>(0x0123)) << "Symbol mapping setup failed."; // Test removal of a global mapping. diff --git a/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp index f65dc0cd609dc..0dba66d475351 100644 --- a/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp @@ -27,7 +27,7 @@ struct MockBaseLayer { TEST(LazyEmittingLayerTest, Empty) { MockBaseLayer M; llvm::orc::LazyEmittingLayer<MockBaseLayer> L(M); - L.addModule(std::unique_ptr<llvm::Module>(), nullptr, nullptr); + cantFail(L.addModule(std::unique_ptr<llvm::Module>(), nullptr)); } } diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp index 2fdf9e8b7379b..25103f79ac6c7 100644 --- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp @@ -14,6 +14,7 @@ #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/NullResolver.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Object/ObjectFile.h" #include "gtest/gtest.h" @@ -21,12 +22,6 @@ using namespace llvm::orc; namespace { -// Stand-in for RuntimeDyld::MemoryManager -typedef int MockMemoryManager; - -// Stand-in for RuntimeDyld::SymbolResolver -typedef int MockSymbolResolver; - // stand-in for object::ObjectFile typedef int MockObjectFile; @@ -54,34 +49,37 @@ public: MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); } - template <typename ObjPtrT, typename MemoryManagerPtrT, - typename SymbolResolverPtrT> - ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through"; - EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through"; + template <typename ObjPtrT> + llvm::Expected<ObjHandleT> + addObject(ObjPtrT Obj, + std::shared_ptr<llvm::JITSymbolResolver> Resolver) { + EXPECT_EQ(MockResolver, Resolver) << "Resolver should pass through"; EXPECT_EQ(MockObject + 1, *Obj) << "Transform should be applied"; LastCalled = "addObject"; MockObjHandle = 111; return MockObjHandle; } + template <typename ObjPtrT> - void expectAddObject(ObjPtrT Obj, MockMemoryManager *MemMgr, - MockSymbolResolver *Resolver) { - MockManager = *MemMgr; - MockResolver = *Resolver; + void expectAddObject(ObjPtrT Obj, + std::shared_ptr<llvm::JITSymbolResolver> Resolver) { + MockResolver = Resolver; MockObject = *Obj; } + + void verifyAddObject(ObjHandleT Returned) { EXPECT_EQ("addObject", LastCalled); EXPECT_EQ(MockObjHandle, Returned) << "Return should pass through"; resetExpectations(); } - void removeObject(ObjHandleT H) { + llvm::Error removeObject(ObjHandleT H) { EXPECT_EQ(MockObjHandle, H); LastCalled = "removeObject"; + return llvm::Error::success(); } + void expectRemoveObject(ObjHandleT H) { MockObjHandle = H; } void verifyRemoveObject() { EXPECT_EQ("removeObject", LastCalled); @@ -94,7 +92,7 @@ public: EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through"; LastCalled = "findSymbol"; MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None); - return MockSymbol; + return llvm::JITSymbol(122, llvm::JITSymbolFlags::None); } void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) { MockName = Name; @@ -102,7 +100,8 @@ public: } void verifyFindSymbol(llvm::JITSymbol Returned) { EXPECT_EQ("findSymbol", LastCalled); - EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress()) + EXPECT_EQ(cantFail(MockSymbol.getAddress()), + cantFail(Returned.getAddress())) << "Return should pass through"; resetExpectations(); } @@ -114,7 +113,7 @@ public: EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through"; LastCalled = "findSymbolIn"; MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None); - return MockSymbol; + return llvm::JITSymbol(122, llvm::JITSymbolFlags::None); } void expectFindSymbolIn(ObjHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { @@ -124,16 +123,20 @@ public: } void verifyFindSymbolIn(llvm::JITSymbol Returned) { EXPECT_EQ("findSymbolIn", LastCalled); - EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress()) + EXPECT_EQ(cantFail(MockSymbol.getAddress()), + cantFail(Returned.getAddress())) << "Return should pass through"; resetExpectations(); } - void emitAndFinalize(ObjHandleT H) { + llvm::Error emitAndFinalize(ObjHandleT H) { EXPECT_EQ(MockObjHandle, H) << "Handle should pass through"; LastCalled = "emitAndFinalize"; + return llvm::Error::success(); } + void expectEmitAndFinalize(ObjHandleT H) { MockObjHandle = H; } + void verifyEmitAndFinalize() { EXPECT_EQ("emitAndFinalize", LastCalled); resetExpectations(); @@ -160,8 +163,7 @@ public: private: // Backing fields for remembering parameter/return values std::string LastCalled; - MockMemoryManager MockManager; - MockSymbolResolver MockResolver; + std::shared_ptr<llvm::JITSymbolResolver> MockResolver; MockObjectFile MockObject; ObjHandleT MockObjHandle; std::string MockName; @@ -174,8 +176,7 @@ private: // Clear remembered parameters between calls void resetExpectations() { LastCalled = "nothing"; - MockManager = 0; - MockResolver = 0; + MockResolver = nullptr; MockObject = 0; MockObjHandle = 0; MockName = "bogus"; @@ -204,47 +205,42 @@ TEST(ObjectTransformLayerTest, Main) { return Obj; }); - // Instantiate some mock objects to use below - MockMemoryManager MockManager = 233; - MockSymbolResolver MockResolver = 244; - // Test addObject with T1 (allocating) auto Obj1 = std::make_shared<MockObjectFile>(211); - auto MM = llvm::make_unique<MockMemoryManager>(MockManager); - auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver); - M.expectAddObject(Obj1, MM.get(), SR.get()); - auto H = T1.addObject(std::move(Obj1), std::move(MM), std::move(SR)); + auto SR = std::make_shared<NullResolver>(); + M.expectAddObject(Obj1, SR); + auto H = cantFail(T1.addObject(std::move(Obj1), SR)); M.verifyAddObject(H); // Test addObjectSet with T2 (mutating) auto Obj2 = std::make_shared<MockObjectFile>(222); - M.expectAddObject(Obj2, &MockManager, &MockResolver); - H = T2.addObject(Obj2, &MockManager, &MockResolver); + M.expectAddObject(Obj2, SR); + H = cantFail(T2.addObject(Obj2, SR)); M.verifyAddObject(H); EXPECT_EQ(223, *Obj2) << "Expected mutation"; // Test removeObjectSet M.expectRemoveObject(H); - T1.removeObject(H); + cantFail(T1.removeObject(H)); M.verifyRemoveObject(); // Test findSymbol std::string Name = "foo"; bool ExportedOnly = true; M.expectFindSymbol(Name, ExportedOnly); - llvm::JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly); - M.verifyFindSymbol(Symbol); + llvm::JITSymbol Sym1 = T2.findSymbol(Name, ExportedOnly); + M.verifyFindSymbol(std::move(Sym1)); // Test findSymbolIn Name = "bar"; ExportedOnly = false; M.expectFindSymbolIn(H, Name, ExportedOnly); - Symbol = T1.findSymbolIn(H, Name, ExportedOnly); - M.verifyFindSymbolIn(Symbol); + llvm::JITSymbol Sym2 = T1.findSymbolIn(H, Name, ExportedOnly); + M.verifyFindSymbolIn(std::move(Sym2)); // Test emitAndFinalize M.expectEmitAndFinalize(H); - T2.emitAndFinalize(H); + cantFail(T2.emitAndFinalize(H)); M.verifyEmitAndFinalize(); // Test mapSectionAddress @@ -295,7 +291,11 @@ TEST(ObjectTransformLayerTest, Main) { }; // Construct the jit layers. - RTDyldObjectLinkingLayer BaseLayer; + RTDyldObjectLinkingLayer BaseLayer( + []() { + return std::make_shared<llvm::SectionMemoryManager>(); + }); + auto IdentityTransform = [](std::shared_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>> Obj) { @@ -312,17 +312,16 @@ TEST(ObjectTransformLayerTest, Main) { // Make sure that the calls from IRCompileLayer to ObjectTransformLayer // compile. - NullResolver Resolver; - NullManager Manager; - CompileLayer.addModule(std::shared_ptr<llvm::Module>(), &Manager, &Resolver); + auto Resolver = std::make_shared<NullResolver>(); + cantFail(CompileLayer.addModule(std::shared_ptr<llvm::Module>(), Resolver)); // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer // compile. decltype(TransformLayer)::ObjHandleT H2; - TransformLayer.emitAndFinalize(H2); + cantFail(TransformLayer.emitAndFinalize(H2)); TransformLayer.findSymbolIn(H2, Name, false); TransformLayer.findSymbol(Name, true); TransformLayer.mapSectionAddress(H2, nullptr, 0); - TransformLayer.removeObject(H2); + cantFail(TransformLayer.removeObject(H2)); } } diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp index 2900a9c927669..5a4d6b4a2252b 100644 --- a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -66,10 +66,11 @@ protected: auto *ET = CCtx->APIExecTest; CCtx->M = ET->createTestModule(ET->TM->getTargetTriple()); LLVMSharedModuleRef SM = LLVMOrcMakeSharedModule(wrap(CCtx->M.release())); - CCtx->H = LLVMOrcAddEagerlyCompiledIR(JITStack, SM, myResolver, nullptr); + LLVMOrcAddEagerlyCompiledIR(JITStack, &CCtx->H, SM, myResolver, nullptr); LLVMOrcDisposeSharedModuleRef(SM); CCtx->Compiled = true; - LLVMOrcTargetAddress MainAddr = LLVMOrcGetSymbolAddress(JITStack, "main"); + LLVMOrcTargetAddress MainAddr; + LLVMOrcGetSymbolAddress(JITStack, &MainAddr, "main"); LLVMOrcSetIndirectStubPointer(JITStack, "foo", MainAddr); return MainAddr; } @@ -89,10 +90,12 @@ TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) { LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); LLVMSharedModuleRef SM = LLVMOrcMakeSharedModule(wrap(M.release())); - LLVMOrcModuleHandle H = - LLVMOrcAddEagerlyCompiledIR(JIT, SM, myResolver, nullptr); + LLVMOrcModuleHandle H; + LLVMOrcAddEagerlyCompiledIR(JIT, &H, SM, myResolver, nullptr); LLVMOrcDisposeSharedModuleRef(SM); - MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main"); + LLVMOrcTargetAddress MainAddr; + LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); + MainFnTy MainFn = (MainFnTy)MainAddr; int Result = MainFn(); EXPECT_EQ(Result, 42) << "Eagerly JIT'd code did not return expected result"; @@ -115,10 +118,12 @@ TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) { LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); LLVMSharedModuleRef SM = LLVMOrcMakeSharedModule(wrap(M.release())); - LLVMOrcModuleHandle H = - LLVMOrcAddLazilyCompiledIR(JIT, SM, myResolver, nullptr); + LLVMOrcModuleHandle H; + LLVMOrcAddLazilyCompiledIR(JIT, &H, SM, myResolver, nullptr); LLVMOrcDisposeSharedModuleRef(SM); - MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main"); + LLVMOrcTargetAddress MainAddr; + LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); + MainFnTy MainFn = (MainFnTy)MainAddr; int Result = MainFn(); EXPECT_EQ(Result, 42) << "Lazily JIT'd code did not return expected result"; @@ -140,11 +145,12 @@ TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) { CompileContext C; C.APIExecTest = this; - LLVMOrcCreateIndirectStub(JIT, "foo", - LLVMOrcCreateLazyCompileCallback(JIT, - myCompileCallback, - &C)); - MainFnTy FooFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "foo"); + LLVMOrcTargetAddress CCAddr; + LLVMOrcCreateLazyCompileCallback(JIT, &CCAddr, myCompileCallback, &C); + LLVMOrcCreateIndirectStub(JIT, "foo", CCAddr); + LLVMOrcTargetAddress MainAddr; + LLVMOrcGetSymbolAddress(JIT, &MainAddr, "foo"); + MainFnTy FooFn = (MainFnTy)MainAddr; int Result = FooFn(); EXPECT_TRUE(C.Compiled) << "Function wasn't lazily compiled"; diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h index d7049ef00e6d1..6c6b4918c2053 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -119,19 +119,21 @@ public: RemoveModuleFtor &&RemoveModule, FindSymbolFtor &&FindSymbol, FindSymbolInFtor &&FindSymbolIn) - : AddModule(AddModule), RemoveModule(RemoveModule), - FindSymbol(FindSymbol), FindSymbolIn(FindSymbolIn) + : AddModule(std::move(AddModule)), + RemoveModule(std::move(RemoveModule)), + FindSymbol(std::move(FindSymbol)), + FindSymbolIn(std::move(FindSymbolIn)) {} template <typename ModuleT, typename MemoryManagerPtrT, typename SymbolResolverPtrT> - ModuleHandleT addModule(ModuleT Ms, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { + Expected<ModuleHandleT> addModule(ModuleT Ms, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { return AddModule(std::move(Ms), std::move(MemMgr), std::move(Resolver)); } - void removeModule(ModuleHandleT H) { - RemoveModule(H); + Error removeModule(ModuleHandleT H) { + return RemoveModule(H); } JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { @@ -169,15 +171,24 @@ createMockBaseLayer(AddModuleFtor &&AddModule, std::forward<FindSymbolInFtor>(FindSymbolIn)); } + +class ReturnNullJITSymbol { +public: + template <typename... Args> + JITSymbol operator()(Args...) const { + return nullptr; + } +}; + template <typename ReturnT> class DoNothingAndReturn { public: - DoNothingAndReturn(ReturnT Val) : Val(Val) {} + DoNothingAndReturn(ReturnT Ret) : Ret(std::move(Ret)) {} template <typename... Args> - ReturnT operator()(Args...) const { return Val; } + void operator()(Args...) const { return Ret; } private: - ReturnT Val; + ReturnT Ret; }; template <> diff --git a/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp index 7c821bc2c34b3..e4b61d855c5f4 100644 --- a/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -45,9 +45,9 @@ public: }; TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { - class SectionMemoryManagerWrapper : public SectionMemoryManager { + class MemoryManagerWrapper : public SectionMemoryManager { public: - SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {} + MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {} uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, @@ -63,7 +63,10 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { bool &DebugSeen; }; - RTDyldObjectLinkingLayer ObjLayer; + bool DebugSectionSeen = false; + auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen); + + RTDyldObjectLinkingLayer ObjLayer([&MM]() { return MM; }); LLVMContext Context; auto M = llvm::make_unique<Module>("", Context); @@ -89,9 +92,6 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { std::make_shared<object::OwningBinary<object::ObjectFile>>( SimpleCompiler(*TM)(*M)); - bool DebugSectionSeen = false; - auto SMMW = - std::make_shared<SectionMemoryManagerWrapper>(DebugSectionSeen); auto Resolver = createLambdaResolver( [](const std::string &Name) { @@ -103,21 +103,21 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { { // Test with ProcessAllSections = false (the default). - auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver); - ObjLayer.emitAndFinalize(H); + auto H = cantFail(ObjLayer.addObject(Obj, Resolver)); + cantFail(ObjLayer.emitAndFinalize(H)); EXPECT_EQ(DebugSectionSeen, false) << "Unexpected debug info section"; - ObjLayer.removeObject(H); + cantFail(ObjLayer.removeObject(H)); } { // Test with ProcessAllSections = true. ObjLayer.setProcessAllSections(true); - auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver); - ObjLayer.emitAndFinalize(H); + auto H = cantFail(ObjLayer.addObject(Obj, Resolver)); + cantFail(ObjLayer.emitAndFinalize(H)); EXPECT_EQ(DebugSectionSeen, true) << "Expected debug info section not seen"; - ObjLayer.removeObject(H); + cantFail(ObjLayer.removeObject(H)); } } @@ -125,7 +125,9 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { if (!TM) return; - RTDyldObjectLinkingLayer ObjLayer; + auto MM = std::make_shared<SectionMemoryManagerWrapper>(); + + RTDyldObjectLinkingLayer ObjLayer([&MM]() { return MM; }); SimpleCompiler Compile(*TM); // Create a pair of modules that will trigger recursive finalization: @@ -179,15 +181,14 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { return JITSymbol(nullptr); }); - auto SMMW = std::make_shared<SectionMemoryManagerWrapper>(); - ObjLayer.addObject(std::move(Obj1), SMMW, &*Resolver); - auto H = ObjLayer.addObject(std::move(Obj2), SMMW, &*Resolver); - ObjLayer.emitAndFinalize(H); - ObjLayer.removeObject(H); - + cantFail(ObjLayer.addObject(std::move(Obj1), Resolver)); + auto H = cantFail(ObjLayer.addObject(std::move(Obj2), Resolver)); + cantFail(ObjLayer.emitAndFinalize(H)); + cantFail(ObjLayer.removeObject(H)); + // Finalization of module 2 should trigger finalization of module 1. // Verify that finalize on SMMW is only called once. - EXPECT_EQ(SMMW->FinalizationCount, 1) + EXPECT_EQ(MM->FinalizationCount, 1) << "Extra call to finalize"; } @@ -195,7 +196,9 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { if (!TM) return; - RTDyldObjectLinkingLayer ObjLayer; + auto MM = std::make_shared<SectionMemoryManagerWrapper>(); + + RTDyldObjectLinkingLayer ObjLayer([&MM]() { return MM; }); SimpleCompiler Compile(*TM); // Create a pair of unrelated modules: @@ -240,15 +243,14 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { std::make_shared<object::OwningBinary<object::ObjectFile>>( Compile(*MB2.getModule())); - auto SMMW = std::make_shared<SectionMemoryManagerWrapper>(); - NullResolver NR; - auto H = ObjLayer.addObject(std::move(Obj1), SMMW, &NR); - ObjLayer.addObject(std::move(Obj2), SMMW, &NR); - ObjLayer.emitAndFinalize(H); - ObjLayer.removeObject(H); - + auto NR = std::make_shared<NullResolver>(); + auto H = cantFail(ObjLayer.addObject(std::move(Obj1), NR)); + cantFail(ObjLayer.addObject(std::move(Obj2), NR)); + cantFail(ObjLayer.emitAndFinalize(H)); + cantFail(ObjLayer.removeObject(H)); + // Only one call to needsToReserveAllocationSpace should have been made. - EXPECT_EQ(SMMW->NeedsToReserveAllocationSpaceCount, 1) + EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1) << "More than one call to needsToReserveAllocationSpace " "(multiple unrelated objects loaded prior to finalization)"; } diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt index 6734de8e2d950..d76ebfa64d881 100644 --- a/unittests/IR/CMakeLists.txt +++ b/unittests/IR/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS AsmParser Core Support + Passes ) set(IRSources @@ -15,6 +16,7 @@ set(IRSources DebugTypeODRUniquingTest.cpp DominatorTreeTest.cpp FunctionTest.cpp + PassBuilderCallbacksTest.cpp IRBuilderTest.cpp InstructionsTest.cpp IntrinsicsTest.cpp diff --git a/unittests/IR/ModuleTest.cpp b/unittests/IR/ModuleTest.cpp index d93d036bb115a..af55a098adda0 100644 --- a/unittests/IR/ModuleTest.cpp +++ b/unittests/IR/ModuleTest.cpp @@ -63,7 +63,7 @@ TEST(ModuleTest, randomNumberGenerator) { std::array<int, NBCheck> RandomStreams[2]; for (auto &RandomStream : RandomStreams) { - std::unique_ptr<RandomNumberGenerator> RNG{M.createRNG(&DP)}; + std::unique_ptr<RandomNumberGenerator> RNG = M.createRNG(&DP); std::generate(RandomStream.begin(), RandomStream.end(), [&]() { return dist(*RNG); }); } diff --git a/unittests/IR/PassBuilderCallbacksTest.cpp b/unittests/IR/PassBuilderCallbacksTest.cpp new file mode 100644 index 0000000000000..df0b11f6cc71c --- /dev/null +++ b/unittests/IR/PassBuilderCallbacksTest.cpp @@ -0,0 +1,520 @@ +//===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <llvm/Analysis/CGSCCPassManager.h> +#include <llvm/Analysis/LoopAnalysisManager.h> +#include <llvm/AsmParser/Parser.h> +#include <llvm/IR/LLVMContext.h> +#include <llvm/IR/PassManager.h> +#include <llvm/Passes/PassBuilder.h> +#include <llvm/Support/SourceMgr.h> +#include <llvm/Transforms/Scalar/LoopPassManager.h> + +using namespace llvm; + +namespace llvm { +/// Provide an ostream operator for StringRef. +/// +/// For convenience we provide a custom matcher below for IRUnit's and analysis +/// result's getName functions, which most of the time returns a StringRef. The +/// matcher makes use of this operator. +static std::ostream &operator<<(std::ostream &O, StringRef S) { + return O << S.str(); +} +} + +namespace { +using testing::DoDefault; +using testing::Return; +using testing::Expectation; +using testing::Invoke; +using testing::WithArgs; +using testing::_; + +/// \brief A CRTP base for analysis mock handles +/// +/// This class reconciles mocking with the value semantics implementation of the +/// AnalysisManager. Analysis mock handles should derive from this class and +/// call \c setDefault() in their constroctur for wiring up the defaults defined +/// by this base with their mock run() and invalidate() implementations. +template <typename DerivedT, typename IRUnitT, + typename AnalysisManagerT = AnalysisManager<IRUnitT>, + typename... ExtraArgTs> +class MockAnalysisHandleBase { +public: + class Analysis : public AnalysisInfoMixin<Analysis> { + friend AnalysisInfoMixin<Analysis>; + friend MockAnalysisHandleBase; + static AnalysisKey Key; + + DerivedT *Handle; + + Analysis(DerivedT &Handle) : Handle(&Handle) { + static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value, + "Must pass the derived type to this template!"); + } + + public: + class Result { + friend MockAnalysisHandleBase; + + DerivedT *Handle; + + Result(DerivedT &Handle) : Handle(&Handle) {} + + public: + // Forward invalidation events to the mock handle. + bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA, + typename AnalysisManagerT::Invalidator &Inv) { + return Handle->invalidate(IR, PA, Inv); + } + }; + + Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) { + return Handle->run(IR, AM, ExtraArgs...); + } + }; + + Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); } + typename Analysis::Result getResult() { + return typename Analysis::Result(static_cast<DerivedT &>(*this)); + } + +protected: + // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within + // the template, so we use a boring static function. + static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA, + typename AnalysisManagerT::Invalidator &Inv) { + auto PAC = PA.template getChecker<Analysis>(); + return !PAC.preserved() && + !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>(); + } + + /// Derived classes should call this in their constructor to set up default + /// mock actions. (We can't do this in our constructor because this has to + /// run after the DerivedT is constructed.) + void setDefaults() { + ON_CALL(static_cast<DerivedT &>(*this), + run(_, _, testing::Matcher<ExtraArgTs>(_)...)) + .WillByDefault(Return(this->getResult())); + ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _)) + .WillByDefault(Invoke(&invalidateCallback)); + } +}; + +/// \brief A CRTP base for pass mock handles +/// +/// This class reconciles mocking with the value semantics implementation of the +/// PassManager. Pass mock handles should derive from this class and +/// call \c setDefault() in their constroctur for wiring up the defaults defined +/// by this base with their mock run() and invalidate() implementations. +template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT, + typename... ExtraArgTs> +AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT, + ExtraArgTs...>::Analysis::Key; + +template <typename DerivedT, typename IRUnitT, + typename AnalysisManagerT = AnalysisManager<IRUnitT>, + typename... ExtraArgTs> +class MockPassHandleBase { +public: + class Pass : public PassInfoMixin<Pass> { + friend MockPassHandleBase; + + DerivedT *Handle; + + Pass(DerivedT &Handle) : Handle(&Handle) { + static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value, + "Must pass the derived type to this template!"); + } + + public: + PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs... ExtraArgs) { + return Handle->run(IR, AM, ExtraArgs...); + } + }; + + Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); } + +protected: + /// Derived classes should call this in their constructor to set up default + /// mock actions. (We can't do this in our constructor because this has to + /// run after the DerivedT is constructed.) + void setDefaults() { + ON_CALL(static_cast<DerivedT &>(*this), + run(_, _, testing::Matcher<ExtraArgTs>(_)...)) + .WillByDefault(Return(PreservedAnalyses::all())); + } +}; + +/// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop. +/// These handles define the appropriate run() mock interface for the respective +/// IRUnit type. +template <typename IRUnitT> struct MockPassHandle; +template <> +struct MockPassHandle<Loop> + : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager, + LoopStandardAnalysisResults &, LPMUpdater &> { + MOCK_METHOD4(run, + PreservedAnalyses(Loop &, LoopAnalysisManager &, + LoopStandardAnalysisResults &, LPMUpdater &)); + MockPassHandle() { setDefaults(); } +}; + +template <> +struct MockPassHandle<Function> + : MockPassHandleBase<MockPassHandle<Function>, Function> { + MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &)); + + MockPassHandle() { setDefaults(); } +}; + +template <> +struct MockPassHandle<LazyCallGraph::SCC> + : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC, + CGSCCAnalysisManager, LazyCallGraph &, + CGSCCUpdateResult &> { + MOCK_METHOD4(run, + PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &, + LazyCallGraph &G, CGSCCUpdateResult &UR)); + + MockPassHandle() { setDefaults(); } +}; + +template <> +struct MockPassHandle<Module> + : MockPassHandleBase<MockPassHandle<Module>, Module> { + MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &)); + + MockPassHandle() { setDefaults(); } +}; + +/// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop. +/// These handles define the appropriate run() and invalidate() mock interfaces +/// for the respective IRUnit type. +template <typename IRUnitT> struct MockAnalysisHandle; +template <> +struct MockAnalysisHandle<Loop> + : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop, + LoopAnalysisManager, + LoopStandardAnalysisResults &> { + + MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &, + LoopStandardAnalysisResults &)); + + MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &, + LoopAnalysisManager::Invalidator &)); + + MockAnalysisHandle<Loop>() { this->setDefaults(); } +}; + +template <> +struct MockAnalysisHandle<Function> + : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> { + MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &)); + + MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &)); + + MockAnalysisHandle<Function>() { setDefaults(); } +}; + +template <> +struct MockAnalysisHandle<LazyCallGraph::SCC> + : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>, + LazyCallGraph::SCC, CGSCCAnalysisManager, + LazyCallGraph &> { + MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &, + CGSCCAnalysisManager &, LazyCallGraph &)); + + MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &, + CGSCCAnalysisManager::Invalidator &)); + + MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); } +}; + +template <> +struct MockAnalysisHandle<Module> + : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> { + MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &)); + + MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &, + ModuleAnalysisManager::Invalidator &)); + + MockAnalysisHandle<Module>() { setDefaults(); } +}; + +static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + return parseAssemblyString(IR, Err, C); +} + +template <typename PassManagerT> class PassBuilderCallbacksTest; + +/// This test fixture is shared between all the actual tests below and +/// takes care of setting up appropriate defaults. +/// +/// The template specialization serves to extract the IRUnit and AM types from +/// the given PassManagerT. +template <typename TestIRUnitT, typename... ExtraPassArgTs, + typename... ExtraAnalysisArgTs> +class PassBuilderCallbacksTest<PassManager< + TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>, + ExtraPassArgTs...>> : public testing::Test { +protected: + using IRUnitT = TestIRUnitT; + using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>; + using PassManagerT = + PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>; + using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis; + + LLVMContext Context; + std::unique_ptr<Module> M; + + PassBuilder PB; + ModulePassManager PM; + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager AM; + + MockPassHandle<IRUnitT> PassHandle; + MockAnalysisHandle<IRUnitT> AnalysisHandle; + + static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM, + ExtraAnalysisArgTs &&... Args) { + (void)AM.template getResult<AnalysisT>( + U, std::forward<ExtraAnalysisArgTs>(Args)...); + return PreservedAnalyses::all(); + } + + PassBuilderCallbacksTest() + : M(parseIR(Context, + "declare void @bar()\n" + "define void @foo(i32 %n) {\n" + "entry:\n" + " br label %loop\n" + "loop:\n" + " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n" + " %iv.next = add i32 %iv, 1\n" + " tail call void @bar()\n" + " %cmp = icmp eq i32 %iv, %n\n" + " br i1 %cmp, label %exit, label %loop\n" + "exit:\n" + " ret void\n" + "}\n")), + PM(true), LAM(true), FAM(true), CGAM(true), AM(true) { + + /// Register a callback for analysis registration. + /// + /// The callback is a function taking a reference to an AnalyisManager + /// object. When called, the callee gets to register its own analyses with + /// this PassBuilder instance. + PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) { + // Register our mock analysis + AM.registerPass([this] { return AnalysisHandle.getAnalysis(); }); + }); + + /// Register a callback for pipeline parsing. + /// + /// During parsing of a textual pipeline, the PassBuilder will call these + /// callbacks for each encountered pass name that it does not know. This + /// includes both simple pass names as well as names of sub-pipelines. In + /// the latter case, the InnerPipeline is not empty. + PB.registerPipelineParsingCallback( + [this](StringRef Name, PassManagerT &PM, + ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { + /// Handle parsing of the names of analysis utilities such as + /// require<test-analysis> and invalidate<test-analysis> for our + /// analysis mock handle + if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM)) + return true; + + /// Parse the name of our pass mock handle + if (Name == "test-transform") { + PM.addPass(PassHandle.getPass()); + return true; + } + return false; + }); + + /// Register builtin analyses and cross-register the analysis proxies + PB.registerModuleAnalyses(AM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, AM); + } +}; + +/// Define a custom matcher for objects which support a 'getName' method. +/// +/// LLVM often has IR objects or analysis objects which expose a name +/// and in tests it is convenient to match these by name for readability. +/// Usually, this name is either a StringRef or a plain std::string. This +/// matcher supports any type exposing a getName() method of this form whose +/// return value is compatible with an std::ostream. For StringRef, this uses +/// the shift operator defined above. +/// +/// It should be used as: +/// +/// HasName("my_function") +/// +/// No namespace or other qualification is required. +MATCHER_P(HasName, Name, "") { + *result_listener << "has name '" << arg.getName() << "'"; + return Name == arg.getName(); +} + +using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>; +using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>; +using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>; +using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>; + +/// Test parsing of the name of our mock pass for all IRUnits. +/// +/// The pass should by default run our mock analysis and then preserve it. +TEST_F(ModuleCallbacksTest, Passes) { + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); + EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) + .WillOnce(Invoke(getAnalysisResult)); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(FunctionCallbacksTest, Passes) { + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); + EXPECT_CALL(PassHandle, run(HasName("foo"), _)) + .WillOnce(Invoke(getAnalysisResult)); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(LoopCallbacksTest, Passes) { + EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); + EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(CGSCCCallbacksTest, Passes) { + EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); + EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +/// Test parsing of the names of analysis utilities for our mock analysis +/// for all IRUnits. +/// +/// We first require<>, then invalidate<> it, expecting the analysis to be run +/// once and subsequently invalidated. +TEST_F(ModuleCallbacksTest, AnalysisUtilities) { + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); + EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); + + StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(CGSCCCallbacksTest, PassUtilities) { + EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); + EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _)); + + StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(FunctionCallbacksTest, AnalysisUtilities) { + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); + EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _)); + + StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(LoopCallbacksTest, PassUtilities) { + EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); + EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _)); + + StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>"; + + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +/// Test parsing of the top-level pipeline. +/// +/// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline +/// from PassBuilder if it encounters an unknown pipeline entry at the top level +/// (i.e., the first entry on the pipeline). +/// This test parses a pipeline named 'another-pipeline', whose only elements +/// may be the test-transform pass or the analysis utilities +TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) { + PB.registerParseTopLevelPipelineCallback([this]( + ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline, + bool VerifyEachPass, bool DebugLogging) { + auto &FirstName = Pipeline.front().Name; + auto &InnerPipeline = Pipeline.front().InnerPipeline; + if (FirstName == "another-pipeline") { + for (auto &E : InnerPipeline) { + if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM)) + continue; + + if (E.Name == "test-transform") { + PM.addPass(PassHandle.getPass()); + continue; + } + return false; + } + } + return true; + }); + + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)); + EXPECT_CALL(PassHandle, run(HasName("<string>"), _)) + .WillOnce(Invoke(getAnalysisResult)); + EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _)); + + StringRef PipelineText = + "another-pipeline(test-transform,invalidate<test-analysis>)"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); + + /// Test the negative case + PipelineText = "another-pipeline(instcombine)"; + ASSERT_FALSE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; +} +} // end anonymous namespace diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index ad06cc4778fe4..0131bce3d2b21 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -210,6 +210,13 @@ TEST(PreservedAnalysesTest, Basic) { EXPECT_FALSE(PAC.preserved()); EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>()); } + auto PA5 = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>(); + { + auto PAC = PA5.getChecker<TestFunctionAnalysis>(); + EXPECT_FALSE(PAC.preserved()); + EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>()); + EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>()); + } } TEST(PreservedAnalysesTest, Preserve) { diff --git a/unittests/ProfileData/CMakeLists.txt b/unittests/ProfileData/CMakeLists.txt index dd39ca7da3ad6..80f9ada7b83a3 100644 --- a/unittests/ProfileData/CMakeLists.txt +++ b/unittests/ProfileData/CMakeLists.txt @@ -10,3 +10,5 @@ add_llvm_unittest(ProfileDataTests InstrProfTest.cpp SampleProfTest.cpp ) + +target_link_libraries(ProfileDataTests LLVMTestingSupport) diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp index 1d621f4060cad..6588e753eab01 100644 --- a/unittests/ProfileData/CoverageMappingTest.cpp +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -13,6 +13,8 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Testing/Support/Error.h" +#include "llvm/Testing/Support/SupportHelpers.h" #include "gtest/gtest.h" #include <ostream> @@ -21,15 +23,8 @@ using namespace llvm; using namespace coverage; -static ::testing::AssertionResult NoError(Error E) { - if (!E) - return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) - << "\n"; -} - -static ::testing::AssertionResult ErrorEquals(coveragemap_error Expected, - Error E) { +LLVM_NODISCARD static ::testing::AssertionResult +ErrorEquals(coveragemap_error Expected, Error E) { coveragemap_error Found; std::string FoundMsg; handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { @@ -209,7 +204,7 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> { std::vector<CounterExpression> Expressions; RawCoverageMappingReader Reader(Coverage, Filenames, Data.Filenames, Expressions, Data.Regions); - ASSERT_TRUE(NoError(Reader.read())); + EXPECT_THAT_ERROR(Reader.read(), Succeeded()); } void writeAndReadCoverageRegions(bool EmitFilenames = true) { @@ -227,7 +222,7 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> { void readProfCounts() { auto Profile = ProfileWriter.writeBuffer(); auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.takeError())); + EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded()); ProfileReader = std::move(ReaderOrErr.get()); } @@ -308,9 +303,10 @@ TEST_P(CoverageMappingTest, correct_deserialize_for_more_than_two_files) { } } +static const auto Err = [](Error E) { FAIL(); }; + TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) { - InstrProfRecord Record("func", 0x1234, {0}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {0}}, Err); const char *FileNames[] = {"bar", "baz", "foo"}; static const unsigned N = array_lengthof(FileNames); @@ -321,7 +317,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) { // in order to preserve that information during possible sorting of CMRs. addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); for (unsigned I = 0; I < N; ++I) { CoverageData Data = LoadedCoverage->getCoverageForFile(FileNames[I]); @@ -331,18 +327,15 @@ TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) { } TEST_P(CoverageMappingTest, load_coverage_with_bogus_function_name) { - InstrProfRecord RecordFunc1("", 0x1234, {10}); - NoError(ProfileWriter.addRecord(std::move(RecordFunc1))); + ProfileWriter.addRecord({"", 0x1234, {10}}, Err); startFunction("", 0x1234); addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5); - ErrorEquals(coveragemap_error::malformed, loadCoverageMapping()); + EXPECT_TRUE(ErrorEquals(coveragemap_error::malformed, loadCoverageMapping())); } TEST_P(CoverageMappingTest, load_coverage_for_several_functions) { - InstrProfRecord RecordFunc1("func1", 0x1234, {10}); - NoError(ProfileWriter.addRecord(std::move(RecordFunc1))); - InstrProfRecord RecordFunc2("func2", 0x2345, {20}); - NoError(ProfileWriter.addRecord(std::move(RecordFunc2))); + ProfileWriter.addRecord({"func1", 0x1234, {10}}, Err); + ProfileWriter.addRecord({"func2", 0x2345, {20}}, Err); startFunction("func1", 0x1234); addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5); @@ -350,7 +343,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_several_functions) { startFunction("func2", 0x2345); addCMR(Counter::getCounter(0), "bar", 2, 2, 6, 6); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); const auto FunctionRecords = LoadedCoverage->getCoveredFunctions(); EXPECT_EQ(2, std::distance(FunctionRecords.begin(), FunctionRecords.end())); @@ -386,15 +379,14 @@ TEST_P(CoverageMappingTest, expansion_gets_first_counter) { } TEST_P(CoverageMappingTest, basic_coverage_iteration) { - InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {30, 20, 10, 0}}, Err); startFunction("func", 0x1234); 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); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -411,7 +403,7 @@ TEST_P(CoverageMappingTest, basic_coverage_iteration) { TEST_P(CoverageMappingTest, uncovered_function) { startFunction("func", 0x1234); addCMR(Counter::getZero(), "file1", 1, 2, 3, 4); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -424,7 +416,7 @@ TEST_P(CoverageMappingTest, uncovered_function_with_mapping) { startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -435,14 +427,13 @@ TEST_P(CoverageMappingTest, uncovered_function_with_mapping) { } TEST_P(CoverageMappingTest, combine_regions) { - InstrProfRecord Record("func", 0x1234, {10, 20, 30}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {10, 20, 30}}, Err); startFunction("func", 0x1234); 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); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -454,14 +445,13 @@ TEST_P(CoverageMappingTest, combine_regions) { } TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) { - InstrProfRecord Record("func", 0x1234, {10, 20, 40}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {10, 20, 40}}, Err); startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -475,17 +465,15 @@ TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) { // If CodeRegions and ExpansionRegions cover the same area, // only counts of CodeRegions should be used. TEST_P(CoverageMappingTest, dont_combine_expansions) { - InstrProfRecord Record1("func", 0x1234, {10, 20}); - InstrProfRecord Record2("func", 0x1234, {0, 0}); - NoError(ProfileWriter.addRecord(std::move(Record1))); - NoError(ProfileWriter.addRecord(std::move(Record2))); + ProfileWriter.addRecord({"func", 0x1234, {10, 20}}, Err); + ProfileWriter.addRecord({"func", 0x1234, {0, 0}}, Err); startFunction("func", 0x1234); 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); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -498,8 +486,7 @@ TEST_P(CoverageMappingTest, dont_combine_expansions) { // If an area is covered only by ExpansionRegions, they should be combinated. TEST_P(CoverageMappingTest, combine_expansions) { - InstrProfRecord Record("func", 0x1234, {2, 3, 7}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {2, 3, 7}}, Err); startFunction("func", 0x1234); addCMR(Counter::getCounter(1), "include1", 1, 1, 1, 10); @@ -508,7 +495,7 @@ TEST_P(CoverageMappingTest, combine_expansions) { addExpansionCMR("file", "include1", 3, 1, 3, 5); addExpansionCMR("file", "include2", 3, 1, 3, 5); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("file"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -520,12 +507,11 @@ TEST_P(CoverageMappingTest, combine_expansions) { } TEST_P(CoverageMappingTest, strip_filename_prefix) { - InstrProfRecord Record("file1:func", 0x1234, {0}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"file1:func", 0x1234, {0}}, Err); startFunction("file1:func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); std::vector<std::string> Names; for (const auto &Func : LoadedCoverage->getCoveredFunctions()) @@ -535,12 +521,11 @@ TEST_P(CoverageMappingTest, strip_filename_prefix) { } TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) { - InstrProfRecord Record("<unknown>:func", 0x1234, {0}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"<unknown>:func", 0x1234, {0}}, Err); startFunction("<unknown>:func", 0x1234); addCMR(Counter::getCounter(0), "", 1, 1, 9, 9); - NoError(loadCoverageMapping(/*EmitFilenames=*/false)); + EXPECT_THAT_ERROR(loadCoverageMapping(/*EmitFilenames=*/false), Succeeded()); std::vector<std::string> Names; for (const auto &Func : LoadedCoverage->getCoveredFunctions()) @@ -550,10 +535,8 @@ TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) { } TEST_P(CoverageMappingTest, dont_detect_false_instantiations) { - InstrProfRecord Record1("foo", 0x1234, {10}); - InstrProfRecord Record2("bar", 0x2345, {20}); - NoError(ProfileWriter.addRecord(std::move(Record1))); - NoError(ProfileWriter.addRecord(std::move(Record2))); + ProfileWriter.addRecord({"foo", 0x1234, {10}}, Err); + ProfileWriter.addRecord({"bar", 0x2345, {20}}, Err); startFunction("foo", 0x1234); addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); @@ -563,7 +546,7 @@ TEST_P(CoverageMappingTest, dont_detect_false_instantiations) { addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); addExpansionCMR("main", "expanded", 9, 1, 9, 5); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); std::vector<const FunctionRecord *> Instantiations = LoadedCoverage->getInstantiations("expanded"); @@ -571,14 +554,13 @@ TEST_P(CoverageMappingTest, dont_detect_false_instantiations) { } TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) { - InstrProfRecord Record("func", 0x1234, {10}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {10}}, Err); startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); addExpansionCMR("main", "expanded", 4, 1, 4, 5); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); CoverageData Data = LoadedCoverage->getCoverageForFile("expanded"); std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); @@ -588,8 +570,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) { } TEST_P(CoverageMappingTest, skip_duplicate_function_record) { - InstrProfRecord Record("func", 0x1234, {1}); - NoError(ProfileWriter.addRecord(std::move(Record))); + ProfileWriter.addRecord({"func", 0x1234, {1}}, Err); startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); @@ -597,7 +578,7 @@ TEST_P(CoverageMappingTest, skip_duplicate_function_record) { startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); - NoError(loadCoverageMapping()); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); auto Funcs = LoadedCoverage->getCoveredFunctions(); unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end()); diff --git a/unittests/ProfileData/InstrProfTest.cpp b/unittests/ProfileData/InstrProfTest.cpp index 13436cc0d5b2e..79f880e475c62 100644 --- a/unittests/ProfileData/InstrProfTest.cpp +++ b/unittests/ProfileData/InstrProfTest.cpp @@ -14,20 +14,15 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/Support/Compression.h" +#include "llvm/Testing/Support/Error.h" +#include "llvm/Testing/Support/SupportHelpers.h" #include "gtest/gtest.h" #include <cstdarg> using namespace llvm; -static ::testing::AssertionResult NoError(Error E) { - if (!E) - return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) - << "\n"; -} - -static ::testing::AssertionResult ErrorEquals(instrprof_error Expected, - Error E) { +LLVM_NODISCARD static ::testing::AssertionResult +ErrorEquals(instrprof_error Expected, Error E) { instrprof_error Found; std::string FoundMsg; handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { @@ -49,7 +44,7 @@ struct InstrProfTest : ::testing::Test { void readProfile(std::unique_ptr<MemoryBuffer> Profile) { auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.takeError())); + EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded()); Reader = std::move(ReaderOrErr.get()); } }; @@ -69,9 +64,13 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) { ASSERT_TRUE(Reader->begin() == Reader->end()); } +static const auto Err = [](Error E) { + consumeError(std::move(E)); + FAIL(); +}; + TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) { - InstrProfRecord Record("foo", 0x1234, {1, 2, 3, 4}); - NoError(Writer.addRecord(std::move(Record))); + Writer.addRecord({"foo", 0x1234, {1, 2, 3, 4}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -88,21 +87,19 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) { } TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) { - InstrProfRecord Record1("foo", 0x1234, {1, 2}); - InstrProfRecord Record2("foo", 0x1235, {3, 4}); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); + Writer.addRecord({"foo", 0x1234, {1, 2}}, Err); + Writer.addRecord({"foo", 0x1235, {3, 4}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(1U, R->Counts[0]); ASSERT_EQ(2U, R->Counts[1]); R = Reader->getInstrProfRecord("foo", 0x1235); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(3U, R->Counts[0]); ASSERT_EQ(4U, R->Counts[1]); @@ -115,20 +112,20 @@ TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) { } TEST_P(MaybeSparseInstrProfTest, get_function_counts) { - InstrProfRecord Record1("foo", 0x1234, {1, 2}); - InstrProfRecord Record2("foo", 0x1235, {3, 4}); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); + Writer.addRecord({"foo", 0x1234, {1, 2}}, Err); + Writer.addRecord({"foo", 0x1235, {3, 4}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); std::vector<uint64_t> Counts; - ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1234, Counts))); + EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1234, Counts), + Succeeded()); ASSERT_EQ(2U, Counts.size()); ASSERT_EQ(1U, Counts[0]); ASSERT_EQ(2U, Counts[1]); - ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1235, Counts))); + EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1235, Counts), + Succeeded()); ASSERT_EQ(2U, Counts.size()); ASSERT_EQ(3U, Counts[0]); ASSERT_EQ(4U, Counts[1]); @@ -142,17 +139,15 @@ TEST_P(MaybeSparseInstrProfTest, get_function_counts) { // Profile data is copied from general.proftext TEST_F(InstrProfTest, get_profile_summary) { - InstrProfRecord Record1("func1", 0x1234, {97531}); - InstrProfRecord Record2("func2", 0x1234, {0, 0}); - InstrProfRecord Record3("func3", 0x1234, - {2305843009213693952, 1152921504606846976, - 576460752303423488, 288230376151711744, - 144115188075855872, 72057594037927936}); - InstrProfRecord Record4("func4", 0x1234, {0}); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); - NoError(Writer.addRecord(std::move(Record4))); + Writer.addRecord({"func1", 0x1234, {97531}}, Err); + Writer.addRecord({"func2", 0x1234, {0, 0}}, Err); + Writer.addRecord( + {"func3", + 0x1234, + {2305843009213693952, 1152921504606846976, 576460752303423488, + 288230376151711744, 144115188075855872, 72057594037927936}}, + Err); + Writer.addRecord({"func4", 0x1234, {0}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -203,25 +198,23 @@ TEST_F(InstrProfTest, get_profile_summary) { } TEST_F(InstrProfTest, test_writer_merge) { - InstrProfRecord Record1("func1", 0x1234, {42}); - NoError(Writer.addRecord(std::move(Record1))); + Writer.addRecord({"func1", 0x1234, {42}}, Err); InstrProfWriter Writer2; - InstrProfRecord Record2("func2", 0x1234, {0, 0}); - NoError(Writer2.addRecord(std::move(Record2))); + Writer2.addRecord({"func2", 0x1234, {0, 0}}, Err); - NoError(Writer.mergeRecordsFromWriter(std::move(Writer2))); + Writer.mergeRecordsFromWriter(std::move(Writer2), Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("func1", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(1U, R->Counts.size()); ASSERT_EQ(42U, R->Counts[0]); R = Reader->getInstrProfRecord("func2", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(0U, R->Counts[0]); ASSERT_EQ(0U, R->Counts[1]); @@ -235,10 +228,7 @@ static const char callee5[] = "callee5"; static const char callee6[] = "callee6"; TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { - InstrProfRecord Record1("caller", 0x1234, {1, 2}); - InstrProfRecord Record2("callee1", 0x1235, {3, 4}); - InstrProfRecord Record3("callee2", 0x1235, {3, 4}); - InstrProfRecord Record4("callee3", 0x1235, {3, 4}); + NamedInstrProfRecord Record1("caller", 0x1234, {1, 2}); // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); @@ -252,15 +242,15 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); - NoError(Writer.addRecord(std::move(Record4))); + Writer.addRecord(std::move(Record1), Err); + Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -282,16 +272,16 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { } TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { - InstrProfRecord Record("caller", 0x1234, {1, 2}); + NamedInstrProfRecord Record("caller", 0x1234, {1, 2}); Record.reserveSites(IPVK_IndirectCallTarget, 1); InstrProfValueData VD0[] = {{1000, 1}, {2000, 2}, {3000, 3}, {5000, 5}, {4000, 4}, {6000, 6}}; Record.addValueData(IPVK_IndirectCallTarget, 0, VD0, 6, nullptr); - NoError(Writer.addRecord(std::move(Record))); + Writer.addRecord(std::move(Record), Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); LLVMContext Ctx; std::unique_ptr<Module> M(new Module("MyModule", Ctx)); @@ -378,10 +368,7 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { } TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) { - InstrProfRecord Record1("caller", 0x1234, {1, 2}); - InstrProfRecord Record2("callee1", 0x1235, {3, 4}); - InstrProfRecord Record3("callee2", 0x1235, {3, 4}); - InstrProfRecord Record4("callee3", 0x1235, {3, 4}); + NamedInstrProfRecord Record1("caller", 0x1234, {1, 2}); // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); @@ -395,15 +382,15 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) { InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - NoError(Writer.addRecord(std::move(Record1), 10)); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); - NoError(Writer.addRecord(std::move(Record4))); + Writer.addRecord(std::move(Record1), 10, Err); + Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -424,10 +411,7 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) { } TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { - InstrProfRecord Record1("caller", 0x1234, {1, 2}); - InstrProfRecord Record2("callee1", 0x1235, {3, 4}); - InstrProfRecord Record3("callee2", 0x1235, {3, 4}); - InstrProfRecord Record4("callee3", 0x1235, {3, 4}); + NamedInstrProfRecord Record1("caller", 0x1234, {1, 2}); // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); @@ -441,10 +425,10 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); - NoError(Writer.addRecord(std::move(Record4))); + Writer.addRecord(std::move(Record1), Err); + Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err); + Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err); // Set big endian output. Writer.setValueProfDataEndianness(support::big); @@ -456,7 +440,7 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { Reader->setValueProfDataEndianness(support::big); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -475,13 +459,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { static const char caller[] = "caller"; - InstrProfRecord Record11(caller, 0x1234, {1, 2}); - InstrProfRecord Record12(caller, 0x1234, {1, 2}); - InstrProfRecord Record2(callee1, 0x1235, {3, 4}); - InstrProfRecord Record3(callee2, 0x1235, {3, 4}); - InstrProfRecord Record4(callee3, 0x1235, {3, 4}); - InstrProfRecord Record5(callee3, 0x1235, {3, 4}); - InstrProfRecord Record6(callee4, 0x1235, {3, 5}); + NamedInstrProfRecord Record11(caller, 0x1234, {1, 2}); + NamedInstrProfRecord Record12(caller, 0x1234, {1, 2}); // 5 value sites. Record11.reserveSites(IPVK_IndirectCallTarget, 5); @@ -525,20 +504,20 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { {uint64_t(callee3), 3}}; Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, 3, nullptr); - NoError(Writer.addRecord(std::move(Record11))); + Writer.addRecord(std::move(Record11), Err); // Merge profile data. - NoError(Writer.addRecord(std::move(Record12))); + Writer.addRecord(std::move(Record12), Err); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); - NoError(Writer.addRecord(std::move(Record4))); - NoError(Writer.addRecord(std::move(Record5))); - NoError(Writer.addRecord(std::move(Record6))); + Writer.addRecord({callee1, 0x1235, {3, 4}}, Err); + Writer.addRecord({callee2, 0x1235, {3, 4}}, Err); + Writer.addRecord({callee3, 0x1235, {3, 4}}, Err); + Writer.addRecord({callee3, 0x1235, {3, 4}}, Err); + Writer.addRecord({callee4, 0x1235, {3, 5}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); ASSERT_EQ(5U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(4U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -588,38 +567,37 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { const uint64_t Max = std::numeric_limits<uint64_t>::max(); - InstrProfRecord Record1("foo", 0x1234, {1}); - auto Result1 = Writer.addRecord(std::move(Record1)); - ASSERT_EQ(InstrProfError::take(std::move(Result1)), - instrprof_error::success); + instrprof_error Result; + auto Err = [&](Error E) { Result = InstrProfError::take(std::move(E)); }; + Result = instrprof_error::success; + Writer.addRecord({"foo", 0x1234, {1}}, Err); + ASSERT_EQ(Result, instrprof_error::success); // Verify counter overflow. - InstrProfRecord Record2("foo", 0x1234, {Max}); - auto Result2 = Writer.addRecord(std::move(Record2)); - ASSERT_EQ(InstrProfError::take(std::move(Result2)), - instrprof_error::counter_overflow); + Result = instrprof_error::success; + Writer.addRecord({"foo", 0x1234, {Max}}, Err); + ASSERT_EQ(Result, instrprof_error::counter_overflow); - InstrProfRecord Record3(bar, 0x9012, {8}); - auto Result3 = Writer.addRecord(std::move(Record3)); - ASSERT_EQ(InstrProfError::take(std::move(Result3)), - instrprof_error::success); + Result = instrprof_error::success; + Writer.addRecord({bar, 0x9012, {8}}, Err); + ASSERT_EQ(Result, instrprof_error::success); - InstrProfRecord Record4("baz", 0x5678, {3, 4}); + NamedInstrProfRecord Record4("baz", 0x5678, {3, 4}); Record4.reserveSites(IPVK_IndirectCallTarget, 1); InstrProfValueData VD4[] = {{uint64_t(bar), 1}}; Record4.addValueData(IPVK_IndirectCallTarget, 0, VD4, 1, nullptr); - auto Result4 = Writer.addRecord(std::move(Record4)); - ASSERT_EQ(InstrProfError::take(std::move(Result4)), - instrprof_error::success); + Result = instrprof_error::success; + Writer.addRecord(std::move(Record4), Err); + ASSERT_EQ(Result, instrprof_error::success); // Verify value data counter overflow. - InstrProfRecord Record5("baz", 0x5678, {5, 6}); + NamedInstrProfRecord Record5("baz", 0x5678, {5, 6}); Record5.reserveSites(IPVK_IndirectCallTarget, 1); InstrProfValueData VD5[] = {{uint64_t(bar), Max}}; Record5.addValueData(IPVK_IndirectCallTarget, 0, VD5, 1, nullptr); - auto Result5 = Writer.addRecord(std::move(Record5)); - ASSERT_EQ(InstrProfError::take(std::move(Result5)), - instrprof_error::counter_overflow); + Result = instrprof_error::success; + Writer.addRecord(std::move(Record5), Err); + ASSERT_EQ(Result, instrprof_error::counter_overflow); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -627,7 +605,7 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { // Verify saturation of counts. Expected<InstrProfRecord> ReadRecord1 = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(ReadRecord1.takeError())); + EXPECT_THAT_ERROR(ReadRecord1.takeError(), Succeeded()); ASSERT_EQ(Max, ReadRecord1->Counts[0]); Expected<InstrProfRecord> ReadRecord2 = @@ -646,8 +624,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) { static const char caller[] = "caller"; - InstrProfRecord Record11(caller, 0x1234, {1, 2}); - InstrProfRecord Record12(caller, 0x1234, {1, 2}); + NamedInstrProfRecord Record11(caller, 0x1234, {1, 2}); + NamedInstrProfRecord Record12(caller, 0x1234, {1, 2}); // 2 value sites. Record11.reserveSites(IPVK_IndirectCallTarget, 2); @@ -670,15 +648,15 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) { Record12.addValueData(IPVK_IndirectCallTarget, 0, VD1, 255, nullptr); Record12.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr); - NoError(Writer.addRecord(std::move(Record11))); + Writer.addRecord(std::move(Record11), Err); // Merge profile data. - NoError(Writer.addRecord(std::move(Record12))); + Writer.addRecord(std::move(Record12), Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.takeError())); + EXPECT_THAT_ERROR(R.takeError(), Succeeded()); std::unique_ptr<InstrProfValueData[]> VD( R->getValueForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(2U, R->getNumValueSites(IPVK_IndirectCallTarget)); @@ -713,12 +691,12 @@ static void addValueProfData(InstrProfRecord &Record) { } TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write) { - InstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); + InstrProfRecord SrcRecord({1ULL << 31, 2}); addValueProfData(SrcRecord); std::unique_ptr<ValueProfData> VPData = ValueProfData::serializeFrom(SrcRecord); - InstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); + InstrProfRecord Record({1ULL << 31, 2}); VPData->deserializeTo(Record, nullptr); // Now read data from Record and sanity check the data @@ -779,12 +757,12 @@ TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write) { TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write_mapping) { - InstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); + NamedInstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); addValueProfData(SrcRecord); std::unique_ptr<ValueProfData> VPData = ValueProfData::serializeFrom(SrcRecord); - InstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); + NamedInstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); InstrProfSymtab Symtab; Symtab.mapAddress(uint64_t(callee1), 0x1000ULL); Symtab.mapAddress(uint64_t(callee2), 0x2000ULL); @@ -817,12 +795,9 @@ TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write_mapping) { } TEST_P(MaybeSparseInstrProfTest, get_max_function_count) { - InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2}); - InstrProfRecord Record2("bar", 0, {1ULL << 63}); - InstrProfRecord Record3("baz", 0x5678, {0, 0, 0, 0}); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); + Writer.addRecord({"foo", 0x1234, {1ULL << 31, 2}}, Err); + Writer.addRecord({"bar", 0, {1ULL << 63}}, Err); + Writer.addRecord({"baz", 0x5678, {0, 0, 0, 0}}, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -830,20 +805,20 @@ TEST_P(MaybeSparseInstrProfTest, get_max_function_count) { } TEST_P(MaybeSparseInstrProfTest, get_weighted_function_counts) { - InstrProfRecord Record1("foo", 0x1234, {1, 2}); - InstrProfRecord Record2("foo", 0x1235, {3, 4}); - NoError(Writer.addRecord(std::move(Record1), 3)); - NoError(Writer.addRecord(std::move(Record2), 5)); + Writer.addRecord({"foo", 0x1234, {1, 2}}, 3, Err); + Writer.addRecord({"foo", 0x1235, {3, 4}}, 5, Err); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); std::vector<uint64_t> Counts; - ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1234, Counts))); + EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1234, Counts), + Succeeded()); ASSERT_EQ(2U, Counts.size()); ASSERT_EQ(3U, Counts[0]); ASSERT_EQ(6U, Counts[1]); - ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1235, Counts))); + EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1235, Counts), + Succeeded()); ASSERT_EQ(2U, Counts.size()); ASSERT_EQ(15U, Counts[0]); ASSERT_EQ(20U, Counts[1]); @@ -859,7 +834,7 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_test) { FuncNames.push_back("bar2"); FuncNames.push_back("bar3"); InstrProfSymtab Symtab; - NoError(Symtab.create(FuncNames)); + EXPECT_THAT_ERROR(Symtab.create(FuncNames), Succeeded()); StringRef R = Symtab.getFuncName(IndexedInstrProf::ComputeHash("func1")); ASSERT_EQ(StringRef("func1"), R); R = Symtab.getFuncName(IndexedInstrProf::ComputeHash("func2")); @@ -880,9 +855,9 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_test) { ASSERT_EQ(StringRef(), R); // Now incrementally update the symtab - NoError(Symtab.addFuncName("blah_1")); - NoError(Symtab.addFuncName("blah_2")); - NoError(Symtab.addFuncName("blah_3")); + EXPECT_THAT_ERROR(Symtab.addFuncName("blah_1"), Succeeded()); + EXPECT_THAT_ERROR(Symtab.addFuncName("blah_2"), Succeeded()); + EXPECT_THAT_ERROR(Symtab.addFuncName("blah_3"), Succeeded()); // Finalize it Symtab.finalizeSymtab(); @@ -910,7 +885,7 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_test) { // Test that we get an error when creating a bogus symtab. TEST_P(MaybeSparseInstrProfTest, instr_prof_bogus_symtab_empty_func_name) { InstrProfSymtab Symtab; - ErrorEquals(instrprof_error::malformed, Symtab.addFuncName("")); + EXPECT_TRUE(ErrorEquals(instrprof_error::malformed, Symtab.addFuncName(""))); } // Testing symtab creator interface used by value profile transformer. @@ -933,7 +908,7 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_module_test) { Function::Create(FTy, Function::WeakODRLinkage, "Wbar", M.get()); InstrProfSymtab ProfSymtab; - NoError(ProfSymtab.create(*M)); + EXPECT_THAT_ERROR(ProfSymtab.create(*M), Succeeded()); StringRef Funcs[] = {"Gfoo", "Gblah", "Gbar", "Ifoo", "Iblah", "Ibar", "Pfoo", "Pblah", "Pbar", "Wfoo", "Wblah", "Wbar"}; @@ -973,13 +948,17 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) { for (bool DoCompression : {false, true}) { // Compressing: std::string FuncNameStrings1; - NoError(collectPGOFuncNameStrings( - FuncNames1, (DoCompression && zlib::isAvailable()), FuncNameStrings1)); + EXPECT_THAT_ERROR(collectPGOFuncNameStrings( + FuncNames1, (DoCompression && zlib::isAvailable()), + FuncNameStrings1), + Succeeded()); // Compressing: std::string FuncNameStrings2; - NoError(collectPGOFuncNameStrings( - FuncNames2, (DoCompression && zlib::isAvailable()), FuncNameStrings2)); + EXPECT_THAT_ERROR(collectPGOFuncNameStrings( + FuncNames2, (DoCompression && zlib::isAvailable()), + FuncNameStrings2), + Succeeded()); for (int Padding = 0; Padding < 2; Padding++) { // Join with paddings : @@ -991,7 +970,7 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) { // Now decompress: InstrProfSymtab Symtab; - NoError(Symtab.create(StringRef(FuncNameStrings))); + EXPECT_THAT_ERROR(Symtab.create(StringRef(FuncNameStrings)), Succeeded()); // Now do the checks: // First sampling some data points: @@ -1015,13 +994,10 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) { } TEST_F(SparseInstrProfTest, preserve_no_records) { - InstrProfRecord Record1("foo", 0x1234, {0}); - InstrProfRecord Record2("bar", 0x4321, {0, 0}); - InstrProfRecord Record3("bar", 0x4321, {0, 0, 0}); + Writer.addRecord({"foo", 0x1234, {0}}, Err); + Writer.addRecord({"bar", 0x4321, {0, 0}}, Err); + Writer.addRecord({"baz", 0x4321, {0, 0, 0}}, Err); - NoError(Writer.addRecord(std::move(Record1))); - NoError(Writer.addRecord(std::move(Record2))); - NoError(Writer.addRecord(std::move(Record3))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); diff --git a/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp b/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp index c54e1b7eed24d..370e1c5ed5e89 100644 --- a/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp +++ b/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp @@ -77,6 +77,7 @@ TEST(DynamicLibrary, Overload) { EXPECT_TRUE(DL.isValid()); EXPECT_TRUE(Err.empty()); + // Test overloading local symbols does not occur by default GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); EXPECT_TRUE(GS != nullptr && GS == &TestA); EXPECT_EQ(StdString(GS()), "ProcessCall"); @@ -85,6 +86,12 @@ TEST(DynamicLibrary, Overload) { EXPECT_TRUE(GS != nullptr && GS == &TestA); EXPECT_EQ(StdString(GS()), "ProcessCall"); + // Test overloading by forcing library priority when searching for a symbol + DynamicLibrary::SearchOrder = DynamicLibrary::SO_LoadedFirst; + GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS != &TestA); + EXPECT_EQ(StdString(GS()), "LibCall"); + DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA)); GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA); @@ -95,6 +102,9 @@ TEST(DynamicLibrary, Overload) { } EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol( "TestA")) == nullptr); + + // Check serach ordering is reset to default after call to llvm_shutdown + EXPECT_TRUE(DynamicLibrary::SearchOrder == DynamicLibrary::SO_Linker); } TEST(DynamicLibrary, Shutdown) { diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp index 299fc50b46979..a762cf023f9cc 100644 --- a/unittests/Support/ErrorTest.cpp +++ b/unittests/Support/ErrorTest.cpp @@ -360,7 +360,7 @@ TEST(Error, CheckJoinErrors) { [&](const CustomError &CE) { Sum += CE.getInfo(); }); - EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate erorr lists."; + EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate error lists."; } } diff --git a/unittests/Support/Host.cpp b/unittests/Support/Host.cpp index fd53697793c7e..4f895e7163c59 100644 --- a/unittests/Support/Host.cpp +++ b/unittests/Support/Host.cpp @@ -10,9 +10,23 @@ #include "llvm/Support/Host.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "gtest/gtest.h" +#define ASSERT_NO_ERROR(x) \ + if (std::error_code ASSERT_NO_ERROR_ec = x) { \ + SmallString<128> MessageStorage; \ + raw_svector_ostream Message(MessageStorage); \ + Message << #x ": did not return errc::success.\n" \ + << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ + << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ + GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ + } else { \ + } + using namespace llvm; class HostTest : public testing::Test { @@ -114,3 +128,50 @@ Hardware : Qualcomm Technologies, Inc MSM8992 EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo), "cortex-a53"); } + +#if defined(__APPLE__) +TEST_F(HostTest, getMacOSHostVersion) { + using namespace llvm::sys; + llvm::Triple HostTriple(getProcessTriple()); + if (!HostTriple.isMacOSX()) + return; + + SmallString<128> TestDirectory; + ASSERT_NO_ERROR(fs::createUniqueDirectory("host_test", TestDirectory)); + SmallString<128> OutputFile(TestDirectory); + path::append(OutputFile, "out"); + + const char *SwVersPath = "/usr/bin/sw_vers"; + const char *argv[] = {SwVersPath, "-productVersion", nullptr}; + StringRef OutputPath = OutputFile.str(); + const StringRef *Redirects[] = {/*STDIN=*/nullptr, /*STDOUT=*/&OutputPath, + /*STDERR=*/nullptr}; + int RetCode = ExecuteAndWait(SwVersPath, argv, /*env=*/nullptr, Redirects); + ASSERT_EQ(0, RetCode); + + int FD = 0; + ASSERT_NO_ERROR(fs::openFileForRead(OutputPath, FD)); + off_t Size = ::lseek(FD, 0, SEEK_END); + ASSERT_NE(-1, Size); + ::lseek(FD, 0, SEEK_SET); + std::unique_ptr<char[]> Buffer = llvm::make_unique<char[]>(Size); + ASSERT_EQ(::read(FD, Buffer.get(), Size), Size); + ::close(FD); + + // Ensure that the two versions match. + StringRef SystemVersion(Buffer.get(), Size); + unsigned SystemMajor, SystemMinor, SystemMicro; + ASSERT_EQ(llvm::Triple((Twine("x86_64-apple-macos") + SystemVersion)) + .getMacOSXVersion(SystemMajor, SystemMinor, SystemMicro), + true); + unsigned HostMajor, HostMinor, HostMicro; + ASSERT_EQ(HostTriple.getMacOSXVersion(HostMajor, HostMinor, HostMicro), true); + + // Don't compare the 'Micro' version, as it's always '0' for the 'Darwin' + // triples. + ASSERT_EQ(std::tie(SystemMajor, SystemMinor), std::tie(HostMajor, HostMinor)); + + ASSERT_NO_ERROR(fs::remove(OutputPath)); + ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); +} +#endif diff --git a/unittests/Support/MathExtrasTest.cpp b/unittests/Support/MathExtrasTest.cpp index e26653b8a6564..694a1f24d0320 100644 --- a/unittests/Support/MathExtrasTest.cpp +++ b/unittests/Support/MathExtrasTest.cpp @@ -177,6 +177,7 @@ TEST(MathExtras, reverseBits) { } TEST(MathExtras, isPowerOf2_32) { + EXPECT_FALSE(isPowerOf2_32(0)); EXPECT_TRUE(isPowerOf2_32(1 << 6)); EXPECT_TRUE(isPowerOf2_32(1 << 12)); EXPECT_FALSE(isPowerOf2_32((1 << 19) + 3)); @@ -184,6 +185,7 @@ TEST(MathExtras, isPowerOf2_32) { } TEST(MathExtras, isPowerOf2_64) { + EXPECT_FALSE(isPowerOf2_64(0)); EXPECT_TRUE(isPowerOf2_64(1LL << 46)); EXPECT_TRUE(isPowerOf2_64(1LL << 12)); EXPECT_FALSE(isPowerOf2_64((1LL << 53) + 3)); diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp index db3d10847cd87..72a91d1441748 100644 --- a/unittests/Transforms/Utils/Cloning.cpp +++ b/unittests/Transforms/Utils/Cloning.cpp @@ -312,11 +312,16 @@ protected: DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL, Entry); // Also create an inlined variable. + // Create a distinct struct type that we should not duplicate during + // cloning). + auto *StructType = DICompositeType::getDistinct( + C, dwarf::DW_TAG_structure_type, "some_struct", nullptr, 0, nullptr, + nullptr, 32, 32, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr); auto *InlinedSP = DBuilder.createFunction(CU, "inlined", "inlined", File, 8, FuncType, true, true, 9, DINode::FlagZero, false); auto *InlinedVar = - DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, IntType, true); + DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, StructType, true); auto *Scope = DBuilder.createLexicalBlock( DBuilder.createLexicalBlockFile(InlinedSP, File), File, 1, 1); auto InlinedDL = @@ -426,7 +431,11 @@ TEST_F(CloneFunc, DebugIntrinsics) { EXPECT_EQ(NewFunc, cast<AllocaInst>(NewIntrin->getAddress())-> getParent()->getParent()); - if (!OldIntrin->getDebugLoc()->getInlinedAt()) { + if (OldIntrin->getDebugLoc()->getInlinedAt()) { + // Inlined variable should refer to the same DILocalVariable as in the + // Old Function + EXPECT_EQ(OldIntrin->getVariable(), NewIntrin->getVariable()); + } else { // Old variable must belong to the old function. EXPECT_EQ(OldFunc->getSubprogram(), cast<DISubprogram>(OldIntrin->getVariable()->getScope())); |
