CFGBuilder.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //===- llvm/Testing/Support/CFGBuilder.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 "CFGBuilder.h"
  9. #include "llvm/IR/CFG.h"
  10. #include "llvm/IR/IRBuilder.h"
  11. #include "llvm/IR/LLVMContext.h"
  12. #include "llvm/Support/Debug.h"
  13. #include "llvm/Support/raw_ostream.h"
  14. #include "gtest/gtest.h"
  15. #define DEBUG_TYPE "cfg-builder"
  16. using namespace llvm;
  17. CFGHolder::CFGHolder(StringRef ModuleName, StringRef FunctionName)
  18. : Context(std::make_unique<LLVMContext>()),
  19. M(std::make_unique<Module>(ModuleName, *Context)) {
  20. FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Context), {}, false);
  21. F = Function::Create(FTy, Function::ExternalLinkage, FunctionName, M.get());
  22. }
  23. CFGHolder::~CFGHolder() = default;
  24. CFGBuilder::CFGBuilder(Function *F, const std::vector<Arc> &InitialArcs,
  25. std::vector<Update> Updates)
  26. : F(F), Updates(std::move(Updates)) {
  27. assert(F);
  28. buildCFG(InitialArcs);
  29. }
  30. static void ConnectBlocks(BasicBlock *From, BasicBlock *To) {
  31. LLVM_DEBUG(dbgs() << "Creating BB arc " << From->getName() << " -> "
  32. << To->getName() << "\n";
  33. dbgs().flush());
  34. auto *IntTy = IntegerType::get(From->getContext(), 32);
  35. if (isa<UnreachableInst>(From->getTerminator()))
  36. From->getTerminator()->eraseFromParent();
  37. if (!From->getTerminator()) {
  38. IRBuilder<> IRB(From);
  39. IRB.CreateSwitch(ConstantInt::get(IntTy, 0), To);
  40. return;
  41. }
  42. SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
  43. const auto Last = SI->getNumCases();
  44. auto *IntVal = ConstantInt::get(IntTy, Last);
  45. SI->addCase(IntVal, To);
  46. }
  47. static void DisconnectBlocks(BasicBlock *From, BasicBlock *To) {
  48. LLVM_DEBUG(dbgs() << "Deleting BB arc " << From->getName() << " -> "
  49. << To->getName() << "\n";
  50. dbgs().flush());
  51. SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
  52. if (SI->getNumCases() == 0) {
  53. SI->eraseFromParent();
  54. IRBuilder<> IRB(From);
  55. IRB.CreateUnreachable();
  56. return;
  57. }
  58. if (SI->getDefaultDest() == To) {
  59. auto FirstC = SI->case_begin();
  60. SI->setDefaultDest(FirstC->getCaseSuccessor());
  61. SI->removeCase(FirstC);
  62. return;
  63. }
  64. for (auto CIt = SI->case_begin(); CIt != SI->case_end(); ++CIt)
  65. if (CIt->getCaseSuccessor() == To) {
  66. SI->removeCase(CIt);
  67. return;
  68. }
  69. }
  70. BasicBlock *CFGBuilder::getOrAddBlock(StringRef BlockName) {
  71. auto BIt = NameToBlock.find(BlockName);
  72. if (BIt != NameToBlock.end())
  73. return BIt->second;
  74. auto *BB = BasicBlock::Create(F->getParent()->getContext(), BlockName, F);
  75. IRBuilder<> IRB(BB);
  76. IRB.CreateUnreachable();
  77. NameToBlock[BlockName] = BB;
  78. return BB;
  79. }
  80. bool CFGBuilder::connect(const Arc &A) {
  81. BasicBlock *From = getOrAddBlock(A.From);
  82. BasicBlock *To = getOrAddBlock(A.To);
  83. if (Arcs.count(A) != 0)
  84. return false;
  85. Arcs.insert(A);
  86. ConnectBlocks(From, To);
  87. return true;
  88. }
  89. bool CFGBuilder::disconnect(const Arc &A) {
  90. assert(NameToBlock.count(A.From) != 0 && "No block to disconnect (From)");
  91. assert(NameToBlock.count(A.To) != 0 && "No block to disconnect (To)");
  92. if (Arcs.count(A) == 0)
  93. return false;
  94. BasicBlock *From = getOrAddBlock(A.From);
  95. BasicBlock *To = getOrAddBlock(A.To);
  96. Arcs.erase(A);
  97. DisconnectBlocks(From, To);
  98. return true;
  99. }
  100. void CFGBuilder::buildCFG(const std::vector<Arc> &NewArcs) {
  101. for (const auto &A : NewArcs) {
  102. const bool Connected = connect(A);
  103. (void)Connected;
  104. assert(Connected);
  105. }
  106. }
  107. Optional<CFGBuilder::Update> CFGBuilder::getNextUpdate() const {
  108. if (UpdateIdx == Updates.size())
  109. return None;
  110. return Updates[UpdateIdx];
  111. }
  112. Optional<CFGBuilder::Update> CFGBuilder::applyUpdate() {
  113. if (UpdateIdx == Updates.size())
  114. return None;
  115. Update NextUpdate = Updates[UpdateIdx++];
  116. if (NextUpdate.Action == ActionKind::Insert)
  117. connect(NextUpdate.Edge);
  118. else
  119. disconnect(NextUpdate.Edge);
  120. return NextUpdate;
  121. }
  122. void CFGBuilder::dump(raw_ostream &OS) const {
  123. OS << "Arcs:\n";
  124. size_t i = 0;
  125. for (const auto &A : Arcs)
  126. OS << " " << i++ << ":\t" << A.From << " -> " << A.To << "\n";
  127. OS << "Updates:\n";
  128. i = 0;
  129. for (const auto &U : Updates) {
  130. OS << (i + 1 == UpdateIdx ? "->" : " ") << i
  131. << ((U.Action == ActionKind::Insert) ? "\tIns " : "\tDel ")
  132. << U.Edge.From << " -> " << U.Edge.To << "\n";
  133. ++i;
  134. }
  135. }
  136. //---- CFGBuilder tests ---------------------------------------------------===//
  137. TEST(CFGBuilder, Construction) {
  138. CFGHolder Holder;
  139. std::vector<CFGBuilder::Arc> Arcs = {{"entry", "a"}, {"a", "b"}, {"a", "c"},
  140. {"c", "d"}, {"d", "b"}, {"d", "e"},
  141. {"d", "f"}, {"e", "f"}};
  142. CFGBuilder B(Holder.F, Arcs, {});
  143. EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
  144. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
  145. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
  146. EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
  147. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
  148. auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
  149. // d has 3 successors, but one of them if going to be a default case
  150. EXPECT_EQ(DSwitch->getNumCases(), 2U);
  151. EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
  152. }
  153. TEST(CFGBuilder, Insertions) {
  154. CFGHolder Holder;
  155. const auto Insert = CFGBuilder::ActionKind::Insert;
  156. std::vector<CFGBuilder::Update> Updates = {
  157. {Insert, {"entry", "a"}}, {Insert, {"a", "b"}}, {Insert, {"a", "c"}},
  158. {Insert, {"c", "d"}}, {Insert, {"d", "b"}}, {Insert, {"d", "e"}},
  159. {Insert, {"d", "f"}}, {Insert, {"e", "f"}}};
  160. const size_t NumUpdates = Updates.size();
  161. CFGBuilder B(Holder.F, {}, Updates);
  162. size_t i = 0;
  163. while (B.applyUpdate())
  164. ++i;
  165. EXPECT_EQ(i, NumUpdates);
  166. EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
  167. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
  168. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
  169. EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
  170. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
  171. auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
  172. // d has 3 successors, but one of them if going to be a default case
  173. EXPECT_EQ(DSwitch->getNumCases(), 2U);
  174. EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
  175. }
  176. TEST(CFGBuilder, Deletions) {
  177. CFGHolder Holder;
  178. std::vector<CFGBuilder::Arc> Arcs = {
  179. {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
  180. const auto Delete = CFGBuilder::ActionKind::Delete;
  181. std::vector<CFGBuilder::Update> Updates = {
  182. {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
  183. };
  184. const size_t NumUpdates = Updates.size();
  185. CFGBuilder B(Holder.F, Arcs, Updates);
  186. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
  187. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
  188. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
  189. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
  190. auto UpdateC = B.applyUpdate();
  191. EXPECT_TRUE(UpdateC);
  192. EXPECT_EQ(UpdateC->Action, CFGBuilder::ActionKind::Delete);
  193. EXPECT_EQ(UpdateC->Edge.From, "c");
  194. EXPECT_EQ(UpdateC->Edge.To, "d");
  195. EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("c")->getTerminator()));
  196. size_t i = 1;
  197. while (B.applyUpdate())
  198. ++i;
  199. EXPECT_EQ(i, NumUpdates);
  200. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
  201. EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("entry")->getTerminator()));
  202. }
  203. TEST(CFGBuilder, Rebuild) {
  204. CFGHolder Holder;
  205. std::vector<CFGBuilder::Arc> Arcs = {
  206. {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
  207. const auto Insert = CFGBuilder::ActionKind::Insert;
  208. const auto Delete = CFGBuilder::ActionKind::Delete;
  209. std::vector<CFGBuilder::Update> Updates = {
  210. {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
  211. {Insert, {"c", "d"}}, {Insert, {"a", "c"}}, {Insert, {"entry", "a"}},
  212. };
  213. const size_t NumUpdates = Updates.size();
  214. CFGBuilder B(Holder.F, Arcs, Updates);
  215. size_t i = 0;
  216. while (B.applyUpdate())
  217. ++i;
  218. EXPECT_EQ(i, NumUpdates);
  219. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
  220. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
  221. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
  222. EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
  223. }
  224. static_assert(is_trivially_copyable<succ_iterator>::value,
  225. "trivially copyable");
  226. static_assert(is_trivially_copyable<succ_const_iterator>::value,
  227. "trivially copyable");
  228. static_assert(is_trivially_copyable<succ_range>::value, "trivially copyable");
  229. static_assert(is_trivially_copyable<succ_const_range>::value,
  230. "trivially copyable");