aboutsummaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/Analysis/CGSCCPassManagerTest.cpp2
-rw-r--r--unittests/Analysis/LazyCallGraphTest.cpp47
-rw-r--r--unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp3
-rw-r--r--unittests/DebugInfo/PDB/CMakeLists.txt3
-rw-r--r--unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp183
-rw-r--r--unittests/IR/CFGBuilder.cpp269
-rw-r--r--unittests/IR/CFGBuilder.h94
-rw-r--r--unittests/IR/CMakeLists.txt1
-rw-r--r--unittests/IR/DominatorTreeTest.cpp300
-rw-r--r--unittests/IR/IRBuilderTest.cpp11
-rw-r--r--unittests/IR/MetadataTest.cpp24
-rw-r--r--unittests/Support/TargetParserTest.cpp5
-rw-r--r--unittests/Support/YAMLIOTest.cpp16
-rw-r--r--unittests/Support/raw_ostream_test.cpp5
14 files changed, 729 insertions, 234 deletions
diff --git a/unittests/Analysis/CGSCCPassManagerTest.cpp b/unittests/Analysis/CGSCCPassManagerTest.cpp
index d46d9535fa4b..e24818265975 100644
--- a/unittests/Analysis/CGSCCPassManagerTest.cpp
+++ b/unittests/Analysis/CGSCCPassManagerTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LazyCallGraph.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
@@ -227,6 +228,7 @@ public:
"entry:\n"
" ret void\n"
"}\n")) {
+ MAM.registerPass([&] { return TargetLibraryAnalysis(); });
MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp
index 65730486cd75..9e7e128bcfb3 100644
--- a/unittests/Analysis/LazyCallGraphTest.cpp
+++ b/unittests/Analysis/LazyCallGraphTest.cpp
@@ -216,10 +216,17 @@ static const char DiamondOfTrianglesRefGraph[] =
" ret void\n"
"}\n";
+static LazyCallGraph buildCG(Module &M) {
+ TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
+ TargetLibraryInfo TLI(TLII);
+ LazyCallGraph CG(M, TLI);
+ return CG;
+}
+
TEST(LazyCallGraphTest, BasicGraphFormation) {
LLVMContext Context;
std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// The order of the entry nodes should be stable w.r.t. the source order of
// the IR, and everything in our module is an entry node, so just directly
@@ -407,7 +414,7 @@ TEST(LazyCallGraphTest, BasicGraphMutation) {
"entry:\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
LazyCallGraph::Node &A = CG.get(lookupFunction(*M, "a"));
LazyCallGraph::Node &B = CG.get(lookupFunction(*M, "b"));
@@ -445,7 +452,7 @@ TEST(LazyCallGraphTest, BasicGraphMutation) {
TEST(LazyCallGraphTest, InnerSCCFormation) {
LLVMContext Context;
std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Now mutate the graph to connect every node into a single RefSCC to ensure
// that our inner SCC formation handles the rest.
@@ -542,7 +549,7 @@ TEST(LazyCallGraphTest, MultiArmSCC) {
" call void @f1()\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -593,7 +600,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
"entry:\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -739,7 +746,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
// a3--a2 |
//
std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -831,7 +838,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
// references rather than calls.
std::unique_ptr<Module> M =
parseAssembly(Context, DiamondOfTrianglesRefGraph);
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -938,7 +945,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeCallCycle) {
"entry:\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1015,7 +1022,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeRefCycle) {
"entry:\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1077,7 +1084,7 @@ TEST(LazyCallGraphTest, InlineAndDeleteFunction) {
// a3--a2 |
//
std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1221,7 +1228,7 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) {
" call void @a()\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1315,7 +1322,7 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) {
" store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1390,7 +1397,7 @@ TEST(LazyCallGraphTest, InternalNoOpEdgeRemoval) {
" store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1467,7 +1474,7 @@ TEST(LazyCallGraphTest, InternalCallEdgeToRef) {
" call void @c()\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1560,7 +1567,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) {
" store void()* @a, void()** undef\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1672,7 +1679,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) {
" store void()* @a, void()** undef\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1802,7 +1809,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) {
" store void()* @a, void()** undef\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -1885,7 +1892,7 @@ TEST(LazyCallGraphTest, HandleBlockAddress) {
" store i8* blockaddress(@f, %bb), i8** %ptr\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
@@ -1933,7 +1940,7 @@ TEST(LazyCallGraphTest, ReplaceNodeFunction) {
" store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Force the graph to be fully expanded.
CG.buildRefSCCs();
@@ -2011,7 +2018,7 @@ TEST(LazyCallGraphTest, RemoveFunctionWithSpurriousRef) {
"entry:\n"
" ret void\n"
"}\n");
- LazyCallGraph CG(*M);
+ LazyCallGraph CG = buildCG(*M);
// Insert spurious ref edges.
LazyCallGraph::Node &AN = CG.get(lookupFunction(*M, "a"));
diff --git a/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp b/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
index 92134513b75b..04b7bb0ba936 100644
--- a/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
+++ b/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
@@ -13,7 +13,6 @@
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
-#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
@@ -402,4 +401,4 @@ TEST_F(RandomAccessVisitorTest, CrossChunkName) {
StringRef Name = Types.getTypeName(IndexOne);
EXPECT_EQ("const FooClass", Name);
-} \ No newline at end of file
+}
diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt
index 989cb396f674..583b065f464c 100644
--- a/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -10,11 +10,10 @@ set(DebugInfoPDBSources
StringTableBuilderTest.cpp
MSFBuilderTest.cpp
PDBApiTest.cpp
- TypeServerHandlerTest.cpp
)
add_llvm_unittest(DebugInfoPDBTests
${DebugInfoPDBSources}
)
-target_link_libraries(DebugInfoPDBTests LLVMTestingSupport) \ No newline at end of file
+target_link_libraries(DebugInfoPDBTests LLVMTestingSupport)
diff --git a/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp b/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
deleted file mode 100644
index d09b9130ee27..000000000000
--- a/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-//===- llvm/unittest/DebugInfo/PDB/TypeServerHandlerTest.cpp --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "gtest/gtest.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::pdb;
-
-namespace {
-
-constexpr uint8_t Guid[] = {0x2a, 0x2c, 0x1c, 0x2a, 0xcb, 0x9e, 0x48, 0x18,
- 0x82, 0x82, 0x7a, 0x87, 0xc3, 0xfe, 0x16, 0xe8};
-StringRef GuidStr(reinterpret_cast<const char *>(Guid),
- llvm::array_lengthof(Guid));
-
-constexpr const char *Name = "Test Name";
-constexpr int Age = 1;
-
-class MockTypeServerHandler : public TypeServerHandler {
-public:
- explicit MockTypeServerHandler(bool HandleAlways)
- : HandleAlways(HandleAlways) {}
-
- Expected<bool> handle(TypeServer2Record &TS,
- TypeVisitorCallbacks &Callbacks) override {
- if (TS.Age != Age || TS.Guid != GuidStr || TS.Name != Name)
- return make_error<CodeViewError>(cv_error_code::corrupt_record,
- "Invalid TypeServer record!");
-
- if (Handled && !HandleAlways)
- return false;
-
- Handled = true;
- return true;
- }
-
- bool Handled = false;
- bool HandleAlways;
-};
-
-class MockTypeVisitorCallbacks : public TypeVisitorCallbacks {
-public:
- enum class State {
- Ready,
- VisitTypeBegin,
- VisitKnownRecord,
- VisitTypeEnd,
- };
- Error visitTypeBegin(CVType &CVT) override {
- if (S != State::Ready)
- return make_error<CodeViewError>(cv_error_code::unspecified,
- "Invalid visitor state!");
-
- S = State::VisitTypeBegin;
- return Error::success();
- }
-
- Error visitKnownRecord(CVType &CVT, TypeServer2Record &TS) override {
- if (S != State::VisitTypeBegin)
- return make_error<CodeViewError>(cv_error_code::unspecified,
- "Invalid visitor state!");
-
- S = State::VisitKnownRecord;
- return Error::success();
- }
-
- Error visitTypeEnd(CVType &CVT) override {
- if (S != State::VisitKnownRecord)
- return make_error<CodeViewError>(cv_error_code::unspecified,
- "Invalid visitor state!");
-
- S = State::VisitTypeEnd;
- return Error::success();
- }
-
- State S = State::Ready;
-};
-
-class TypeServerHandlerTest : public testing::Test {
-public:
- void SetUp() override {
- TypeServer2Record R(TypeRecordKind::TypeServer2);
- R.Age = Age;
- R.Guid = GuidStr;
- R.Name = Name;
-
- TypeTableBuilder Builder(Allocator);
- Builder.writeKnownType(R);
- TypeServerRecord.RecordData = Builder.records().front();
- TypeServerRecord.Type = TypeLeafKind::LF_TYPESERVER2;
- }
-
-protected:
- BumpPtrAllocator Allocator;
- CVType TypeServerRecord;
-};
-
-// Test that when no type server handler is registered, it gets handled by the
-// normal
-// visitor callbacks.
-TEST_F(TypeServerHandlerTest, VisitRecordNoTypeServer) {
- MockTypeVisitorCallbacks C2;
- MockTypeVisitorCallbacks C1;
- TypeVisitorCallbackPipeline Pipeline;
-
- Pipeline.addCallbackToPipeline(C1);
- Pipeline.addCallbackToPipeline(C2);
-
- EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, Pipeline),
- Succeeded());
-
- EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
- EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C2.S);
-}
-
-// Test that when a TypeServerHandler is registered, it gets consumed by the
-// handler if and only if the handler returns true.
-TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerOnce) {
- MockTypeServerHandler Handler(false);
-
- MockTypeVisitorCallbacks C1;
-
- // Our mock server returns true the first time.
- EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
- codeview::VDS_BytesExternal,
- &Handler),
- Succeeded());
- EXPECT_TRUE(Handler.Handled);
- EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
-
- // And false the second time.
- EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
- codeview::VDS_BytesExternal,
- &Handler),
- Succeeded());
- EXPECT_TRUE(Handler.Handled);
- EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
-}
-
-// Test that when a type server handler is registered, if the handler keeps
-// returning true, it will keep getting consumed by the handler and not go
-// to the default processor.
-TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerAlways) {
- MockTypeServerHandler Handler(true);
-
- MockTypeVisitorCallbacks C1;
-
- EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
- codeview::VDS_BytesExternal,
- &Handler),
- Succeeded());
- EXPECT_TRUE(Handler.Handled);
- EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
-
- EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
- codeview::VDS_BytesExternal,
- &Handler),
- Succeeded());
- EXPECT_TRUE(Handler.Handled);
- EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
-}
-
-} // end anonymous namespace
diff --git a/unittests/IR/CFGBuilder.cpp b/unittests/IR/CFGBuilder.cpp
new file mode 100644
index 000000000000..50494ab5c7ca
--- /dev/null
+++ b/unittests/IR/CFGBuilder.cpp
@@ -0,0 +1,269 @@
+//===- llvm/Testing/Support/CFGBuilder.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFGBuilder.h"
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/TypeBuilder.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "cfg-builder"
+
+using namespace llvm;
+
+CFGHolder::CFGHolder(StringRef ModuleName, StringRef FunctionName)
+ : Context(llvm::make_unique<LLVMContext>()),
+ M(llvm::make_unique<Module>(ModuleName, *Context)) {
+ FunctionType *FTy = TypeBuilder<void(), false>::get(*Context);
+ F = cast<Function>(M->getOrInsertFunction(FunctionName, FTy));
+}
+CFGHolder::~CFGHolder() = default;
+
+CFGBuilder::CFGBuilder(Function *F, const std::vector<Arc> &InitialArcs,
+ std::vector<Update> Updates)
+ : F(F), Updates(std::move(Updates)) {
+ assert(F);
+ buildCFG(InitialArcs);
+}
+
+static void ConnectBlocks(BasicBlock *From, BasicBlock *To) {
+ DEBUG(dbgs() << "Creating BB arc " << From->getName() << " -> "
+ << To->getName() << "\n";
+ dbgs().flush());
+ auto *IntTy = IntegerType::get(From->getContext(), 32);
+
+ if (isa<UnreachableInst>(From->getTerminator()))
+ From->getTerminator()->eraseFromParent();
+ if (!From->getTerminator()) {
+ IRBuilder<> IRB(From);
+ IRB.CreateSwitch(ConstantInt::get(IntTy, 0), To);
+ return;
+ }
+
+ SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
+ const auto Last = SI->getNumCases();
+
+ auto *IntVal = ConstantInt::get(IntTy, Last);
+ SI->addCase(IntVal, To);
+}
+
+static void DisconnectBlocks(BasicBlock *From, BasicBlock *To) {
+ DEBUG(dbgs() << "Deleting BB arc " << From->getName() << " -> "
+ << To->getName() << "\n";
+ dbgs().flush());
+ SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
+
+ if (SI->getNumCases() == 0) {
+ SI->eraseFromParent();
+ IRBuilder<> IRB(From);
+ IRB.CreateUnreachable();
+ return;
+ }
+
+ if (SI->getDefaultDest() == To) {
+ auto FirstC = SI->case_begin();
+ SI->setDefaultDest(FirstC->getCaseSuccessor());
+ SI->removeCase(FirstC);
+ return;
+ }
+
+ for (auto CIt = SI->case_begin(); CIt != SI->case_end(); ++CIt)
+ if (CIt->getCaseSuccessor() == To) {
+ SI->removeCase(CIt);
+ return;
+ }
+}
+
+BasicBlock *CFGBuilder::getOrAddBlock(StringRef BlockName) {
+ auto BIt = NameToBlock.find(BlockName);
+ if (BIt != NameToBlock.end())
+ return BIt->second;
+
+ auto *BB = BasicBlock::Create(F->getParent()->getContext(), BlockName, F);
+ IRBuilder<> IRB(BB);
+ IRB.CreateUnreachable();
+ NameToBlock[BlockName] = BB;
+ return BB;
+}
+
+bool CFGBuilder::connect(const Arc &A) {
+ BasicBlock *From = getOrAddBlock(A.From);
+ BasicBlock *To = getOrAddBlock(A.To);
+ if (Arcs.count(A) != 0)
+ return false;
+
+ Arcs.insert(A);
+ ConnectBlocks(From, To);
+ return true;
+}
+
+bool CFGBuilder::disconnect(const Arc &A) {
+ assert(NameToBlock.count(A.From) != 0 && "No block to disconnect (From)");
+ assert(NameToBlock.count(A.To) != 0 && "No block to disconnect (To)");
+ if (Arcs.count(A) == 0)
+ return false;
+
+ BasicBlock *From = getOrAddBlock(A.From);
+ BasicBlock *To = getOrAddBlock(A.To);
+ Arcs.erase(A);
+ DisconnectBlocks(From, To);
+ return true;
+}
+
+void CFGBuilder::buildCFG(const std::vector<Arc> &NewArcs) {
+ for (const auto &A : NewArcs) {
+ const bool Connected = connect(A);
+ (void)Connected;
+ assert(Connected);
+ }
+}
+
+Optional<CFGBuilder::Update> CFGBuilder::getNextUpdate() const {
+ if (UpdateIdx == Updates.size())
+ return None;
+ return Updates[UpdateIdx];
+}
+
+Optional<CFGBuilder::Update> CFGBuilder::applyUpdate() {
+ if (UpdateIdx == Updates.size())
+ return None;
+ Update NextUpdate = Updates[UpdateIdx++];
+ if (NextUpdate.Action == ActionKind::Insert)
+ connect(NextUpdate.Edge);
+ else
+ disconnect(NextUpdate.Edge);
+
+ return NextUpdate;
+}
+
+void CFGBuilder::dump(raw_ostream &OS) const {
+ OS << "Arcs:\n";
+ size_t i = 0;
+ for (const auto &A : Arcs)
+ OS << " " << i++ << ":\t" << A.From << " -> " << A.To << "\n";
+
+ OS << "Updates:\n";
+ i = 0;
+ for (const auto &U : Updates) {
+ OS << (i + 1 == UpdateIdx ? "->" : " ") << i
+ << ((U.Action == ActionKind::Insert) ? "\tIns " : "\tDel ")
+ << U.Edge.From << " -> " << U.Edge.To << "\n";
+ ++i;
+ }
+}
+
+//---- CFGBuilder tests ---------------------------------------------------===//
+
+TEST(CFGBuilder, Construction) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {{"entry", "a"}, {"a", "b"}, {"a", "c"},
+ {"c", "d"}, {"d", "b"}, {"d", "e"},
+ {"d", "f"}, {"e", "f"}};
+ CFGBuilder B(Holder.F, Arcs, {});
+
+ EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
+ EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
+
+ auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
+ // d has 3 successors, but one of them if going to be a default case
+ EXPECT_EQ(DSwitch->getNumCases(), 2U);
+ EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
+}
+
+TEST(CFGBuilder, Insertions) {
+ CFGHolder Holder;
+ const auto Insert = CFGBuilder::ActionKind::Insert;
+ std::vector<CFGBuilder::Update> Updates = {
+ {Insert, {"entry", "a"}}, {Insert, {"a", "b"}}, {Insert, {"a", "c"}},
+ {Insert, {"c", "d"}}, {Insert, {"d", "b"}}, {Insert, {"d", "e"}},
+ {Insert, {"d", "f"}}, {Insert, {"e", "f"}}};
+ const size_t NumUpdates = Updates.size();
+
+ CFGBuilder B(Holder.F, {}, Updates);
+
+ size_t i = 0;
+ while (B.applyUpdate())
+ ++i;
+ EXPECT_EQ(i, NumUpdates);
+
+ EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
+ EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
+
+ auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
+ // d has 3 successors, but one of them if going to be a default case
+ EXPECT_EQ(DSwitch->getNumCases(), 2U);
+ EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
+}
+
+TEST(CFGBuilder, Deletions) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
+ const auto Delete = CFGBuilder::ActionKind::Delete;
+ std::vector<CFGBuilder::Update> Updates = {
+ {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
+ };
+ const size_t NumUpdates = Updates.size();
+
+ CFGBuilder B(Holder.F, Arcs, Updates);
+
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
+
+ auto UpdateC = B.applyUpdate();
+
+ EXPECT_TRUE(UpdateC);
+ EXPECT_EQ(UpdateC->Action, CFGBuilder::ActionKind::Delete);
+ EXPECT_EQ(UpdateC->Edge.From, "c");
+ EXPECT_EQ(UpdateC->Edge.To, "d");
+ EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("c")->getTerminator()));
+
+ size_t i = 1;
+ while (B.applyUpdate())
+ ++i;
+ EXPECT_EQ(i, NumUpdates);
+
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
+ EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("entry")->getTerminator()));
+}
+
+TEST(CFGBuilder, Rebuild) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
+ const auto Insert = CFGBuilder::ActionKind::Insert;
+ const auto Delete = CFGBuilder::ActionKind::Delete;
+ std::vector<CFGBuilder::Update> Updates = {
+ {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
+ {Insert, {"c", "d"}}, {Insert, {"a", "c"}}, {Insert, {"entry", "a"}},
+ };
+ const size_t NumUpdates = Updates.size();
+
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ size_t i = 0;
+ while (B.applyUpdate())
+ ++i;
+ EXPECT_EQ(i, NumUpdates);
+
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
+ EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
+}
diff --git a/unittests/IR/CFGBuilder.h b/unittests/IR/CFGBuilder.h
new file mode 100644
index 000000000000..d9d9c378e110
--- /dev/null
+++ b/unittests/IR/CFGBuilder.h
@@ -0,0 +1,94 @@
+//===- CFGBuilder.h - CFG building and updating utility ----------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// CFGBuilders provides utilities fo building and updating CFG for testing
+/// purposes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_CFG_BUILDER_H
+#define LLVM_UNITTESTS_CFG_BUILDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Debug.h"
+
+#include <memory>
+#include <set>
+#include <tuple>
+#include <vector>
+
+namespace llvm {
+
+class LLVMContext;
+class Module;
+class Function;
+class BasicBlock;
+class raw_ostream;
+
+struct CFGHolder {
+ std::unique_ptr<LLVMContext> Context;
+ std::unique_ptr<Module> M;
+ Function *F;
+
+ CFGHolder(StringRef ModuleName = "m", StringRef FunctionName = "foo");
+ ~CFGHolder(); // Defined in the .cpp file so we can use forward declarations.
+};
+
+/// \brief
+/// CFGBuilder builds IR with specific CFG, based on the supplied list of arcs.
+/// It's able to apply the provided updates and automatically modify the IR.
+///
+/// Internally it makes every basic block end with either SwitchInst or with
+/// UnreachableInst. When all arc to a BB are deleted, the BB remains in the
+/// function and doesn't get deleted.
+///
+class CFGBuilder {
+public:
+ struct Arc {
+ StringRef From;
+ StringRef To;
+
+ friend bool operator<(const Arc &LHS, const Arc &RHS) {
+ return std::tie(LHS.From, LHS.To) <
+ std::tie(RHS.From, RHS.To);
+ }
+ };
+
+ enum class ActionKind { Insert, Delete };
+ struct Update {
+ ActionKind Action;
+ Arc Edge;
+ };
+
+ CFGBuilder(Function *F, const std::vector<Arc> &InitialArcs,
+ std::vector<Update> Updates);
+
+ BasicBlock *getOrAddBlock(StringRef BlockName);
+ Optional<Update> getNextUpdate() const;
+ Optional<Update> applyUpdate();
+ void dump(raw_ostream &OS = dbgs()) const;
+
+private:
+ void buildCFG(const std::vector<Arc> &Arcs);
+ bool connect(const Arc &A);
+ bool disconnect(const Arc &A);
+
+ Function *F;
+ unsigned UpdateIdx = 0;
+ StringMap<BasicBlock *> NameToBlock;
+ std::set<Arc> Arcs;
+ std::vector<Update> Updates;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt
index d76ebfa64d88..92c9f8d3788d 100644
--- a/unittests/IR/CMakeLists.txt
+++ b/unittests/IR/CMakeLists.txt
@@ -10,6 +10,7 @@ set(IRSources
AsmWriterTest.cpp
AttributesTest.cpp
BasicBlockTest.cpp
+ CFGBuilder.cpp
ConstantRangeTest.cpp
ConstantsTest.cpp
DebugInfoTest.cpp
diff --git a/unittests/IR/DominatorTreeTest.cpp b/unittests/IR/DominatorTreeTest.cpp
index fa3dad8a2ab1..df1e2993dc85 100644
--- a/unittests/IR/DominatorTreeTest.cpp
+++ b/unittests/IR/DominatorTreeTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include <random>
#include "llvm/Analysis/PostDominators.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Constants.h"
@@ -15,22 +16,24 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
+#include "CFGBuilder.h"
#include "gtest/gtest.h"
using namespace llvm;
+struct PostDomTree : PostDomTreeBase<BasicBlock> {
+ PostDomTree(Function &F) { recalculate(F); }
+};
+
/// Build the dominator tree for the function and run the Test.
-static void
-runWithDomTree(Module &M, StringRef FuncName,
- function_ref<void(Function &F, DominatorTree *DT,
- DominatorTreeBase<BasicBlock> *PDT)>
- Test) {
+static void runWithDomTree(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, DominatorTree *DT, PostDomTree *PDT)> Test) {
auto *F = M.getFunction(FuncName);
ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
// Compute the dominator tree for the function.
DominatorTree DT(*F);
- DominatorTreeBase<BasicBlock> PDT(/*isPostDom*/ true);
- PDT.recalculate(*F);
+ PostDomTree PDT(*F);
Test(*F, &DT, &PDT);
}
@@ -72,8 +75,7 @@ TEST(DominatorTree, Unreachable) {
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
runWithDomTree(
- *M, "f",
- [&](Function &F, DominatorTree *DT, DominatorTreeBase<BasicBlock> *PDT) {
+ *M, "f", [&](Function &F, DominatorTree *DT, PostDomTree *PDT) {
Function::iterator FI = F.begin();
BasicBlock *BB0 = &*FI++;
@@ -293,8 +295,7 @@ TEST(DominatorTree, NonUniqueEdges) {
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
runWithDomTree(
- *M, "f",
- [&](Function &F, DominatorTree *DT, DominatorTreeBase<BasicBlock> *PDT) {
+ *M, "f", [&](Function &F, DominatorTree *DT, PostDomTree *PDT) {
Function::iterator FI = F.begin();
BasicBlock *BB0 = &*FI++;
@@ -324,3 +325,280 @@ TEST(DominatorTree, NonUniqueEdges) {
EXPECT_FALSE(DT->dominates(Edge_BB0_BB1_b, BB2));
});
}
+
+namespace {
+const auto Insert = CFGBuilder::ActionKind::Insert;
+const auto Delete = CFGBuilder::ActionKind::Delete;
+
+bool CompUpdates(const CFGBuilder::Update &A, const CFGBuilder::Update &B) {
+ return std::tie(A.Action, A.Edge.From, A.Edge.To) <
+ std::tie(B.Action, B.Edge.From, B.Edge.To);
+}
+} // namespace
+
+TEST(DominatorTree, InsertReachable) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
+ {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
+
+ std::vector<CFGBuilder::Update> Updates = {{Insert, {"12", "10"}},
+ {Insert, {"10", "9"}},
+ {Insert, {"7", "6"}},
+ {Insert, {"7", "5"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Insert);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.insertEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.insertEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, InsertReachable2) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
+ {"7", "5"}, {"2", "8"}, {"8", "11"}, {"11", "12"}, {"12", "10"},
+ {"10", "9"}, {"9", "10"}};
+
+ std::vector<CFGBuilder::Update> Updates = {{Insert, {"10", "7"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate = B.applyUpdate();
+ EXPECT_TRUE(LastUpdate);
+
+ EXPECT_EQ(LastUpdate->Action, Insert);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.insertEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.insertEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+}
+
+TEST(DominatorTree, InsertUnreachable) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {{"1", "2"}, {"2", "3"}, {"3", "4"},
+ {"5", "6"}, {"5", "7"}, {"3", "8"},
+ {"9", "10"}, {"11", "12"}};
+
+ std::vector<CFGBuilder::Update> Updates = {{Insert, {"4", "5"}},
+ {Insert, {"8", "9"}},
+ {Insert, {"10", "12"}},
+ {Insert, {"10", "11"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Insert);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.insertEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.insertEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, InsertMixed) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"5", "6"}, {"5", "7"},
+ {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}, {"7", "3"}};
+
+ std::vector<CFGBuilder::Update> Updates = {
+ {Insert, {"4", "5"}}, {Insert, {"2", "5"}}, {Insert, {"10", "9"}},
+ {Insert, {"12", "10"}}, {Insert, {"12", "10"}}, {Insert, {"7", "8"}},
+ {Insert, {"7", "5"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Insert);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.insertEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.insertEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, InsertPermut) {
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"5", "6"}, {"5", "7"},
+ {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}, {"7", "3"}};
+
+ std::vector<CFGBuilder::Update> Updates = {{Insert, {"4", "5"}},
+ {Insert, {"2", "5"}},
+ {Insert, {"10", "9"}},
+ {Insert, {"12", "10"}}};
+
+ while (std::next_permutation(Updates.begin(), Updates.end(), CompUpdates)) {
+ CFGHolder Holder;
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Insert);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.insertEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.insertEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+ }
+}
+
+TEST(DominatorTree, DeleteReachable) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"2", "4"}, {"3", "4"}, {"4", "5"}, {"5", "6"},
+ {"5", "7"}, {"7", "8"}, {"3", "8"}, {"8", "9"}, {"9", "10"}, {"10", "2"}};
+
+ std::vector<CFGBuilder::Update> Updates = {
+ {Delete, {"2", "4"}}, {Delete, {"7", "8"}}, {Delete, {"10", "2"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Delete);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.deleteEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.deleteEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, DeleteUnreachable) {
+ CFGHolder Holder;
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
+ {"7", "8"}, {"3", "8"}, {"8", "9"}, {"9", "10"}, {"10", "2"}};
+
+ std::vector<CFGBuilder::Update> Updates = {
+ {Delete, {"8", "9"}}, {Delete, {"7", "8"}}, {Delete, {"3", "4"}}};
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ EXPECT_EQ(LastUpdate->Action, Delete);
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ DT.deleteEdge(From, To);
+ EXPECT_TRUE(DT.verify());
+ PDT.deleteEdge(From, To);
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, InsertDelete) {
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
+ {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
+
+ std::vector<CFGBuilder::Update> Updates = {
+ {Insert, {"2", "4"}}, {Insert, {"12", "10"}}, {Insert, {"10", "9"}},
+ {Insert, {"7", "6"}}, {Insert, {"7", "5"}}, {Delete, {"3", "8"}},
+ {Insert, {"10", "7"}}, {Insert, {"2", "8"}}, {Delete, {"3", "4"}},
+ {Delete, {"8", "9"}}, {Delete, {"11", "12"}}};
+
+ CFGHolder Holder;
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ if (LastUpdate->Action == Insert) {
+ DT.insertEdge(From, To);
+ PDT.insertEdge(From, To);
+ } else {
+ DT.deleteEdge(From, To);
+ PDT.deleteEdge(From, To);
+ }
+
+ EXPECT_TRUE(DT.verify());
+ EXPECT_TRUE(PDT.verify());
+ }
+}
+
+TEST(DominatorTree, InsertDeleteExhaustive) {
+ std::vector<CFGBuilder::Arc> Arcs = {
+ {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
+ {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
+
+ std::vector<CFGBuilder::Update> Updates = {
+ {Insert, {"2", "4"}}, {Insert, {"12", "10"}}, {Insert, {"10", "9"}},
+ {Insert, {"7", "6"}}, {Insert, {"7", "5"}}, {Delete, {"3", "8"}},
+ {Insert, {"10", "7"}}, {Insert, {"2", "8"}}, {Delete, {"3", "4"}},
+ {Delete, {"8", "9"}}, {Delete, {"11", "12"}}};
+
+ std::mt19937 Generator(0);
+ for (unsigned i = 0; i < 16; ++i) {
+ std::shuffle(Updates.begin(), Updates.end(), Generator);
+ CFGHolder Holder;
+ CFGBuilder B(Holder.F, Arcs, Updates);
+ DominatorTree DT(*Holder.F);
+ EXPECT_TRUE(DT.verify());
+ PostDomTree PDT(*Holder.F);
+ EXPECT_TRUE(PDT.verify());
+
+ Optional<CFGBuilder::Update> LastUpdate;
+ while ((LastUpdate = B.applyUpdate())) {
+ BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
+ BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
+ if (LastUpdate->Action == Insert) {
+ DT.insertEdge(From, To);
+ PDT.insertEdge(From, To);
+ } else {
+ DT.deleteEdge(From, To);
+ PDT.deleteEdge(From, To);
+ }
+
+ EXPECT_TRUE(DT.verify());
+ EXPECT_TRUE(PDT.verify());
+ }
+ }
+}
diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp
index 186330f10573..d361107cc0d2 100644
--- a/unittests/IR/IRBuilderTest.cpp
+++ b/unittests/IR/IRBuilderTest.cpp
@@ -463,13 +463,14 @@ TEST_F(IRBuilderTest, DebugLoc) {
TEST_F(IRBuilderTest, DIImportedEntity) {
IRBuilder<> Builder(BB);
DIBuilder DIB(*M);
+ auto F = DIB.createFile("F.CBL", "/");
auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74,
- DIB.createFile("F.CBL", "/"), "llvm-cobol74",
+ F, "llvm-cobol74",
true, "", 0);
- DIB.createImportedDeclaration(CU, nullptr, 1);
- DIB.createImportedDeclaration(CU, nullptr, 1);
- DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, 2);
- DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, 2);
+ DIB.createImportedDeclaration(CU, nullptr, F, 1);
+ DIB.createImportedDeclaration(CU, nullptr, F, 1);
+ DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2);
+ DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2);
DIB.finalize();
EXPECT_TRUE(verifyModule(*M));
EXPECT_TRUE(CU->getImportedEntities().size() == 2);
diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp
index cb38b30f43e6..e47afca532d2 100644
--- a/unittests/IR/MetadataTest.cpp
+++ b/unittests/IR/MetadataTest.cpp
@@ -2116,29 +2116,35 @@ TEST_F(DIImportedEntityTest, get) {
unsigned Tag = dwarf::DW_TAG_imported_module;
DIScope *Scope = getSubprogram();
DINode *Entity = getCompositeType();
+ DIFile *File = getFile();
unsigned Line = 5;
StringRef Name = "name";
- auto *N = DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name);
+ auto *N =
+ DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, Name);
EXPECT_EQ(Tag, N->getTag());
EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(Entity, N->getEntity());
+ EXPECT_EQ(File, N->getFile());
EXPECT_EQ(Line, N->getLine());
EXPECT_EQ(Name, N->getName());
- EXPECT_EQ(N, DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name));
+ EXPECT_EQ(
+ N, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, Name));
EXPECT_NE(N,
DIImportedEntity::get(Context, dwarf::DW_TAG_imported_declaration,
- Scope, Entity, Line, Name));
+ Scope, Entity, File, Line, Name));
EXPECT_NE(N, DIImportedEntity::get(Context, Tag, getSubprogram(), Entity,
- Line, Name));
+ File, Line, Name));
EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, getCompositeType(),
- Line, Name));
- EXPECT_NE(N,
- DIImportedEntity::get(Context, Tag, Scope, Entity, Line + 1, Name));
- EXPECT_NE(N,
- DIImportedEntity::get(Context, Tag, Scope, Entity, Line, "other"));
+ File, Line, Name));
+ EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, nullptr, Line,
+ Name));
+ EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, File,
+ Line + 1, Name));
+ EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line,
+ "other"));
TempDIImportedEntity Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp
index b252641f1a13..b9b725f934b3 100644
--- a/unittests/Support/TargetParserTest.cpp
+++ b/unittests/Support/TargetParserTest.cpp
@@ -737,7 +737,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
unsigned Extensions = AArch64::AEK_CRC | AArch64::AEK_CRYPTO |
AArch64::AEK_FP | AArch64::AEK_SIMD |
AArch64::AEK_FP16 | AArch64::AEK_PROFILE |
- AArch64::AEK_RAS;
+ AArch64::AEK_RAS | AArch64::AEK_SVE;
for (unsigned i = 0; i <= Extensions; i++)
EXPECT_TRUE(i == 0 ? !AArch64::getExtensionFeatures(i, Features)
@@ -762,7 +762,8 @@ TEST(TargetParserTest, AArch64ArchExtFeature) {
{"simd", "nosimd", "+neon", "-neon"},
{"fp16", "nofp16", "+fullfp16", "-fullfp16"},
{"profile", "noprofile", "+spe", "-spe"},
- {"ras", "noras", "+ras", "-ras"}};
+ {"ras", "noras", "+ras", "-ras"},
+ {"sve", "nosve", "+sve", "-sve"}};
for (unsigned i = 0; i < array_lengthof(ArchExt); i++) {
EXPECT_EQ(StringRef(ArchExt[i][2]),
diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp
index 5cf0e9d0f5b3..120773a0c8dd 100644
--- a/unittests/Support/YAMLIOTest.cpp
+++ b/unittests/Support/YAMLIOTest.cpp
@@ -232,6 +232,22 @@ TEST(YAMLIO, TestSequenceMapWriteAndRead) {
}
}
+//
+// Test YAML filename handling.
+//
+static void testErrorFilename(const llvm::SMDiagnostic &Error, void *) {
+ EXPECT_EQ(Error.getFilename(), "foo.yaml");
+}
+
+TEST(YAMLIO, TestGivenFilename) {
+ auto Buffer = llvm::MemoryBuffer::getMemBuffer("{ x: 42 }", "foo.yaml");
+ Input yin(*Buffer, nullptr, testErrorFilename);
+ FooBar Value;
+ yin >> Value;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
//===----------------------------------------------------------------------===//
// Test built-in types
diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp
index a7a5ce8dd6d4..a75f446e4ba1 100644
--- a/unittests/Support/raw_ostream_test.cpp
+++ b/unittests/Support/raw_ostream_test.cpp
@@ -151,6 +151,11 @@ TEST(raw_ostreamTest, Justify) {
EXPECT_EQ(" xyz", printToString(right_justify("xyz", 6), 6));
EXPECT_EQ("abc", printToString(right_justify("abc", 3), 3));
EXPECT_EQ("big", printToString(right_justify("big", 1), 3));
+ EXPECT_EQ(" on ", printToString(center_justify("on", 9), 9));
+ EXPECT_EQ(" off ", printToString(center_justify("off", 10), 10));
+ EXPECT_EQ("single ", printToString(center_justify("single", 7), 7));
+ EXPECT_EQ("none", printToString(center_justify("none", 1), 4));
+ EXPECT_EQ("none", printToString(center_justify("none", 1), 1));
}
TEST(raw_ostreamTest, FormatHex) {