1 //===- llvm/Testing/Support/CFGBuilder.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"
11 #include "llvm/IR/CFG.h"
12 #include "llvm/IR/IRBuilder.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "gtest/gtest.h"
18 #define DEBUG_TYPE "cfg-builder"
22 CFGHolder::CFGHolder(StringRef ModuleName
, StringRef FunctionName
)
23 : Context(llvm::make_unique
<LLVMContext
>()),
24 M(llvm::make_unique
<Module
>(ModuleName
, *Context
)) {
25 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(*Context
), {}, false);
26 F
= Function::Create(FTy
, Function::ExternalLinkage
, FunctionName
, M
.get());
28 CFGHolder::~CFGHolder() = default;
30 CFGBuilder::CFGBuilder(Function
*F
, const std::vector
<Arc
> &InitialArcs
,
31 std::vector
<Update
> Updates
)
32 : F(F
), Updates(std::move(Updates
)) {
34 buildCFG(InitialArcs
);
37 static void ConnectBlocks(BasicBlock
*From
, BasicBlock
*To
) {
38 LLVM_DEBUG(dbgs() << "Creating BB arc " << From
->getName() << " -> "
39 << To
->getName() << "\n";
41 auto *IntTy
= IntegerType::get(From
->getContext(), 32);
43 if (isa
<UnreachableInst
>(From
->getTerminator()))
44 From
->getTerminator()->eraseFromParent();
45 if (!From
->getTerminator()) {
46 IRBuilder
<> IRB(From
);
47 IRB
.CreateSwitch(ConstantInt::get(IntTy
, 0), To
);
51 SwitchInst
*SI
= cast
<SwitchInst
>(From
->getTerminator());
52 const auto Last
= SI
->getNumCases();
54 auto *IntVal
= ConstantInt::get(IntTy
, Last
);
55 SI
->addCase(IntVal
, To
);
58 static void DisconnectBlocks(BasicBlock
*From
, BasicBlock
*To
) {
59 LLVM_DEBUG(dbgs() << "Deleting BB arc " << From
->getName() << " -> "
60 << To
->getName() << "\n";
62 SwitchInst
*SI
= cast
<SwitchInst
>(From
->getTerminator());
64 if (SI
->getNumCases() == 0) {
65 SI
->eraseFromParent();
66 IRBuilder
<> IRB(From
);
67 IRB
.CreateUnreachable();
71 if (SI
->getDefaultDest() == To
) {
72 auto FirstC
= SI
->case_begin();
73 SI
->setDefaultDest(FirstC
->getCaseSuccessor());
74 SI
->removeCase(FirstC
);
78 for (auto CIt
= SI
->case_begin(); CIt
!= SI
->case_end(); ++CIt
)
79 if (CIt
->getCaseSuccessor() == To
) {
85 BasicBlock
*CFGBuilder::getOrAddBlock(StringRef BlockName
) {
86 auto BIt
= NameToBlock
.find(BlockName
);
87 if (BIt
!= NameToBlock
.end())
90 auto *BB
= BasicBlock::Create(F
->getParent()->getContext(), BlockName
, F
);
92 IRB
.CreateUnreachable();
93 NameToBlock
[BlockName
] = BB
;
97 bool CFGBuilder::connect(const Arc
&A
) {
98 BasicBlock
*From
= getOrAddBlock(A
.From
);
99 BasicBlock
*To
= getOrAddBlock(A
.To
);
100 if (Arcs
.count(A
) != 0)
104 ConnectBlocks(From
, To
);
108 bool CFGBuilder::disconnect(const Arc
&A
) {
109 assert(NameToBlock
.count(A
.From
) != 0 && "No block to disconnect (From)");
110 assert(NameToBlock
.count(A
.To
) != 0 && "No block to disconnect (To)");
111 if (Arcs
.count(A
) == 0)
114 BasicBlock
*From
= getOrAddBlock(A
.From
);
115 BasicBlock
*To
= getOrAddBlock(A
.To
);
117 DisconnectBlocks(From
, To
);
121 void CFGBuilder::buildCFG(const std::vector
<Arc
> &NewArcs
) {
122 for (const auto &A
: NewArcs
) {
123 const bool Connected
= connect(A
);
129 Optional
<CFGBuilder::Update
> CFGBuilder::getNextUpdate() const {
130 if (UpdateIdx
== Updates
.size())
132 return Updates
[UpdateIdx
];
135 Optional
<CFGBuilder::Update
> CFGBuilder::applyUpdate() {
136 if (UpdateIdx
== Updates
.size())
138 Update NextUpdate
= Updates
[UpdateIdx
++];
139 if (NextUpdate
.Action
== ActionKind::Insert
)
140 connect(NextUpdate
.Edge
);
142 disconnect(NextUpdate
.Edge
);
147 void CFGBuilder::dump(raw_ostream
&OS
) const {
150 for (const auto &A
: Arcs
)
151 OS
<< " " << i
++ << ":\t" << A
.From
<< " -> " << A
.To
<< "\n";
155 for (const auto &U
: Updates
) {
156 OS
<< (i
+ 1 == UpdateIdx
? "->" : " ") << i
157 << ((U
.Action
== ActionKind::Insert
) ? "\tIns " : "\tDel ")
158 << U
.Edge
.From
<< " -> " << U
.Edge
.To
<< "\n";
163 //---- CFGBuilder tests ---------------------------------------------------===//
165 TEST(CFGBuilder
, Construction
) {
167 std::vector
<CFGBuilder::Arc
> Arcs
= {{"entry", "a"}, {"a", "b"}, {"a", "c"},
168 {"c", "d"}, {"d", "b"}, {"d", "e"},
169 {"d", "f"}, {"e", "f"}};
170 CFGBuilder
B(Holder
.F
, Arcs
, {});
172 EXPECT_TRUE(B
.getOrAddBlock("entry") == &Holder
.F
->getEntryBlock());
173 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("entry")->getTerminator()));
174 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("a")->getTerminator()));
175 EXPECT_TRUE(isa
<UnreachableInst
>(B
.getOrAddBlock("b")->getTerminator()));
176 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator()));
178 auto *DSwitch
= cast
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator());
179 // d has 3 successors, but one of them if going to be a default case
180 EXPECT_EQ(DSwitch
->getNumCases(), 2U);
181 EXPECT_FALSE(B
.getNextUpdate()); // No updates to apply.
184 TEST(CFGBuilder
, Insertions
) {
186 const auto Insert
= CFGBuilder::ActionKind::Insert
;
187 std::vector
<CFGBuilder::Update
> Updates
= {
188 {Insert
, {"entry", "a"}}, {Insert
, {"a", "b"}}, {Insert
, {"a", "c"}},
189 {Insert
, {"c", "d"}}, {Insert
, {"d", "b"}}, {Insert
, {"d", "e"}},
190 {Insert
, {"d", "f"}}, {Insert
, {"e", "f"}}};
191 const size_t NumUpdates
= Updates
.size();
193 CFGBuilder
B(Holder
.F
, {}, Updates
);
196 while (B
.applyUpdate())
198 EXPECT_EQ(i
, NumUpdates
);
200 EXPECT_TRUE(B
.getOrAddBlock("entry") == &Holder
.F
->getEntryBlock());
201 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("entry")->getTerminator()));
202 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("a")->getTerminator()));
203 EXPECT_TRUE(isa
<UnreachableInst
>(B
.getOrAddBlock("b")->getTerminator()));
204 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator()));
206 auto *DSwitch
= cast
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator());
207 // d has 3 successors, but one of them if going to be a default case
208 EXPECT_EQ(DSwitch
->getNumCases(), 2U);
209 EXPECT_FALSE(B
.getNextUpdate()); // No updates to apply.
212 TEST(CFGBuilder
, Deletions
) {
214 std::vector
<CFGBuilder::Arc
> Arcs
= {
215 {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
216 const auto Delete
= CFGBuilder::ActionKind::Delete
;
217 std::vector
<CFGBuilder::Update
> Updates
= {
218 {Delete
, {"c", "d"}}, {Delete
, {"a", "c"}}, {Delete
, {"entry", "a"}},
220 const size_t NumUpdates
= Updates
.size();
222 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
224 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("entry")->getTerminator()));
225 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("a")->getTerminator()));
226 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("c")->getTerminator()));
227 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator()));
229 auto UpdateC
= B
.applyUpdate();
231 EXPECT_TRUE(UpdateC
);
232 EXPECT_EQ(UpdateC
->Action
, CFGBuilder::ActionKind::Delete
);
233 EXPECT_EQ(UpdateC
->Edge
.From
, "c");
234 EXPECT_EQ(UpdateC
->Edge
.To
, "d");
235 EXPECT_TRUE(isa
<UnreachableInst
>(B
.getOrAddBlock("c")->getTerminator()));
238 while (B
.applyUpdate())
240 EXPECT_EQ(i
, NumUpdates
);
242 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("a")->getTerminator()));
243 EXPECT_TRUE(isa
<UnreachableInst
>(B
.getOrAddBlock("entry")->getTerminator()));
246 TEST(CFGBuilder
, Rebuild
) {
248 std::vector
<CFGBuilder::Arc
> Arcs
= {
249 {"entry", "a"}, {"a", "b"}, {"a", "c"}, {"c", "d"}, {"d", "b"}};
250 const auto Insert
= CFGBuilder::ActionKind::Insert
;
251 const auto Delete
= CFGBuilder::ActionKind::Delete
;
252 std::vector
<CFGBuilder::Update
> Updates
= {
253 {Delete
, {"c", "d"}}, {Delete
, {"a", "c"}}, {Delete
, {"entry", "a"}},
254 {Insert
, {"c", "d"}}, {Insert
, {"a", "c"}}, {Insert
, {"entry", "a"}},
256 const size_t NumUpdates
= Updates
.size();
258 CFGBuilder
B(Holder
.F
, Arcs
, Updates
);
260 while (B
.applyUpdate())
262 EXPECT_EQ(i
, NumUpdates
);
264 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("entry")->getTerminator()));
265 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("a")->getTerminator()));
266 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("c")->getTerminator()));
267 EXPECT_TRUE(isa
<SwitchInst
>(B
.getOrAddBlock("d")->getTerminator()));
270 static_assert(is_trivially_copyable
<succ_iterator
>::value
,
271 "trivially copyable");
272 static_assert(is_trivially_copyable
<succ_const_iterator
>::value
,
273 "trivially copyable");
274 static_assert(is_trivially_copyable
<succ_range
>::value
, "trivially copyable");
275 static_assert(is_trivially_copyable
<succ_const_range
>::value
,
276 "trivially copyable");