llvm.org GIT mirror llvm / 40d6772
[Dominators] Add CFGBuilder testing utility Summary: This patch introduces a new testing utility for building and modifying CFG -- CFGBuilder. The primary use case for the utility is testing the upcoming incremental dominator tree update API. The current design provides a simple mechanism of constructing arbitrary graphs and then applying series of updates to them. CFGBuilder takes care of creating empty functions, connecting and disconnecting basic blocks. Under the hood it uses SwitchInst and UnreachableInst. It will be also possible to create a thin wrapper over CFGBuilder for parsing string input and to hook it up to other textual tools (e.g. opt used with FileCheck). Reviewers: dberlin, sanjoy, grosser, dblaikie Reviewed By: dblaikie Subscribers: davide, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D34798 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307960 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 2 years ago
3 changed file(s) with 366 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- llvm/Testing/Support/CFGBuilder.cpp --------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CFGBuilder.h"
10
11 #include "llvm/IR/IRBuilder.h"
12 #include "llvm/IR/LLVMContext.h"
13 #include "llvm/IR/TypeBuilder.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "gtest/gtest.h"
17
18 #include
19
20 #define DEBUG_TYPE "cfg-builder"
21
22 using namespace llvm;
23
24 CFGHolder::CFGHolder(StringRef ModuleName, StringRef FunctionName)
25 : Context(llvm::make_unique()),
26 M(llvm::make_unique(ModuleName, *Context)) {
27 FunctionType *FTy = TypeBuilder::get(*Context);
28 F = cast(M->getOrInsertFunction(FunctionName, FTy));
29 }
30 CFGHolder::~CFGHolder() = default;
31
32 bool llvm::operator<(const CFGBuilder::Arc &LHS, const CFGBuilder::Arc &RHS) {
33 return std::tie(LHS.From, LHS.To) < std::tie(RHS.From, RHS.To);
34 }
35
36 CFGBuilder::CFGBuilder(Function *F, const std::vector &InitialArcs,
37 std::vector Updates)
38 : F(F), Updates(std::move(Updates)) {
39 assert(F);
40 buildCFG(InitialArcs);
41 }
42
43 static void ConnectBlocks(BasicBlock *From, BasicBlock *To) {
44 DEBUG(dbgs() << "Creating BB arc " << From->getName() << " -> "
45 << To->getName() << "\n";
46 dbgs().flush());
47 auto *IntTy = IntegerType::get(From->getContext(), 32);
48
49 if (isa(From->getTerminator()))
50 From->getTerminator()->eraseFromParent();
51 if (!From->getTerminator()) {
52 IRBuilder<> IRB(From);
53 IRB.CreateSwitch(ConstantInt::get(IntTy, 0), To);
54 return;
55 }
56
57 SwitchInst *SI = cast(From->getTerminator());
58 const auto Last = SI->getNumCases();
59
60 auto *IntVal = ConstantInt::get(IntTy, Last);
61 SI->addCase(IntVal, To);
62 }
63
64 static void DisconnectBlocks(BasicBlock *From, BasicBlock *To) {
65 DEBUG(dbgs() << "Deleting BB arc " << From->getName() << " -> "
66 << To->getName() << "\n";
67 dbgs().flush());
68 SwitchInst *SI = cast(From->getTerminator());
69
70 if (SI->getNumCases() == 0) {
71 SI->eraseFromParent();
72 IRBuilder<> IRB(From);
73 IRB.CreateUnreachable();
74 return;
75 }
76
77 if (SI->getDefaultDest() == To) {
78 auto FirstC = SI->case_begin();
79 SI->setDefaultDest(FirstC->getCaseSuccessor());
80 SI->removeCase(FirstC);
81 return;
82 }
83
84 for (auto CIt = SI->case_begin(); CIt != SI->case_end(); ++CIt)
85 if (CIt->getCaseSuccessor() == To) {
86 SI->removeCase(CIt);
87 return;
88 }
89 }
90
91 BasicBlock *CFGBuilder::getOrAddBlock(StringRef BlockName) {
92 auto BIt = NameToBlock.find(BlockName);
93 if (BIt != NameToBlock.end())
94 return BIt->second;
95
96 auto *BB = BasicBlock::Create(F->getParent()->getContext(), BlockName, F);
97 IRBuilder<> IRB(BB);
98 IRB.CreateUnreachable();
99 NameToBlock[BlockName] = BB;
100 return BB;
101 }
102
103 bool CFGBuilder::connect(const Arc &A) {
104 BasicBlock *From = getOrAddBlock(A.From);
105 BasicBlock *To = getOrAddBlock(A.To);
106 if (Arcs.count(A) != 0)
107 return false;
108
109 Arcs.insert(A);
110 ConnectBlocks(From, To);
111 return true;
112 }
113
114 bool CFGBuilder::disconnect(const Arc &A) {
115 assert(NameToBlock.count(A.From) != 0 && "No block to disconnect (From)");
116 assert(NameToBlock.count(A.To) != 0 && "No block to disconnect (To)");
117 if (Arcs.count(A) == 0)
118 return false;
119
120 BasicBlock *From = getOrAddBlock(A.From);
121 BasicBlock *To = getOrAddBlock(A.To);
122 Arcs.erase(A);
123 DisconnectBlocks(From, To);
124 return true;
125 }
126
127 void CFGBuilder::buildCFG(const std::vector &NewArcs) {
128 for (const auto &A : NewArcs) {
129 const bool Connected = connect(A);
130 (void)Connected;
131 assert(Connected);
132 }
133 }
134
135 Optional CFGBuilder::getNextUpdate() const {
136 if (UpdateIdx == Updates.size())
137 return None;
138 return Updates[UpdateIdx];
139 }
140
141 Optional CFGBuilder::applyUpdate() {
142 if (UpdateIdx == Updates.size())
143 return None;
144 Update NextUpdate = Updates[UpdateIdx++];
145 if (NextUpdate.Action == ActionKind::Insert)
146 connect(NextUpdate.Arc);
147 else
148 disconnect(NextUpdate.Arc);
149
150 return NextUpdate;
151 }
152
153 void CFGBuilder::dump(raw_ostream &OS) const {
154 OS << "Arcs:\n";
155 size_t i = 0;
156 for (const auto &A : Arcs)
157 OS << " " << i++ << ":\t" << A.From << " -> " << A.To << "\n";
158
159 OS << "Updates:\n";
160 i = 0;
161 for (const auto &U : Updates) {
162 OS << (i + 1 == UpdateIdx ? "->" : " ") << i
163 << ((U.Action == ActionKind::Insert) ? "\tIns " : "\tDel ") << U.Arc.From
164 << " -> " << U.Arc.To << "\n";
165 ++i;
166 }
167 }
168
169 //---- CFGBuilder tests ---------------------------------------------------===//
170
171 TEST(CFGBuilder, Construction) {
172 CFGHolder Holder;
173 std::vector Arcs = {{"entry", "a"}, {"a", "b"}, {"a", "c"},
174 {"c", "d"}, {"d", "b"}, {"d", "e"},
175 {"d", "f"}, {"e", "f"}};
176 CFGBuilder B(Holder.F, Arcs, {});
177
178 EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
179 EXPECT_TRUE(isa(B.getOrAddBlock("entry")->getTerminator()));
180 EXPECT_TRUE(isa(B.getOrAddBlock("a")->getTerminator()));
181 EXPECT_TRUE(isa(B.getOrAddBlock("b")->getTerminator()));
182 EXPECT_TRUE(isa(B.getOrAddBlock("d")->getTerminator()));
183
184 auto *DSwitch = cast(B.getOrAddBlock("d")->getTerminator());
185 // d has 3 successors, but one of them if going to be a default case
186 EXPECT_EQ(DSwitch->getNumCases(), 2U);
187 EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
188 }
189
190 TEST(CFGBuilder, Insertions) {
191 CFGHolder Holder;
192 const auto Insert = CFGBuilder::ActionKind::Insert;
193 std::vector Updates = {
194 {Insert, {"entry", "a"}}, {Insert, {"a", "b"}}, {Insert, {"a", "c"}},
195 {Insert, {"c", "d"}}, {Insert, {"d", "b"}}, {Insert, {"d", "e"}},
196 {Insert, {"d", "f"}}, {Insert, {"e", "f"}}};
197 const size_t NumUpdates = Updates.size();
198
199 CFGBuilder B(Holder.F, {}, Updates);
200
201 size_t i = 0;
202 while (B.applyUpdate())
203 ++i;
204 EXPECT_EQ(i, NumUpdates);
205
206 EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
207 EXPECT_TRUE(isa(B.getOrAddBlock("entry")->getTerminator()));
208 EXPECT_TRUE(isa(B.getOrAddBlock("a")->getTerminator()));
209 EXPECT_TRUE(isa(B.getOrAddBlock("b")->getTerminator()));
210 EXPECT_TRUE(isa(B.getOrAddBlock("d")->getTerminator()));
211
212 auto *DSwitch = cast(B.getOrAddBlock("d")->getTerminator());
213 // d has 3 successors, but one of them if going to be a default case
214 EXPECT_EQ(DSwitch->getNumCases(), 2U);
215 EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
216 }
217
218 TEST(CFGBuilder, Deletions) {
219 CFGHolder Holder;
220 std::vector Arcs = {
221 {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
222 const auto Delete = CFGBuilder::ActionKind::Delete;
223 std::vector Updates = {
224 {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
225 };
226 const size_t NumUpdates = Updates.size();
227
228 CFGBuilder B(Holder.F, Arcs, Updates);
229
230 EXPECT_TRUE(isa(B.getOrAddBlock("entry")->getTerminator()));
231 EXPECT_TRUE(isa(B.getOrAddBlock("a")->getTerminator()));
232 EXPECT_TRUE(isa(B.getOrAddBlock("c")->getTerminator()));
233 EXPECT_TRUE(isa(B.getOrAddBlock("d")->getTerminator()));
234
235 auto UpdateC = B.applyUpdate();
236
237 EXPECT_TRUE(UpdateC);
238 EXPECT_EQ(UpdateC->Action, CFGBuilder::ActionKind::Delete);
239 EXPECT_EQ(UpdateC->Arc.From, "c");
240 EXPECT_EQ(UpdateC->Arc.To, "d");
241 EXPECT_TRUE(isa(B.getOrAddBlock("c")->getTerminator()));
242
243 size_t i = 1;
244 while (B.applyUpdate())
245 ++i;
246 EXPECT_EQ(i, NumUpdates);
247
248 EXPECT_TRUE(isa(B.getOrAddBlock("a")->getTerminator()));
249 EXPECT_TRUE(isa(B.getOrAddBlock("entry")->getTerminator()));
250 }
251
252 TEST(CFGBuilder, Rebuild) {
253 CFGHolder Holder;
254 std::vector Arcs = {
255 {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
256 const auto Insert = CFGBuilder::ActionKind::Insert;
257 const auto Delete = CFGBuilder::ActionKind::Delete;
258 std::vector Updates = {
259 {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
260 {Insert, {"c", "d"}}, {Insert, {"a", "c"}}, {Insert, {"entry", "a"}},
261 };
262 const size_t NumUpdates = Updates.size();
263
264 CFGBuilder B(Holder.F, Arcs, Updates);
265 size_t i = 0;
266 while (B.applyUpdate())
267 ++i;
268 EXPECT_EQ(i, NumUpdates);
269
270 EXPECT_TRUE(isa(B.getOrAddBlock("entry")->getTerminator()));
271 EXPECT_TRUE(isa(B.getOrAddBlock("a")->getTerminator()));
272 EXPECT_TRUE(isa(B.getOrAddBlock("c")->getTerminator()));
273 EXPECT_TRUE(isa(B.getOrAddBlock("d")->getTerminator()));
274 }
0 //===- CFGBuilder.h - CFG building and updating utility ----------*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// CFGBuilders provides utilities fo building and updating CFG for testing
10 /// purposes.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_UNITTESTS_CFG_BUILDER_H
15 #define LLVM_UNITTESTS_CFG_BUILDER_H
16
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Debug.h"
22
23 #include
24 #include
25 #include
26
27 namespace llvm {
28
29 class LLVMContext;
30 class Module;
31 class Function;
32 class BasicBlock;
33 class raw_ostream;
34
35 struct CFGHolder {
36 std::unique_ptr Context;
37 std::unique_ptr M;
38 Function *F;
39
40 CFGHolder(StringRef ModuleName = "m", StringRef FunctionName = "foo");
41 ~CFGHolder(); // Defined in the .cpp file so we can use forward declarations.
42 };
43
44 /// \brief
45 /// CFGBuilder builds IR with specific CFG, based on the supplied list of arcs.
46 /// It's able to apply the provided updates and automatically modify the IR.
47 ///
48 /// Internally it makes every basic block end with either SwitchInst or with
49 /// UnreachableInst. When all arc to a BB are deleted, the BB remains in the
50 /// function and doesn't get deleted.
51 ///
52 class CFGBuilder {
53 public:
54 struct Arc {
55 StringRef From;
56 StringRef To;
57
58 friend bool operator<(const Arc &LHS, const Arc &RHS);
59 };
60
61 enum class ActionKind { Insert, Delete };
62 struct Update {
63 ActionKind Action;
64 Arc Arc;
65 };
66
67 CFGBuilder(Function *F, const std::vector &InitialArcs,
68 std::vector Updates);
69
70 BasicBlock *getOrAddBlock(StringRef BlockName);
71 Optional getNextUpdate() const;
72 Optional applyUpdate();
73 void dump(raw_ostream &OS = dbgs()) const;
74
75 private:
76 void buildCFG(const std::vector &Arcs);
77 bool connect(const Arc &A);
78 bool disconnect(const Arc &A);
79
80 Function *F;
81 unsigned UpdateIdx = 0;
82 StringMap NameToBlock;
83 std::set Arcs;
84 std::vector Updates;
85 };
86
87 } // namespace llvm
88
89 #endif
99 AsmWriterTest.cpp
1010 AttributesTest.cpp
1111 BasicBlockTest.cpp
12 CFGBuilder.cpp
1213 ConstantRangeTest.cpp
1314 ConstantsTest.cpp
1415 DebugInfoTest.cpp