1 //===- llvm/unittests/IR/DominatorTreeBatchUpdatesTest.cpp ----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "CFGBuilder.h"
10 #include "llvm/Analysis/PostDominators.h"
11 #include "llvm/IR/Dominators.h"
12 #include "llvm/Support/GenericDomTreeConstruction.h"
13 #include "gtest/gtest.h"
16 #define DEBUG_TYPE "batch-update-tests"
21 const auto CFGInsert
= CFGBuilder::ActionKind::Insert
;
22 const auto CFGDelete
= CFGBuilder::ActionKind::Delete
;
24 using DomUpdate
= DominatorTree::UpdateType
;
26 std::is_same_v
<DomUpdate
, PostDominatorTree::UpdateType
>,
27 "Trees differing only in IsPostDom should have the same update types");
28 using DomSNCA
= DomTreeBuilder::SemiNCAInfo
<DomTreeBuilder::BBDomTree
>;
29 using PostDomSNCA
= DomTreeBuilder::SemiNCAInfo
<DomTreeBuilder::BBPostDomTree
>;
30 const auto Insert
= DominatorTree::Insert
;
31 const auto Delete
= DominatorTree::Delete
;
33 std::vector
<DomUpdate
> ToDomUpdates(CFGBuilder
&B
,
34 std::vector
<CFGBuilder::Update
> &In
) {
35 std::vector
<DomUpdate
> Res
;
36 Res
.reserve(In
.size());
38 for (const auto &CFGU
: In
)
39 Res
.push_back({CFGU
.Action
== CFGInsert
? Insert
: Delete
,
40 B
.getOrAddBlock(CFGU
.Edge
.From
),
41 B
.getOrAddBlock(CFGU
.Edge
.To
)});
46 TEST(DominatorTreeBatchUpdates
, LegalizeDomUpdates
) {
48 CFGBuilder
Builder(Holder
.F
, {{"A", "B"}}, {});
50 BasicBlock
*A
= Builder
.getOrAddBlock("A");
51 BasicBlock
*B
= Builder
.getOrAddBlock("B");
52 BasicBlock
*C
= Builder
.getOrAddBlock("C");
53 BasicBlock
*D
= Builder
.getOrAddBlock("D");
55 std::vector
<DomUpdate
> Updates
= {
56 {Insert
, B
, C
}, {Insert
, C
, D
}, {Delete
, B
, C
}, {Insert
, B
, C
},
57 {Insert
, B
, D
}, {Delete
, C
, D
}, {Delete
, A
, B
}};
58 SmallVector
<DomUpdate
, 4> Legalized
;
59 cfg::LegalizeUpdates
<BasicBlock
*>(Updates
, Legalized
, false);
60 LLVM_DEBUG(dbgs() << "Legalized updates:\t");
61 LLVM_DEBUG(for (auto &U
: Legalized
) { U
.dump(); dbgs() << ", "; });
62 LLVM_DEBUG(dbgs() << "\n");
63 EXPECT_EQ(Legalized
.size(), 3UL);
64 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Insert
, B
, C
}));
65 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Insert
, B
, D
}));
66 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Delete
, A
, B
}));
69 TEST(DominatorTreeBatchUpdates
, LegalizePostDomUpdates
) {
71 CFGBuilder
Builder(Holder
.F
, {{"A", "B"}}, {});
73 BasicBlock
*A
= Builder
.getOrAddBlock("A");
74 BasicBlock
*B
= Builder
.getOrAddBlock("B");
75 BasicBlock
*C
= Builder
.getOrAddBlock("C");
76 BasicBlock
*D
= Builder
.getOrAddBlock("D");
78 std::vector
<DomUpdate
> Updates
= {
79 {Insert
, B
, C
}, {Insert
, C
, D
}, {Delete
, B
, C
}, {Insert
, B
, C
},
80 {Insert
, B
, D
}, {Delete
, C
, D
}, {Delete
, A
, B
}};
81 SmallVector
<DomUpdate
, 4> Legalized
;
82 cfg::LegalizeUpdates
<BasicBlock
*>(Updates
, Legalized
, true);
83 LLVM_DEBUG(dbgs() << "Legalized postdom updates:\t");
84 LLVM_DEBUG(for (auto &U
: Legalized
) { U
.dump(); dbgs() << ", "; });
85 LLVM_DEBUG(dbgs() << "\n");
86 EXPECT_EQ(Legalized
.size(), 3UL);
87 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Insert
, C
, B
}));
88 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Insert
, D
, B
}));
89 EXPECT_TRUE(llvm::is_contained(Legalized
, DomUpdate
{Delete
, B
, A
}));
92 TEST(DominatorTreeBatchUpdates
, SingleInsertion
) {
94 CFGBuilder
Builder(Holder
.F
, {{"A", "B"}}, {{CFGInsert
, {"B", "C"}}});
96 DominatorTree
DT(*Holder
.F
);
97 EXPECT_TRUE(DT
.verify());
98 PostDominatorTree
PDT(*Holder
.F
);
99 EXPECT_TRUE(PDT
.verify());
101 BasicBlock
*B
= Builder
.getOrAddBlock("B");
102 BasicBlock
*C
= Builder
.getOrAddBlock("C");
103 std::vector
<DomUpdate
> Updates
= {{Insert
, B
, C
}};
105 ASSERT_TRUE(Builder
.applyUpdate());
107 DT
.applyUpdates(Updates
);
108 EXPECT_TRUE(DT
.verify());
109 PDT
.applyUpdates(Updates
);
110 EXPECT_TRUE(PDT
.verify());
113 TEST(DominatorTreeBatchUpdates
, SingleDeletion
) {
115 CFGBuilder
Builder(Holder
.F
, {{"A", "B"}, {"B", "C"}},
116 {{CFGDelete
, {"B", "C"}}});
118 DominatorTree
DT(*Holder
.F
);
119 EXPECT_TRUE(DT
.verify());
120 PostDominatorTree
PDT(*Holder
.F
);
121 EXPECT_TRUE(PDT
.verify());
123 BasicBlock
*B
= Builder
.getOrAddBlock("B");
124 BasicBlock
*C
= Builder
.getOrAddBlock("C");
125 std::vector
<DomUpdate
> Updates
= {{Delete
, B
, C
}};
127 ASSERT_TRUE(Builder
.applyUpdate());
129 DT
.applyUpdates(Updates
);
130 EXPECT_TRUE(DT
.verify());
131 PDT
.applyUpdates(Updates
);
132 EXPECT_TRUE(PDT
.verify());
135 TEST(DominatorTreeBatchUpdates
, FewInsertion
) {
136 std::vector
<CFGBuilder::Update
> CFGUpdates
= {{CFGInsert
, {"B", "C"}},
137 {CFGInsert
, {"C", "B"}},
138 {CFGInsert
, {"C", "D"}},
139 {CFGInsert
, {"D", "E"}}};
142 CFGBuilder
Builder(Holder
.F
, {{"A", "B"}}, CFGUpdates
);
144 DominatorTree
DT(*Holder
.F
);
145 EXPECT_TRUE(DT
.verify());
146 PostDominatorTree
PDT(*Holder
.F
);
147 EXPECT_TRUE(PDT
.verify());
149 BasicBlock
*B
= Builder
.getOrAddBlock("B");
150 BasicBlock
*C
= Builder
.getOrAddBlock("C");
151 BasicBlock
*D
= Builder
.getOrAddBlock("D");
152 BasicBlock
*E
= Builder
.getOrAddBlock("E");
154 std::vector
<DomUpdate
> Updates
= {
155 {Insert
, B
, C
}, {Insert
, C
, B
}, {Insert
, C
, D
}, {Insert
, D
, E
}};
157 while (Builder
.applyUpdate())
160 DT
.applyUpdates(Updates
);
161 EXPECT_TRUE(DT
.verify());
162 PDT
.applyUpdates(Updates
);
163 EXPECT_TRUE(PDT
.verify());
166 TEST(DominatorTreeBatchUpdates
, FewDeletions
) {
167 std::vector
<CFGBuilder::Update
> CFGUpdates
= {{CFGDelete
, {"B", "C"}},
168 {CFGDelete
, {"C", "B"}},
169 {CFGDelete
, {"B", "D"}},
170 {CFGDelete
, {"D", "E"}}};
174 Holder
.F
, {{"A", "B"}, {"B", "C"}, {"B", "D"}, {"D", "E"}, {"C", "B"}},
177 DominatorTree
DT(*Holder
.F
);
178 EXPECT_TRUE(DT
.verify());
179 PostDominatorTree
PDT(*Holder
.F
);
180 EXPECT_TRUE(PDT
.verify());
182 auto Updates
= ToDomUpdates(Builder
, CFGUpdates
);
184 while (Builder
.applyUpdate())
187 DT
.applyUpdates(Updates
);
188 EXPECT_TRUE(DT
.verify());
189 PDT
.applyUpdates(Updates
);
190 EXPECT_TRUE(PDT
.verify());
193 TEST(DominatorTreeBatchUpdates
, InsertDelete
) {
194 std::vector
<CFGBuilder::Arc
> Arcs
= {
195 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
196 {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
198 std::vector
<CFGBuilder::Update
> Updates
= {
199 {CFGInsert
, {"2", "4"}}, {CFGInsert
, {"12", "10"}},
200 {CFGInsert
, {"10", "9"}}, {CFGInsert
, {"7", "6"}},
201 {CFGInsert
, {"7", "5"}}, {CFGDelete
, {"3", "8"}},
202 {CFGInsert
, {"10", "7"}}, {CFGInsert
, {"2", "8"}},
203 {CFGDelete
, {"3", "4"}}, {CFGDelete
, {"8", "9"}},
204 {CFGDelete
, {"11", "12"}}};
207 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
208 DominatorTree
DT(*Holder
.F
);
209 EXPECT_TRUE(DT
.verify());
210 PostDominatorTree
PDT(*Holder
.F
);
211 EXPECT_TRUE(PDT
.verify());
213 while (B
.applyUpdate())
216 auto DomUpdates
= ToDomUpdates(B
, Updates
);
217 DT
.applyUpdates(DomUpdates
);
218 EXPECT_TRUE(DT
.verify());
219 PDT
.applyUpdates(DomUpdates
);
220 EXPECT_TRUE(PDT
.verify());
223 TEST(DominatorTreeBatchUpdates
, InsertDeleteExhaustive
) {
224 std::vector
<CFGBuilder::Arc
> Arcs
= {
225 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
226 {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
228 std::vector
<CFGBuilder::Update
> Updates
= {
229 {CFGInsert
, {"2", "4"}}, {CFGInsert
, {"12", "10"}},
230 {CFGInsert
, {"10", "9"}}, {CFGInsert
, {"7", "6"}},
231 {CFGInsert
, {"7", "5"}}, {CFGDelete
, {"3", "8"}},
232 {CFGInsert
, {"10", "7"}}, {CFGInsert
, {"2", "8"}},
233 {CFGDelete
, {"3", "4"}}, {CFGDelete
, {"8", "9"}},
234 {CFGDelete
, {"11", "12"}}};
236 std::mt19937
Generator(0);
237 for (unsigned i
= 0; i
< 16; ++i
) {
238 std::shuffle(Updates
.begin(), Updates
.end(), Generator
);
240 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
241 DominatorTree
DT(*Holder
.F
);
242 EXPECT_TRUE(DT
.verify());
243 PostDominatorTree
PDT(*Holder
.F
);
244 EXPECT_TRUE(PDT
.verify());
246 while (B
.applyUpdate())
249 auto DomUpdates
= ToDomUpdates(B
, Updates
);
250 DT
.applyUpdates(DomUpdates
);
251 EXPECT_TRUE(DT
.verify());
252 PDT
.applyUpdates(DomUpdates
);
253 EXPECT_TRUE(PDT
.verify());
257 // These are some odd flowgraphs, usually generated from csmith cases,
258 // which are difficult on post dom trees.
259 TEST(DominatorTreeBatchUpdates
, InfiniteLoop
) {
260 std::vector
<CFGBuilder::Arc
> Arcs
= {
263 {"3", "6"}, {"3", "5"},
266 {"6", "3"}, {"6", "4"}};
268 // SplitBlock on 3 -> 5
269 std::vector
<CFGBuilder::Update
> Updates
= {
270 {CFGInsert
, {"N", "5"}}, {CFGInsert
, {"3", "N"}}, {CFGDelete
, {"3", "5"}}};
273 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
274 DominatorTree
DT(*Holder
.F
);
275 EXPECT_TRUE(DT
.verify());
276 PostDominatorTree
PDT(*Holder
.F
);
277 EXPECT_TRUE(PDT
.verify());
279 while (B
.applyUpdate())
282 auto DomUpdates
= ToDomUpdates(B
, Updates
);
283 DT
.applyUpdates(DomUpdates
);
284 EXPECT_TRUE(DT
.verify());
285 PDT
.applyUpdates(DomUpdates
);
286 EXPECT_TRUE(PDT
.verify());
289 TEST(DominatorTreeBatchUpdates
, DeadBlocks
) {
290 std::vector
<CFGBuilder::Arc
> Arcs
= {
293 {"3", "4"}, {"3", "7"},
295 {"5", "6"}, {"5", "7"},
297 {"7", "2"}, {"7", "8"}};
299 // Remove dead 5 and 7,
300 // plus SplitBlock on 7 -> 8
301 std::vector
<CFGBuilder::Update
> Updates
= {
302 {CFGDelete
, {"6", "7"}}, {CFGDelete
, {"5", "7"}}, {CFGDelete
, {"5", "6"}},
303 {CFGInsert
, {"N", "8"}}, {CFGInsert
, {"7", "N"}}, {CFGDelete
, {"7", "8"}}};
306 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
307 DominatorTree
DT(*Holder
.F
);
308 EXPECT_TRUE(DT
.verify());
309 PostDominatorTree
PDT(*Holder
.F
);
310 EXPECT_TRUE(PDT
.verify());
312 while (B
.applyUpdate())
315 auto DomUpdates
= ToDomUpdates(B
, Updates
);
316 DT
.applyUpdates(DomUpdates
);
317 EXPECT_TRUE(DT
.verify());
318 PDT
.applyUpdates(DomUpdates
);
319 EXPECT_TRUE(PDT
.verify());
322 TEST(DominatorTreeBatchUpdates
, InfiniteLoop2
) {
323 std::vector
<CFGBuilder::Arc
> Arcs
= {
325 {"2", "6"}, {"2", "3"},
327 {"4", "5"}, {"4", "6"},
331 // SplitBlock on 4 -> 6
332 std::vector
<CFGBuilder::Update
> Updates
= {
333 {CFGInsert
, {"N", "6"}}, {CFGInsert
, {"4", "N"}}, {CFGDelete
, {"4", "6"}}};
336 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
337 DominatorTree
DT(*Holder
.F
);
338 EXPECT_TRUE(DT
.verify());
339 PostDominatorTree
PDT(*Holder
.F
);
340 EXPECT_TRUE(PDT
.verify());
342 while (B
.applyUpdate())
345 auto DomUpdates
= ToDomUpdates(B
, Updates
);
346 DT
.applyUpdates(DomUpdates
);
347 EXPECT_TRUE(DT
.verify());
348 PDT
.applyUpdates(DomUpdates
);
349 EXPECT_TRUE(PDT
.verify());