DominatorTreeBatchUpdatesTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //===- llvm/unittests/IR/DominatorTreeBatchUpdatesTest.cpp ----------------===//
  2. //
  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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include <random>
  9. #include "CFGBuilder.h"
  10. #include "gtest/gtest.h"
  11. #include "llvm/Analysis/PostDominators.h"
  12. #include "llvm/IR/Dominators.h"
  13. #include "llvm/Support/GenericDomTreeConstruction.h"
  14. #define DEBUG_TYPE "batch-update-tests"
  15. using namespace llvm;
  16. namespace {
  17. const auto CFGInsert = CFGBuilder::ActionKind::Insert;
  18. const auto CFGDelete = CFGBuilder::ActionKind::Delete;
  19. using DomUpdate = DominatorTree::UpdateType;
  20. static_assert(
  21. std::is_same<DomUpdate, PostDominatorTree::UpdateType>::value,
  22. "Trees differing only in IsPostDom should have the same update types");
  23. using DomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBDomTree>;
  24. using PostDomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBPostDomTree>;
  25. const auto Insert = DominatorTree::Insert;
  26. const auto Delete = DominatorTree::Delete;
  27. std::vector<DomUpdate> ToDomUpdates(CFGBuilder &B,
  28. std::vector<CFGBuilder::Update> &In) {
  29. std::vector<DomUpdate> Res;
  30. Res.reserve(In.size());
  31. for (const auto &CFGU : In)
  32. Res.push_back({CFGU.Action == CFGInsert ? Insert : Delete,
  33. B.getOrAddBlock(CFGU.Edge.From),
  34. B.getOrAddBlock(CFGU.Edge.To)});
  35. return Res;
  36. }
  37. } // namespace
  38. TEST(DominatorTreeBatchUpdates, LegalizeDomUpdates) {
  39. CFGHolder Holder;
  40. CFGBuilder Builder(Holder.F, {{"A", "B"}}, {});
  41. BasicBlock *A = Builder.getOrAddBlock("A");
  42. BasicBlock *B = Builder.getOrAddBlock("B");
  43. BasicBlock *C = Builder.getOrAddBlock("C");
  44. BasicBlock *D = Builder.getOrAddBlock("D");
  45. std::vector<DomUpdate> Updates = {
  46. {Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C},
  47. {Insert, B, D}, {Delete, C, D}, {Delete, A, B}};
  48. SmallVector<DomUpdate, 4> Legalized;
  49. cfg::LegalizeUpdates<BasicBlock *>(Updates, Legalized, false);
  50. LLVM_DEBUG(dbgs() << "Legalized updates:\t");
  51. LLVM_DEBUG(for (auto &U : Legalized) { U.dump(); dbgs() << ", "; });
  52. LLVM_DEBUG(dbgs() << "\n");
  53. EXPECT_EQ(Legalized.size(), 3UL);
  54. EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, C}), Legalized.end());
  55. EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, D}), Legalized.end());
  56. EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, A, B}), Legalized.end());
  57. }
  58. TEST(DominatorTreeBatchUpdates, LegalizePostDomUpdates) {
  59. CFGHolder Holder;
  60. CFGBuilder Builder(Holder.F, {{"A", "B"}}, {});
  61. BasicBlock *A = Builder.getOrAddBlock("A");
  62. BasicBlock *B = Builder.getOrAddBlock("B");
  63. BasicBlock *C = Builder.getOrAddBlock("C");
  64. BasicBlock *D = Builder.getOrAddBlock("D");
  65. std::vector<DomUpdate> Updates = {
  66. {Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C},
  67. {Insert, B, D}, {Delete, C, D}, {Delete, A, B}};
  68. SmallVector<DomUpdate, 4> Legalized;
  69. cfg::LegalizeUpdates<BasicBlock *>(Updates, Legalized, true);
  70. LLVM_DEBUG(dbgs() << "Legalized postdom updates:\t");
  71. LLVM_DEBUG(for (auto &U : Legalized) { U.dump(); dbgs() << ", "; });
  72. LLVM_DEBUG(dbgs() << "\n");
  73. EXPECT_EQ(Legalized.size(), 3UL);
  74. EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, C, B}), Legalized.end());
  75. EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, D, B}), Legalized.end());
  76. EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, B, A}), Legalized.end());
  77. }
  78. TEST(DominatorTreeBatchUpdates, SingleInsertion) {
  79. CFGHolder Holder;
  80. CFGBuilder Builder(Holder.F, {{"A", "B"}}, {{CFGInsert, {"B", "C"}}});
  81. DominatorTree DT(*Holder.F);
  82. EXPECT_TRUE(DT.verify());
  83. PostDominatorTree PDT(*Holder.F);
  84. EXPECT_TRUE(PDT.verify());
  85. BasicBlock *B = Builder.getOrAddBlock("B");
  86. BasicBlock *C = Builder.getOrAddBlock("C");
  87. std::vector<DomUpdate> Updates = {{Insert, B, C}};
  88. ASSERT_TRUE(Builder.applyUpdate());
  89. DT.applyUpdates(Updates);
  90. EXPECT_TRUE(DT.verify());
  91. PDT.applyUpdates(Updates);
  92. EXPECT_TRUE(PDT.verify());
  93. }
  94. TEST(DominatorTreeBatchUpdates, SingleDeletion) {
  95. CFGHolder Holder;
  96. CFGBuilder Builder(Holder.F, {{"A", "B"}, {"B", "C"}},
  97. {{CFGDelete, {"B", "C"}}});
  98. DominatorTree DT(*Holder.F);
  99. EXPECT_TRUE(DT.verify());
  100. PostDominatorTree PDT(*Holder.F);
  101. EXPECT_TRUE(PDT.verify());
  102. BasicBlock *B = Builder.getOrAddBlock("B");
  103. BasicBlock *C = Builder.getOrAddBlock("C");
  104. std::vector<DomUpdate> Updates = {{Delete, B, C}};
  105. ASSERT_TRUE(Builder.applyUpdate());
  106. DT.applyUpdates(Updates);
  107. EXPECT_TRUE(DT.verify());
  108. PDT.applyUpdates(Updates);
  109. EXPECT_TRUE(PDT.verify());
  110. }
  111. TEST(DominatorTreeBatchUpdates, FewInsertion) {
  112. std::vector<CFGBuilder::Update> CFGUpdates = {{CFGInsert, {"B", "C"}},
  113. {CFGInsert, {"C", "B"}},
  114. {CFGInsert, {"C", "D"}},
  115. {CFGInsert, {"D", "E"}}};
  116. CFGHolder Holder;
  117. CFGBuilder Builder(Holder.F, {{"A", "B"}}, CFGUpdates);
  118. DominatorTree DT(*Holder.F);
  119. EXPECT_TRUE(DT.verify());
  120. PostDominatorTree PDT(*Holder.F);
  121. EXPECT_TRUE(PDT.verify());
  122. BasicBlock *B = Builder.getOrAddBlock("B");
  123. BasicBlock *C = Builder.getOrAddBlock("C");
  124. BasicBlock *D = Builder.getOrAddBlock("D");
  125. BasicBlock *E = Builder.getOrAddBlock("E");
  126. std::vector<DomUpdate> Updates = {
  127. {Insert, B, C}, {Insert, C, B}, {Insert, C, D}, {Insert, D, E}};
  128. while (Builder.applyUpdate())
  129. ;
  130. DT.applyUpdates(Updates);
  131. EXPECT_TRUE(DT.verify());
  132. PDT.applyUpdates(Updates);
  133. EXPECT_TRUE(PDT.verify());
  134. }
  135. TEST(DominatorTreeBatchUpdates, FewDeletions) {
  136. std::vector<CFGBuilder::Update> CFGUpdates = {{CFGDelete, {"B", "C"}},
  137. {CFGDelete, {"C", "B"}},
  138. {CFGDelete, {"B", "D"}},
  139. {CFGDelete, {"D", "E"}}};
  140. CFGHolder Holder;
  141. CFGBuilder Builder(
  142. Holder.F, {{"A", "B"}, {"B", "C"}, {"B", "D"}, {"D", "E"}, {"C", "B"}},
  143. CFGUpdates);
  144. DominatorTree DT(*Holder.F);
  145. EXPECT_TRUE(DT.verify());
  146. PostDominatorTree PDT(*Holder.F);
  147. EXPECT_TRUE(PDT.verify());
  148. auto Updates = ToDomUpdates(Builder, CFGUpdates);
  149. while (Builder.applyUpdate())
  150. ;
  151. DT.applyUpdates(Updates);
  152. EXPECT_TRUE(DT.verify());
  153. PDT.applyUpdates(Updates);
  154. EXPECT_TRUE(PDT.verify());
  155. }
  156. TEST(DominatorTreeBatchUpdates, InsertDelete) {
  157. std::vector<CFGBuilder::Arc> Arcs = {
  158. {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
  159. {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
  160. std::vector<CFGBuilder::Update> Updates = {
  161. {CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}},
  162. {CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}},
  163. {CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}},
  164. {CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}},
  165. {CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}},
  166. {CFGDelete, {"11", "12"}}};
  167. CFGHolder Holder;
  168. CFGBuilder B(Holder.F, Arcs, Updates);
  169. DominatorTree DT(*Holder.F);
  170. EXPECT_TRUE(DT.verify());
  171. PostDominatorTree PDT(*Holder.F);
  172. EXPECT_TRUE(PDT.verify());
  173. while (B.applyUpdate())
  174. ;
  175. auto DomUpdates = ToDomUpdates(B, Updates);
  176. DT.applyUpdates(DomUpdates);
  177. EXPECT_TRUE(DT.verify());
  178. PDT.applyUpdates(DomUpdates);
  179. EXPECT_TRUE(PDT.verify());
  180. }
  181. TEST(DominatorTreeBatchUpdates, InsertDeleteExhaustive) {
  182. std::vector<CFGBuilder::Arc> Arcs = {
  183. {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
  184. {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
  185. std::vector<CFGBuilder::Update> Updates = {
  186. {CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}},
  187. {CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}},
  188. {CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}},
  189. {CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}},
  190. {CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}},
  191. {CFGDelete, {"11", "12"}}};
  192. std::mt19937 Generator(0);
  193. for (unsigned i = 0; i < 16; ++i) {
  194. std::shuffle(Updates.begin(), Updates.end(), Generator);
  195. CFGHolder Holder;
  196. CFGBuilder B(Holder.F, Arcs, Updates);
  197. DominatorTree DT(*Holder.F);
  198. EXPECT_TRUE(DT.verify());
  199. PostDominatorTree PDT(*Holder.F);
  200. EXPECT_TRUE(PDT.verify());
  201. while (B.applyUpdate())
  202. ;
  203. auto DomUpdates = ToDomUpdates(B, Updates);
  204. DT.applyUpdates(DomUpdates);
  205. EXPECT_TRUE(DT.verify());
  206. PDT.applyUpdates(DomUpdates);
  207. EXPECT_TRUE(PDT.verify());
  208. }
  209. }
  210. // These are some odd flowgraphs, usually generated from csmith cases,
  211. // which are difficult on post dom trees.
  212. TEST(DominatorTreeBatchUpdates, InfiniteLoop) {
  213. std::vector<CFGBuilder::Arc> Arcs = {
  214. {"1", "2"},
  215. {"2", "3"},
  216. {"3", "6"}, {"3", "5"},
  217. {"4", "5"},
  218. {"5", "2"},
  219. {"6", "3"}, {"6", "4"}};
  220. // SplitBlock on 3 -> 5
  221. std::vector<CFGBuilder::Update> Updates = {
  222. {CFGInsert, {"N", "5"}}, {CFGInsert, {"3", "N"}}, {CFGDelete, {"3", "5"}}};
  223. CFGHolder Holder;
  224. CFGBuilder B(Holder.F, Arcs, Updates);
  225. DominatorTree DT(*Holder.F);
  226. EXPECT_TRUE(DT.verify());
  227. PostDominatorTree PDT(*Holder.F);
  228. EXPECT_TRUE(PDT.verify());
  229. while (B.applyUpdate())
  230. ;
  231. auto DomUpdates = ToDomUpdates(B, Updates);
  232. DT.applyUpdates(DomUpdates);
  233. EXPECT_TRUE(DT.verify());
  234. PDT.applyUpdates(DomUpdates);
  235. EXPECT_TRUE(PDT.verify());
  236. }
  237. TEST(DominatorTreeBatchUpdates, DeadBlocks) {
  238. std::vector<CFGBuilder::Arc> Arcs = {
  239. {"1", "2"},
  240. {"2", "3"},
  241. {"3", "4"}, {"3", "7"},
  242. {"4", "4"},
  243. {"5", "6"}, {"5", "7"},
  244. {"6", "7"},
  245. {"7", "2"}, {"7", "8"}};
  246. // Remove dead 5 and 7,
  247. // plus SplitBlock on 7 -> 8
  248. std::vector<CFGBuilder::Update> Updates = {
  249. {CFGDelete, {"6", "7"}}, {CFGDelete, {"5", "7"}}, {CFGDelete, {"5", "6"}},
  250. {CFGInsert, {"N", "8"}}, {CFGInsert, {"7", "N"}}, {CFGDelete, {"7", "8"}}};
  251. CFGHolder Holder;
  252. CFGBuilder B(Holder.F, Arcs, Updates);
  253. DominatorTree DT(*Holder.F);
  254. EXPECT_TRUE(DT.verify());
  255. PostDominatorTree PDT(*Holder.F);
  256. EXPECT_TRUE(PDT.verify());
  257. while (B.applyUpdate())
  258. ;
  259. auto DomUpdates = ToDomUpdates(B, Updates);
  260. DT.applyUpdates(DomUpdates);
  261. EXPECT_TRUE(DT.verify());
  262. PDT.applyUpdates(DomUpdates);
  263. EXPECT_TRUE(PDT.verify());
  264. }
  265. TEST(DominatorTreeBatchUpdates, InfiniteLoop2) {
  266. std::vector<CFGBuilder::Arc> Arcs = {
  267. {"1", "2"},
  268. {"2", "6"}, {"2", "3"},
  269. {"3", "4"},
  270. {"4", "5"}, {"4", "6"},
  271. {"5", "4"},
  272. {"6", "2"}};
  273. // SplitBlock on 4 -> 6
  274. std::vector<CFGBuilder::Update> Updates = {
  275. {CFGInsert, {"N", "6"}}, {CFGInsert, {"4", "N"}}, {CFGDelete, {"4", "6"}}};
  276. CFGHolder Holder;
  277. CFGBuilder B(Holder.F, Arcs, Updates);
  278. DominatorTree DT(*Holder.F);
  279. EXPECT_TRUE(DT.verify());
  280. PostDominatorTree PDT(*Holder.F);
  281. EXPECT_TRUE(PDT.verify());
  282. while (B.applyUpdate())
  283. ;
  284. auto DomUpdates = ToDomUpdates(B, Updates);
  285. DT.applyUpdates(DomUpdates);
  286. EXPECT_TRUE(DT.verify());
  287. PDT.applyUpdates(DomUpdates);
  288. EXPECT_TRUE(PDT.verify());
  289. }