aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/Analysis/LazyCallGraphTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/Analysis/LazyCallGraphTest.cpp')
-rw-r--r--llvm/unittests/Analysis/LazyCallGraphTest.cpp682
1 files changed, 682 insertions, 0 deletions
diff --git a/llvm/unittests/Analysis/LazyCallGraphTest.cpp b/llvm/unittests/Analysis/LazyCallGraphTest.cpp
index c2c1cd2..b154c6f 100644
--- a/llvm/unittests/Analysis/LazyCallGraphTest.cpp
+++ b/llvm/unittests/Analysis/LazyCallGraphTest.cpp
@@ -13,6 +13,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
@@ -2170,4 +2171,685 @@ TEST(LazyCallGraphTest, RemoveFunctionWithSpurriousRef) {
EXPECT_EQ(&RC2, &*I++);
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
}
+
+TEST(LazyCallGraphTest, AddSplitFunction1) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -call-> g.
+ (void)CallInst::Create(G, {}, "", &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC1 = &*I++;
+ EXPECT_EQ(RC1, CG.lookupRefSCC(*GN));
+ LazyCallGraph::RefSCC *RC2 = &*I++;
+ EXPECT_EQ(RC2, ORC);
+ EXPECT_EQ(RC2, CG.lookupRefSCC(FN));
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction2) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC1 = &*I++;
+ EXPECT_EQ(RC1, CG.lookupRefSCC(*GN));
+ LazyCallGraph::RefSCC *RC2 = &*I++;
+ EXPECT_EQ(RC2, ORC);
+ EXPECT_EQ(RC2, CG.lookupRefSCC(FN));
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction3) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -ref-> f.
+ (void)CastInst::CreatePointerCast(&F, Type::getInt8PtrTy(Context), "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -call-> g.
+ (void)CallInst::Create(G, {}, "", &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[1]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction4) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -ref-> f.
+ (void)CastInst::CreatePointerCast(&F, Type::getInt8PtrTy(Context), "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ // Order doesn't matter for sibling SCCs.
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(&CG.lookupSCC(*GN)->getOuterRefSCC(), RC);
+ EXPECT_EQ(&CG.lookupSCC(FN)->getOuterRefSCC(), RC);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction5) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -call-> f.
+ (void)CallInst::Create(&F, {}, "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[1]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction6) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -call-> f.
+ (void)CallInst::Create(&F, {}, "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -call-> g.
+ (void)CallInst::Create(G, {}, "", &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(1, RC->size());
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[0]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction7) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " call void @f2()\n"
+ " ret void\n"
+ "}\n"
+ "define void @f2() {\n"
+ " call void @f()\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+ Function &F2 = lookupFunction(*M, "f2");
+ LazyCallGraph::Node &F2N = CG.get(F2);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -call-> f2.
+ (void)CallInst::Create(&F2, {}, "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -call-> g.
+ (void)CallInst::Create(G, {}, "", &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(1, RC->size());
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(F2N), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[0]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction8) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " call void @f2()\n"
+ " ret void\n"
+ "}\n"
+ "define void @f2() {\n"
+ " call void @f()\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+ Function &F2 = lookupFunction(*M, "f2");
+ LazyCallGraph::Node &F2N = CG.get(F2);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -call-> f2.
+ (void)CallInst::Create(&F2, {}, "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(F2N), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[1]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunction9) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " call void @f2()\n"
+ " ret void\n"
+ "}\n"
+ "define void @f2() {\n"
+ " call void @f()\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+ Function &F2 = lookupFunction(*M, "f2");
+ LazyCallGraph::Node &F2N = CG.get(F2);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -ref-> f2.
+ (void)CastInst::CreatePointerCast(&F2, Type::getInt8PtrTy(Context), "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -call-> g.
+ (void)CallInst::Create(G, {}, "", &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitFunction(F, *G);
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(CG.lookupSCC(*GN), &(*RC)[0]);
+ EXPECT_EQ(CG.lookupSCC(FN), &(*RC)[1]);
+ EXPECT_EQ(CG.lookupSCC(F2N), &(*RC)[1]);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunctions1) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G}));
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC1 = &*I++;
+ EXPECT_EQ(RC1, CG.lookupRefSCC(*GN));
+ LazyCallGraph::RefSCC *RC2 = &*I++;
+ EXPECT_EQ(RC2, ORC);
+ EXPECT_EQ(RC2, CG.lookupRefSCC(FN));
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunctions2) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g", F.getParent());
+ BasicBlock *GBB = BasicBlock::Create(Context, "", G);
+ // Create g -ref-> f.
+ (void)CastInst::CreatePointerCast(&F, Type::getInt8PtrTy(Context), "", GBB);
+ (void)ReturnInst::Create(Context, GBB);
+
+ // Create f -ref-> g.
+ (void)CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G}));
+
+ LazyCallGraph::Node *GN = CG.lookup(*G);
+ EXPECT_TRUE(GN);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, CG.lookupRefSCC(*GN));
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ // Order doesn't matter for sibling SCCs.
+ EXPECT_EQ(2, RC->size());
+ EXPECT_EQ(&CG.lookupSCC(*GN)->getOuterRefSCC(), RC);
+ EXPECT_EQ(&CG.lookupSCC(FN)->getOuterRefSCC(), RC);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunctions3) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g1", F.getParent());
+ auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g2", F.getParent());
+ BasicBlock *G1BB = BasicBlock::Create(Context, "", G1);
+ BasicBlock *G2BB = BasicBlock::Create(Context, "", G2);
+ // Create g1 -ref-> g2 and g2 -ref-> g1.
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "", G1BB);
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "", G2BB);
+ (void)ReturnInst::Create(Context, G1BB);
+ (void)ReturnInst::Create(Context, G2BB);
+
+ // Create f -ref-> g1 and f -ref-> g2.
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G1, G2}));
+
+ LazyCallGraph::Node *G1N = CG.lookup(*G1);
+ EXPECT_TRUE(G1N);
+ LazyCallGraph::Node *G2N = CG.lookup(*G2);
+ EXPECT_TRUE(G2N);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC1 = &*I++;
+ EXPECT_EQ(2, RC1->size());
+ EXPECT_EQ(RC1, CG.lookupRefSCC(*G1N));
+ EXPECT_EQ(RC1, CG.lookupRefSCC(*G2N));
+ LazyCallGraph::RefSCC *RC2 = &*I++;
+ EXPECT_EQ(RC2, ORC);
+ EXPECT_EQ(RC2, CG.lookupRefSCC(FN));
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
+
+TEST(LazyCallGraphTest, AddSplitFunctions4) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g1", F.getParent());
+ auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g2", F.getParent());
+ BasicBlock *G1BB = BasicBlock::Create(Context, "", G1);
+ BasicBlock *G2BB = BasicBlock::Create(Context, "", G2);
+ // Create g1 -ref-> g2 and g2 -ref-> g1.
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "", G1BB);
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "", G2BB);
+ // Create g2 -ref-> f.
+ (void)CastInst::CreatePointerCast(&F, Type::getInt8PtrTy(Context), "", G2BB);
+ (void)ReturnInst::Create(Context, G1BB);
+ (void)ReturnInst::Create(Context, G2BB);
+
+ // Create f -ref-> g1 and f -ref-> g2.
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G1, G2}));
+
+ LazyCallGraph::Node *G1N = CG.lookup(*G1);
+ EXPECT_TRUE(G1N);
+ LazyCallGraph::Node *G2N = CG.lookup(*G2);
+ EXPECT_TRUE(G2N);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ // Order doesn't matter for sibling SCCs.
+ EXPECT_EQ(3, RC->size());
+ EXPECT_EQ(&CG.lookupSCC(FN)->getOuterRefSCC(), RC);
+ EXPECT_EQ(&CG.lookupSCC(*G1N)->getOuterRefSCC(), RC);
+ EXPECT_EQ(&CG.lookupSCC(*G2N)->getOuterRefSCC(), RC);
+ EXPECT_EQ(RC, CG.lookupRefSCC(*G1N));
+ EXPECT_EQ(RC, CG.lookupRefSCC(*G2N));
+}
+
+TEST(LazyCallGraphTest, AddSplitFunctions5) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M =
+ parseAssembly(Context, "define void @f() {\n"
+ " %1 = bitcast void ()* @f2 to i8*\n"
+ " ret void\n"
+ "}\n"
+ "define void @f2() {\n"
+ " call void @f()\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG = buildCG(*M);
+
+ Function &F = lookupFunction(*M, "f");
+ LazyCallGraph::Node &FN = CG.get(F);
+ Function &F2 = lookupFunction(*M, "f2");
+ LazyCallGraph::Node &F2N = CG.get(F);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *ORC = &*I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g1", F.getParent());
+ auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(),
+ F.getAddressSpace(), "g2", F.getParent());
+ BasicBlock *G1BB = BasicBlock::Create(Context, "", G1);
+ BasicBlock *G2BB = BasicBlock::Create(Context, "", G2);
+ // Create g1 -ref-> g2 and g2 -ref-> g1.
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "", G1BB);
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "", G2BB);
+ // Create g2 -ref-> f2.
+ (void)CastInst::CreatePointerCast(&F2, Type::getInt8PtrTy(Context), "", G2BB);
+ (void)ReturnInst::Create(Context, G1BB);
+ (void)ReturnInst::Create(Context, G2BB);
+
+ // Create f -ref-> g1 and f -ref-> g2.
+ (void)CastInst::CreatePointerCast(G1, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+ (void)CastInst::CreatePointerCast(G2, Type::getInt8PtrTy(Context), "",
+ &*F.getEntryBlock().begin());
+
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+
+ CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G1, G2}));
+
+ LazyCallGraph::Node *G1N = CG.lookup(*G1);
+ EXPECT_TRUE(G1N);
+ LazyCallGraph::Node *G2N = CG.lookup(*G2);
+ EXPECT_TRUE(G2N);
+
+ I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC *RC = &*I++;
+ EXPECT_EQ(4, RC->size());
+ EXPECT_EQ(RC, ORC);
+ EXPECT_EQ(RC, CG.lookupRefSCC(*G1N));
+ EXPECT_EQ(RC, CG.lookupRefSCC(*G2N));
+ EXPECT_EQ(RC, CG.lookupRefSCC(FN));
+ EXPECT_EQ(RC, CG.lookupRefSCC(F2N));
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
}