xref: /llvm-project/llvm/unittests/IR/DominatorTreeBatchUpdatesTest.cpp (revision d34e60ca8532511acb8c93ef26297e349fbec86a)
1 //===- 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 
19 using namespace llvm;
20 
21 namespace {
22 const auto CFGInsert = CFGBuilder::ActionKind::Insert;
23 const auto CFGDelete = CFGBuilder::ActionKind::Delete;
24 
25 struct PostDomTree : PostDomTreeBase<BasicBlock> {
26   PostDomTree(Function &F) { recalculate(F); }
27 };
28 
29 using DomUpdate = DominatorTree::UpdateType;
30 static_assert(
31     std::is_same<DomUpdate, PostDomTree::UpdateType>::value,
32     "Trees differing only in IsPostDom should have the same update types");
33 using DomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBDomTree>;
34 using PostDomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBPostDomTree>;
35 const auto Insert = DominatorTree::Insert;
36 const auto Delete = DominatorTree::Delete;
37 
38 std::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 
51 TEST(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);
65   LLVM_DEBUG(dbgs() << "Legalized updates:\t");
66   LLVM_DEBUG(for (auto &U : Legalized) dbgs() << U << ", ");
67   LLVM_DEBUG(dbgs() << "\n");
68   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 
74 TEST(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);
88   LLVM_DEBUG(dbgs() << "Legalized postdom updates:\t");
89   LLVM_DEBUG(for (auto &U : Legalized) dbgs() << U << ", ");
90   LLVM_DEBUG(dbgs() << "\n");
91   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 
97 TEST(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);
104   EXPECT_TRUE(PDT.verify());
105 
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 
118 TEST(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);
126   EXPECT_TRUE(PDT.verify());
127 
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 
140 TEST(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 
171 TEST(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 
198 TEST(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 
228 TEST(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 }
261 
262 // These are some odd flowgraphs, usually generated from csmith cases,
263 // which are difficult on post dom trees.
264 TEST(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 
294 TEST(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 
327 TEST(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 }
356