summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/APFloatTest.cpp16
-rw-r--r--unittests/ADT/FunctionRefTest.cpp14
-rw-r--r--unittests/Analysis/AliasAnalysisTest.cpp5
-rw-r--r--unittests/Analysis/CGSCCPassManagerTest.cpp198
-rw-r--r--unittests/Analysis/LazyCallGraphTest.cpp33
-rw-r--r--unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp5
-rw-r--r--unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp8
-rw-r--r--unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp2
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp95
-rw-r--r--unittests/ExecutionEngine/Orc/OrcCAPITest.cpp32
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.h29
-rw-r--r--unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp60
-rw-r--r--unittests/IR/CMakeLists.txt2
-rw-r--r--unittests/IR/ModuleTest.cpp2
-rw-r--r--unittests/IR/PassBuilderCallbacksTest.cpp520
-rw-r--r--unittests/IR/PassManagerTest.cpp7
-rw-r--r--unittests/ProfileData/CMakeLists.txt2
-rw-r--r--unittests/ProfileData/CoverageMappingTest.cpp97
-rw-r--r--unittests/ProfileData/InstrProfTest.cpp268
-rw-r--r--unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp10
-rw-r--r--unittests/Support/ErrorTest.cpp2
-rw-r--r--unittests/Support/Host.cpp61
-rw-r--r--unittests/Support/MathExtrasTest.cpp2
-rw-r--r--unittests/Transforms/Utils/Cloning.cpp13
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()));