123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- //===- llvm/Testing/Support/CFGBuilder.cpp --------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "CFGBuilder.h"
- #include "llvm/IR/CFG.h"
- #include "llvm/IR/IRBuilder.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/raw_ostream.h"
- #include "gtest/gtest.h"
- #define DEBUG_TYPE "cfg-builder"
- using namespace llvm;
- CFGHolder::CFGHolder(StringRef ModuleName, StringRef FunctionName)
- : Context(std::make_unique<LLVMContext>()),
- M(std::make_unique<Module>(ModuleName, *Context)) {
- FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Context), {}, false);
- F = Function::Create(FTy, Function::ExternalLinkage, FunctionName, M.get());
- }
- CFGHolder::~CFGHolder() = default;
- CFGBuilder::CFGBuilder(Function *F, const std::vector<Arc> &InitialArcs,
- std::vector<Update> Updates)
- : F(F), Updates(std::move(Updates)) {
- assert(F);
- buildCFG(InitialArcs);
- }
- static void ConnectBlocks(BasicBlock *From, BasicBlock *To) {
- LLVM_DEBUG(dbgs() << "Creating BB arc " << From->getName() << " -> "
- << To->getName() << "\n";
- dbgs().flush());
- auto *IntTy = IntegerType::get(From->getContext(), 32);
- if (isa<UnreachableInst>(From->getTerminator()))
- From->getTerminator()->eraseFromParent();
- if (!From->getTerminator()) {
- IRBuilder<> IRB(From);
- IRB.CreateSwitch(ConstantInt::get(IntTy, 0), To);
- return;
- }
- SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
- const auto Last = SI->getNumCases();
- auto *IntVal = ConstantInt::get(IntTy, Last);
- SI->addCase(IntVal, To);
- }
- static void DisconnectBlocks(BasicBlock *From, BasicBlock *To) {
- LLVM_DEBUG(dbgs() << "Deleting BB arc " << From->getName() << " -> "
- << To->getName() << "\n";
- dbgs().flush());
- SwitchInst *SI = cast<SwitchInst>(From->getTerminator());
- if (SI->getNumCases() == 0) {
- SI->eraseFromParent();
- IRBuilder<> IRB(From);
- IRB.CreateUnreachable();
- return;
- }
- if (SI->getDefaultDest() == To) {
- auto FirstC = SI->case_begin();
- SI->setDefaultDest(FirstC->getCaseSuccessor());
- SI->removeCase(FirstC);
- return;
- }
- for (auto CIt = SI->case_begin(); CIt != SI->case_end(); ++CIt)
- if (CIt->getCaseSuccessor() == To) {
- SI->removeCase(CIt);
- return;
- }
- }
- BasicBlock *CFGBuilder::getOrAddBlock(StringRef BlockName) {
- auto BIt = NameToBlock.find(BlockName);
- if (BIt != NameToBlock.end())
- return BIt->second;
- auto *BB = BasicBlock::Create(F->getParent()->getContext(), BlockName, F);
- IRBuilder<> IRB(BB);
- IRB.CreateUnreachable();
- NameToBlock[BlockName] = BB;
- return BB;
- }
- bool CFGBuilder::connect(const Arc &A) {
- BasicBlock *From = getOrAddBlock(A.From);
- BasicBlock *To = getOrAddBlock(A.To);
- if (Arcs.count(A) != 0)
- return false;
- Arcs.insert(A);
- ConnectBlocks(From, To);
- return true;
- }
- bool CFGBuilder::disconnect(const Arc &A) {
- assert(NameToBlock.count(A.From) != 0 && "No block to disconnect (From)");
- assert(NameToBlock.count(A.To) != 0 && "No block to disconnect (To)");
- if (Arcs.count(A) == 0)
- return false;
- BasicBlock *From = getOrAddBlock(A.From);
- BasicBlock *To = getOrAddBlock(A.To);
- Arcs.erase(A);
- DisconnectBlocks(From, To);
- return true;
- }
- void CFGBuilder::buildCFG(const std::vector<Arc> &NewArcs) {
- for (const auto &A : NewArcs) {
- const bool Connected = connect(A);
- (void)Connected;
- assert(Connected);
- }
- }
- Optional<CFGBuilder::Update> CFGBuilder::getNextUpdate() const {
- if (UpdateIdx == Updates.size())
- return None;
- return Updates[UpdateIdx];
- }
- Optional<CFGBuilder::Update> CFGBuilder::applyUpdate() {
- if (UpdateIdx == Updates.size())
- return None;
- Update NextUpdate = Updates[UpdateIdx++];
- if (NextUpdate.Action == ActionKind::Insert)
- connect(NextUpdate.Edge);
- else
- disconnect(NextUpdate.Edge);
- return NextUpdate;
- }
- void CFGBuilder::dump(raw_ostream &OS) const {
- OS << "Arcs:\n";
- size_t i = 0;
- for (const auto &A : Arcs)
- OS << " " << i++ << ":\t" << A.From << " -> " << A.To << "\n";
- OS << "Updates:\n";
- i = 0;
- for (const auto &U : Updates) {
- OS << (i + 1 == UpdateIdx ? "->" : " ") << i
- << ((U.Action == ActionKind::Insert) ? "\tIns " : "\tDel ")
- << U.Edge.From << " -> " << U.Edge.To << "\n";
- ++i;
- }
- }
- //---- CFGBuilder tests ---------------------------------------------------===//
- TEST(CFGBuilder, Construction) {
- CFGHolder Holder;
- std::vector<CFGBuilder::Arc> Arcs = {{"entry", "a"}, {"a", "b"}, {"a", "c"},
- {"c", "d"}, {"d", "b"}, {"d", "e"},
- {"d", "f"}, {"e", "f"}};
- CFGBuilder B(Holder.F, Arcs, {});
- EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
- EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
- auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
- // d has 3 successors, but one of them if going to be a default case
- EXPECT_EQ(DSwitch->getNumCases(), 2U);
- EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
- }
- TEST(CFGBuilder, Insertions) {
- CFGHolder Holder;
- const auto Insert = CFGBuilder::ActionKind::Insert;
- std::vector<CFGBuilder::Update> Updates = {
- {Insert, {"entry", "a"}}, {Insert, {"a", "b"}}, {Insert, {"a", "c"}},
- {Insert, {"c", "d"}}, {Insert, {"d", "b"}}, {Insert, {"d", "e"}},
- {Insert, {"d", "f"}}, {Insert, {"e", "f"}}};
- const size_t NumUpdates = Updates.size();
- CFGBuilder B(Holder.F, {}, Updates);
- size_t i = 0;
- while (B.applyUpdate())
- ++i;
- EXPECT_EQ(i, NumUpdates);
- EXPECT_TRUE(B.getOrAddBlock("entry") == &Holder.F->getEntryBlock());
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
- EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("b")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
- auto *DSwitch = cast<SwitchInst>(B.getOrAddBlock("d")->getTerminator());
- // d has 3 successors, but one of them if going to be a default case
- EXPECT_EQ(DSwitch->getNumCases(), 2U);
- EXPECT_FALSE(B.getNextUpdate()); // No updates to apply.
- }
- TEST(CFGBuilder, Deletions) {
- CFGHolder Holder;
- std::vector<CFGBuilder::Arc> Arcs = {
- {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
- const auto Delete = CFGBuilder::ActionKind::Delete;
- std::vector<CFGBuilder::Update> Updates = {
- {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
- };
- const size_t NumUpdates = Updates.size();
- CFGBuilder B(Holder.F, Arcs, Updates);
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
- auto UpdateC = B.applyUpdate();
- EXPECT_TRUE(UpdateC);
- EXPECT_EQ(UpdateC->Action, CFGBuilder::ActionKind::Delete);
- EXPECT_EQ(UpdateC->Edge.From, "c");
- EXPECT_EQ(UpdateC->Edge.To, "d");
- EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("c")->getTerminator()));
- size_t i = 1;
- while (B.applyUpdate())
- ++i;
- EXPECT_EQ(i, NumUpdates);
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
- EXPECT_TRUE(isa<UnreachableInst>(B.getOrAddBlock("entry")->getTerminator()));
- }
- TEST(CFGBuilder, Rebuild) {
- CFGHolder Holder;
- std::vector<CFGBuilder::Arc> Arcs = {
- {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
- const auto Insert = CFGBuilder::ActionKind::Insert;
- const auto Delete = CFGBuilder::ActionKind::Delete;
- std::vector<CFGBuilder::Update> Updates = {
- {Delete, {"c", "d"}}, {Delete, {"a", "c"}}, {Delete, {"entry", "a"}},
- {Insert, {"c", "d"}}, {Insert, {"a", "c"}}, {Insert, {"entry", "a"}},
- };
- const size_t NumUpdates = Updates.size();
- CFGBuilder B(Holder.F, Arcs, Updates);
- size_t i = 0;
- while (B.applyUpdate())
- ++i;
- EXPECT_EQ(i, NumUpdates);
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("entry")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("a")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("c")->getTerminator()));
- EXPECT_TRUE(isa<SwitchInst>(B.getOrAddBlock("d")->getTerminator()));
- }
- static_assert(is_trivially_copyable<succ_iterator>::value,
- "trivially copyable");
- static_assert(is_trivially_copyable<succ_const_iterator>::value,
- "trivially copyable");
- static_assert(is_trivially_copyable<succ_range>::value, "trivially copyable");
- static_assert(is_trivially_copyable<succ_const_range>::value,
- "trivially copyable");
|