blob: c75728b59ffe313aaaaa752f88b053fc0c637ace [file] [log] [blame]
Jakub Kuderski624463a2017-08-16 16:12:52 +00001//===- llvm/unittests/IR/DominatorTreeBatchUpdatesTest.cpp ----------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <random>
11#include "CFGBuilder.h"
12#include "gtest/gtest.h"
13#include "llvm/Analysis/PostDominators.h"
14#include "llvm/IR/Dominators.h"
15#include "llvm/Support/GenericDomTreeConstruction.h"
16
17#define DEBUG_TYPE "batch-update-tests"
18
19using namespace llvm;
20
21namespace {
22const auto CFGInsert = CFGBuilder::ActionKind::Insert;
23const auto CFGDelete = CFGBuilder::ActionKind::Delete;
24
25struct PostDomTree : PostDomTreeBase<BasicBlock> {
26 PostDomTree(Function &F) { recalculate(F); }
27};
28
29using DomUpdate = DominatorTree::UpdateType;
30static_assert(
31 std::is_same<DomUpdate, PostDomTree::UpdateType>::value,
32 "Trees differing only in IsPostDom should have the same update types");
33using DomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBDomTree>;
34using PostDomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBPostDomTree>;
35const auto Insert = DominatorTree::Insert;
36const auto Delete = DominatorTree::Delete;
37
38std::vector<DomUpdate> ToDomUpdates(CFGBuilder &B,
39 std::vector<CFGBuilder::Update> &In) {
40 std::vector<DomUpdate> Res;
41 Res.reserve(In.size());
42
43 for (const auto &CFGU : In)
44 Res.push_back({CFGU.Action == CFGInsert ? Insert : Delete,
45 B.getOrAddBlock(CFGU.Edge.From),
46 B.getOrAddBlock(CFGU.Edge.To)});
47 return Res;
48}
49} // namespace
50
51TEST(DominatorTreeBatchUpdates, LegalizeDomUpdates) {
52 CFGHolder Holder;
53 CFGBuilder Builder(Holder.F, {{"A", "B"}}, {});
54
55 BasicBlock *A = Builder.getOrAddBlock("A");
56 BasicBlock *B = Builder.getOrAddBlock("B");
57 BasicBlock *C = Builder.getOrAddBlock("C");
58 BasicBlock *D = Builder.getOrAddBlock("D");
59
60 std::vector<DomUpdate> Updates = {
61 {Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C},
62 {Insert, B, D}, {Delete, C, D}, {Delete, A, B}};
63 SmallVector<DomUpdate, 4> Legalized;
64 DomSNCA::LegalizeUpdates(Updates, Legalized);
Nicola Zaghend34e60c2018-05-14 12:53:11 +000065 LLVM_DEBUG(dbgs() << "Legalized updates:\t");
66 LLVM_DEBUG(for (auto &U : Legalized) dbgs() << U << ", ");
67 LLVM_DEBUG(dbgs() << "\n");
Jakub Kuderski624463a2017-08-16 16:12:52 +000068 EXPECT_EQ(Legalized.size(), 3UL);
69 EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, C}), Legalized.end());
70 EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, D}), Legalized.end());
71 EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, A, B}), Legalized.end());
72}
73
74TEST(DominatorTreeBatchUpdates, LegalizePostDomUpdates) {
75 CFGHolder Holder;
76 CFGBuilder Builder(Holder.F, {{"A", "B"}}, {});
77
78 BasicBlock *A = Builder.getOrAddBlock("A");
79 BasicBlock *B = Builder.getOrAddBlock("B");
80 BasicBlock *C = Builder.getOrAddBlock("C");
81 BasicBlock *D = Builder.getOrAddBlock("D");
82
83 std::vector<DomUpdate> Updates = {
84 {Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C},
85 {Insert, B, D}, {Delete, C, D}, {Delete, A, B}};
86 SmallVector<DomUpdate, 4> Legalized;
87 PostDomSNCA::LegalizeUpdates(Updates, Legalized);
Nicola Zaghend34e60c2018-05-14 12:53:11 +000088 LLVM_DEBUG(dbgs() << "Legalized postdom updates:\t");
89 LLVM_DEBUG(for (auto &U : Legalized) dbgs() << U << ", ");
90 LLVM_DEBUG(dbgs() << "\n");
Jakub Kuderski624463a2017-08-16 16:12:52 +000091 EXPECT_EQ(Legalized.size(), 3UL);
92 EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, C, B}), Legalized.end());
93 EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, D, B}), Legalized.end());
94 EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, B, A}), Legalized.end());
95}
96
97TEST(DominatorTreeBatchUpdates, SingleInsertion) {
98 CFGHolder Holder;
99 CFGBuilder Builder(Holder.F, {{"A", "B"}}, {{CFGInsert, {"B", "C"}}});
100
101 DominatorTree DT(*Holder.F);
102 EXPECT_TRUE(DT.verify());
103 PostDomTree PDT(*Holder.F);
Jakub Kuderski0cbc1b02018-05-11 09:30:29 +0000104 EXPECT_TRUE(PDT.verify());
Jakub Kuderski624463a2017-08-16 16:12:52 +0000105
106 BasicBlock *B = Builder.getOrAddBlock("B");
107 BasicBlock *C = Builder.getOrAddBlock("C");
108 std::vector<DomUpdate> Updates = {{Insert, B, C}};
109
110 ASSERT_TRUE(Builder.applyUpdate());
111
112 DT.applyUpdates(Updates);
113 EXPECT_TRUE(DT.verify());
114 PDT.applyUpdates(Updates);
115 EXPECT_TRUE(PDT.verify());
116}
117
118TEST(DominatorTreeBatchUpdates, SingleDeletion) {
119 CFGHolder Holder;
120 CFGBuilder Builder(Holder.F, {{"A", "B"}, {"B", "C"}},
121 {{CFGDelete, {"B", "C"}}});
122
123 DominatorTree DT(*Holder.F);
124 EXPECT_TRUE(DT.verify());
125 PostDomTree PDT(*Holder.F);
Jakub Kuderski0cbc1b02018-05-11 09:30:29 +0000126 EXPECT_TRUE(PDT.verify());
Jakub Kuderski624463a2017-08-16 16:12:52 +0000127
128 BasicBlock *B = Builder.getOrAddBlock("B");
129 BasicBlock *C = Builder.getOrAddBlock("C");
130 std::vector<DomUpdate> Updates = {{Delete, B, C}};
131
132 ASSERT_TRUE(Builder.applyUpdate());
133
134 DT.applyUpdates(Updates);
135 EXPECT_TRUE(DT.verify());
136 PDT.applyUpdates(Updates);
137 EXPECT_TRUE(PDT.verify());
138}
139
140TEST(DominatorTreeBatchUpdates, FewInsertion) {
141 std::vector<CFGBuilder::Update> CFGUpdates = {{CFGInsert, {"B", "C"}},
142 {CFGInsert, {"C", "B"}},
143 {CFGInsert, {"C", "D"}},
144 {CFGInsert, {"D", "E"}}};
145
146 CFGHolder Holder;
147 CFGBuilder Builder(Holder.F, {{"A", "B"}}, CFGUpdates);
148
149 DominatorTree DT(*Holder.F);
150 EXPECT_TRUE(DT.verify());
151 PostDomTree PDT(*Holder.F);
152 EXPECT_TRUE(PDT.verify());
153
154 BasicBlock *B = Builder.getOrAddBlock("B");
155 BasicBlock *C = Builder.getOrAddBlock("C");
156 BasicBlock *D = Builder.getOrAddBlock("D");
157 BasicBlock *E = Builder.getOrAddBlock("E");
158
159 std::vector<DomUpdate> Updates = {
160 {Insert, B, C}, {Insert, C, B}, {Insert, C, D}, {Insert, D, E}};
161
162 while (Builder.applyUpdate())
163 ;
164
165 DT.applyUpdates(Updates);
166 EXPECT_TRUE(DT.verify());
167 PDT.applyUpdates(Updates);
168 EXPECT_TRUE(PDT.verify());
169}
170
171TEST(DominatorTreeBatchUpdates, FewDeletions) {
172 std::vector<CFGBuilder::Update> CFGUpdates = {{CFGDelete, {"B", "C"}},
173 {CFGDelete, {"C", "B"}},
174 {CFGDelete, {"B", "D"}},
175 {CFGDelete, {"D", "E"}}};
176
177 CFGHolder Holder;
178 CFGBuilder Builder(
179 Holder.F, {{"A", "B"}, {"B", "C"}, {"B", "D"}, {"D", "E"}, {"C", "B"}},
180 CFGUpdates);
181
182 DominatorTree DT(*Holder.F);
183 EXPECT_TRUE(DT.verify());
184 PostDomTree PDT(*Holder.F);
185 EXPECT_TRUE(PDT.verify());
186
187 auto Updates = ToDomUpdates(Builder, CFGUpdates);
188
189 while (Builder.applyUpdate())
190 ;
191
192 DT.applyUpdates(Updates);
193 EXPECT_TRUE(DT.verify());
194 PDT.applyUpdates(Updates);
195 EXPECT_TRUE(PDT.verify());
196}
197
198TEST(DominatorTreeBatchUpdates, InsertDelete) {
199 std::vector<CFGBuilder::Arc> Arcs = {
200 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
201 {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
202
203 std::vector<CFGBuilder::Update> Updates = {
204 {CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}},
205 {CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}},
206 {CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}},
207 {CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}},
208 {CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}},
209 {CFGDelete, {"11", "12"}}};
210
211 CFGHolder Holder;
212 CFGBuilder B(Holder.F, Arcs, Updates);
213 DominatorTree DT(*Holder.F);
214 EXPECT_TRUE(DT.verify());
215 PostDomTree PDT(*Holder.F);
216 EXPECT_TRUE(PDT.verify());
217
218 while (B.applyUpdate())
219 ;
220
221 auto DomUpdates = ToDomUpdates(B, Updates);
222 DT.applyUpdates(DomUpdates);
223 EXPECT_TRUE(DT.verify());
224 PDT.applyUpdates(DomUpdates);
225 EXPECT_TRUE(PDT.verify());
226}
227
228TEST(DominatorTreeBatchUpdates, InsertDeleteExhaustive) {
229 std::vector<CFGBuilder::Arc> Arcs = {
230 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
231 {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
232
233 std::vector<CFGBuilder::Update> Updates = {
234 {CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}},
235 {CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}},
236 {CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}},
237 {CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}},
238 {CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}},
239 {CFGDelete, {"11", "12"}}};
240
241 std::mt19937 Generator(0);
242 for (unsigned i = 0; i < 16; ++i) {
243 std::shuffle(Updates.begin(), Updates.end(), Generator);
244 CFGHolder Holder;
245 CFGBuilder B(Holder.F, Arcs, Updates);
246 DominatorTree DT(*Holder.F);
247 EXPECT_TRUE(DT.verify());
248 PostDomTree PDT(*Holder.F);
249 EXPECT_TRUE(PDT.verify());
250
251 while (B.applyUpdate())
252 ;
253
254 auto DomUpdates = ToDomUpdates(B, Updates);
255 DT.applyUpdates(DomUpdates);
256 EXPECT_TRUE(DT.verify());
257 PDT.applyUpdates(DomUpdates);
258 EXPECT_TRUE(PDT.verify());
259 }
260}
David Green990eb1f2018-01-20 10:29:37 +0000261
262// These are some odd flowgraphs, usually generated from csmith cases,
263// which are difficult on post dom trees.
264TEST(DominatorTreeBatchUpdates, InfiniteLoop) {
265 std::vector<CFGBuilder::Arc> Arcs = {
266 {"1", "2"},
267 {"2", "3"},
268 {"3", "6"}, {"3", "5"},
269 {"4", "5"},
270 {"5", "2"},
271 {"6", "3"}, {"6", "4"}};
272
273 // SplitBlock on 3 -> 5
274 std::vector<CFGBuilder::Update> Updates = {
275 {CFGInsert, {"N", "5"}}, {CFGInsert, {"3", "N"}}, {CFGDelete, {"3", "5"}}};
276
277 CFGHolder Holder;
278 CFGBuilder B(Holder.F, Arcs, Updates);
279 DominatorTree DT(*Holder.F);
280 EXPECT_TRUE(DT.verify());
281 PostDomTree PDT(*Holder.F);
282 EXPECT_TRUE(PDT.verify());
283
284 while (B.applyUpdate())
285 ;
286
287 auto DomUpdates = ToDomUpdates(B, Updates);
288 DT.applyUpdates(DomUpdates);
289 EXPECT_TRUE(DT.verify());
290 PDT.applyUpdates(DomUpdates);
291 EXPECT_TRUE(PDT.verify());
292}
293
294TEST(DominatorTreeBatchUpdates, DeadBlocks) {
295 std::vector<CFGBuilder::Arc> Arcs = {
296 {"1", "2"},
297 {"2", "3"},
298 {"3", "4"}, {"3", "7"},
299 {"4", "4"},
300 {"5", "6"}, {"5", "7"},
301 {"6", "7"},
302 {"7", "2"}, {"7", "8"}};
303
304 // Remove dead 5 and 7,
305 // plus SplitBlock on 7 -> 8
306 std::vector<CFGBuilder::Update> Updates = {
307 {CFGDelete, {"6", "7"}}, {CFGDelete, {"5", "7"}}, {CFGDelete, {"5", "6"}},
308 {CFGInsert, {"N", "8"}}, {CFGInsert, {"7", "N"}}, {CFGDelete, {"7", "8"}}};
309
310 CFGHolder Holder;
311 CFGBuilder B(Holder.F, Arcs, Updates);
312 DominatorTree DT(*Holder.F);
313 EXPECT_TRUE(DT.verify());
314 PostDomTree PDT(*Holder.F);
315 EXPECT_TRUE(PDT.verify());
316
317 while (B.applyUpdate())
318 ;
319
320 auto DomUpdates = ToDomUpdates(B, Updates);
321 DT.applyUpdates(DomUpdates);
322 EXPECT_TRUE(DT.verify());
323 PDT.applyUpdates(DomUpdates);
324 EXPECT_TRUE(PDT.verify());
325}
326
327TEST(DominatorTreeBatchUpdates, InfiniteLoop2) {
328 std::vector<CFGBuilder::Arc> Arcs = {
329 {"1", "2"},
330 {"2", "6"}, {"2", "3"},
331 {"3", "4"},
332 {"4", "5"}, {"4", "6"},
333 {"5", "4"},
334 {"6", "2"}};
335
336 // SplitBlock on 4 -> 6
337 std::vector<CFGBuilder::Update> Updates = {
338 {CFGInsert, {"N", "6"}}, {CFGInsert, {"4", "N"}}, {CFGDelete, {"4", "6"}}};
339
340 CFGHolder Holder;
341 CFGBuilder B(Holder.F, Arcs, Updates);
342 DominatorTree DT(*Holder.F);
343 EXPECT_TRUE(DT.verify());
344 PostDomTree PDT(*Holder.F);
345 EXPECT_TRUE(PDT.verify());
346
347 while (B.applyUpdate())
348 ;
349
350 auto DomUpdates = ToDomUpdates(B, Updates);
351 DT.applyUpdates(DomUpdates);
352 EXPECT_TRUE(DT.verify());
353 PDT.applyUpdates(DomUpdates);
354 EXPECT_TRUE(PDT.verify());
355}