blob: ab7e0a4ac005b2519924d5d45d2d5d88c0771353 [file] [log] [blame]
Nick Lewycky0b682452013-07-27 01:24:00 +00001//===- CFGTest.cpp - CFG tests --------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Analysis/CFG.h"
11#include "llvm/ADT/OwningPtr.h"
Nick Lewycky0b682452013-07-27 01:24:00 +000012#include "llvm/Analysis/LoopInfo.h"
Chandler Carruth9aca9182014-01-07 12:34:26 +000013#include "llvm/AsmParser/Parser.h"
Chandler Carruth5ad5f152014-01-13 09:26:24 +000014#include "llvm/IR/Dominators.h"
Nick Lewycky0b682452013-07-27 01:24:00 +000015#include "llvm/IR/Function.h"
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000016#include "llvm/IR/LLVMContext.h"
Nick Lewycky0b682452013-07-27 01:24:00 +000017#include "llvm/IR/Module.h"
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000018#include "llvm/Pass.h"
19#include "llvm/PassManager.h"
Nick Lewycky0b682452013-07-27 01:24:00 +000020#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/InstIterator.h"
22#include "llvm/Support/SourceMgr.h"
Nick Lewycky0b682452013-07-27 01:24:00 +000023#include "gtest/gtest.h"
24
25using namespace llvm;
26
27namespace {
28
29// This fixture assists in running the isPotentiallyReachable utility four ways
30// and ensuring it produces the correct answer each time.
31class IsPotentiallyReachableTest : public testing::Test {
32protected:
33 void ParseAssembly(const char *Assembly) {
34 M.reset(new Module("Module", getGlobalContext()));
35
36 SMDiagnostic Error;
37 bool Parsed = ParseAssemblyString(Assembly, M.get(),
38 Error, M->getContext()) == M.get();
39
40 std::string errMsg;
41 raw_string_ostream os(errMsg);
42 Error.print("", os);
43
44 if (!Parsed) {
45 // A failure here means that the test itself is buggy.
46 report_fatal_error(os.str().c_str());
47 }
48
49 Function *F = M->getFunction("test");
50 if (F == NULL)
51 report_fatal_error("Test must have a function named @test");
52
53 A = B = NULL;
54 for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
55 if (I->hasName()) {
56 if (I->getName() == "A")
57 A = &*I;
58 else if (I->getName() == "B")
59 B = &*I;
60 }
61 }
62 if (A == NULL)
63 report_fatal_error("@test must have an instruction %A");
64 if (B == NULL)
65 report_fatal_error("@test must have an instruction %B");
66 }
67
68 void ExpectPath(bool ExpectedResult) {
69 static char ID;
70 class IsPotentiallyReachableTestPass : public FunctionPass {
71 public:
72 IsPotentiallyReachableTestPass(bool ExpectedResult,
73 Instruction *A, Instruction *B)
74 : FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B) {}
75
76 static int initialize() {
77 PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass",
78 "", &ID, 0, true, true);
79 PassRegistry::getPassRegistry()->registerPass(*PI, false);
80 initializeLoopInfoPass(*PassRegistry::getPassRegistry());
Chandler Carruth73523022014-01-13 13:07:17 +000081 initializeDominatorTreeWrapperPassPass(
82 *PassRegistry::getPassRegistry());
Nick Lewycky0b682452013-07-27 01:24:00 +000083 return 0;
84 }
85
86 void getAnalysisUsage(AnalysisUsage &AU) const {
87 AU.setPreservesAll();
88 AU.addRequired<LoopInfo>();
Chandler Carruth73523022014-01-13 13:07:17 +000089 AU.addRequired<DominatorTreeWrapperPass>();
Nick Lewycky0b682452013-07-27 01:24:00 +000090 }
91
92 bool runOnFunction(Function &F) {
93 if (!F.hasName() || F.getName() != "test")
94 return false;
95
96 LoopInfo *LI = &getAnalysis<LoopInfo>();
Chandler Carruth73523022014-01-13 13:07:17 +000097 DominatorTree *DT =
98 &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
Nick Lewycky0b682452013-07-27 01:24:00 +000099 EXPECT_EQ(isPotentiallyReachable(A, B, 0, 0), ExpectedResult);
100 EXPECT_EQ(isPotentiallyReachable(A, B, DT, 0), ExpectedResult);
101 EXPECT_EQ(isPotentiallyReachable(A, B, 0, LI), ExpectedResult);
102 EXPECT_EQ(isPotentiallyReachable(A, B, DT, LI), ExpectedResult);
103 return false;
104 }
105 bool ExpectedResult;
106 Instruction *A, *B;
107 };
108
109 static int initialize = IsPotentiallyReachableTestPass::initialize();
110 (void)initialize;
111
112 IsPotentiallyReachableTestPass *P =
113 new IsPotentiallyReachableTestPass(ExpectedResult, A, B);
114 PassManager PM;
115 PM.add(P);
116 PM.run(*M);
117 }
Benjamin Kramer3c29c072014-02-10 14:17:42 +0000118
Nick Lewycky0b682452013-07-27 01:24:00 +0000119 OwningPtr<Module> M;
120 Instruction *A, *B;
121};
122
123}
124
125TEST_F(IsPotentiallyReachableTest, SameBlockNoPath) {
126 ParseAssembly(
127 "define void @test() {\n"
128 "entry:\n"
129 " bitcast i8 undef to i8\n"
130 " %B = bitcast i8 undef to i8\n"
131 " bitcast i8 undef to i8\n"
132 " bitcast i8 undef to i8\n"
133 " %A = bitcast i8 undef to i8\n"
134 " ret void\n"
135 "}\n");
136 ExpectPath(false);
137}
138
139TEST_F(IsPotentiallyReachableTest, SameBlockPath) {
140 ParseAssembly(
141 "define void @test() {\n"
142 "entry:\n"
143 " %A = bitcast i8 undef to i8\n"
144 " bitcast i8 undef to i8\n"
145 " bitcast i8 undef to i8\n"
146 " %B = bitcast i8 undef to i8\n"
147 " ret void\n"
148 "}\n");
149 ExpectPath(true);
150}
151
Nick Lewycky8d2e86d2013-08-13 00:03:47 +0000152TEST_F(IsPotentiallyReachableTest, SameBlockNoLoop) {
153 ParseAssembly(
154 "define void @test() {\n"
155 "entry:\n"
156 " br label %middle\n"
157 "middle:\n"
158 " %B = bitcast i8 undef to i8\n"
159 " bitcast i8 undef to i8\n"
160 " bitcast i8 undef to i8\n"
161 " %A = bitcast i8 undef to i8\n"
162 " br label %nextblock\n"
163 "nextblock:\n"
164 " ret void\n"
165 "}\n");
166 ExpectPath(false);
167}
168
Nick Lewycky0b682452013-07-27 01:24:00 +0000169TEST_F(IsPotentiallyReachableTest, StraightNoPath) {
170 ParseAssembly(
171 "define void @test() {\n"
172 "entry:\n"
173 " %B = bitcast i8 undef to i8\n"
174 " br label %exit\n"
175 "exit:\n"
176 " %A = bitcast i8 undef to i8\n"
177 " ret void\n"
178 "}");
179 ExpectPath(false);
180}
181
182TEST_F(IsPotentiallyReachableTest, StraightPath) {
183 ParseAssembly(
184 "define void @test() {\n"
185 "entry:\n"
186 " %A = bitcast i8 undef to i8\n"
187 " br label %exit\n"
188 "exit:\n"
189 " %B = bitcast i8 undef to i8\n"
190 " ret void\n"
191 "}");
192 ExpectPath(true);
193}
194
195TEST_F(IsPotentiallyReachableTest, DestUnreachable) {
196 ParseAssembly(
197 "define void @test() {\n"
198 "entry:\n"
199 " br label %midblock\n"
200 "midblock:\n"
201 " %A = bitcast i8 undef to i8\n"
202 " ret void\n"
203 "unreachable:\n"
204 " %B = bitcast i8 undef to i8\n"
205 " br label %midblock\n"
206 "}");
207 ExpectPath(false);
208}
209
210TEST_F(IsPotentiallyReachableTest, BranchToReturn) {
211 ParseAssembly(
212 "define void @test(i1 %x) {\n"
213 "entry:\n"
214 " %A = bitcast i8 undef to i8\n"
215 " br i1 %x, label %block1, label %block2\n"
216 "block1:\n"
217 " ret void\n"
218 "block2:\n"
219 " %B = bitcast i8 undef to i8\n"
220 " ret void\n"
221 "}");
222 ExpectPath(true);
223}
224
225TEST_F(IsPotentiallyReachableTest, SimpleLoop1) {
226 ParseAssembly(
227 "declare i1 @switch()\n"
228 "\n"
229 "define void @test() {\n"
230 "entry:\n"
231 " br label %loop\n"
232 "loop:\n"
233 " %B = bitcast i8 undef to i8\n"
234 " %A = bitcast i8 undef to i8\n"
235 " %x = call i1 @switch()\n"
236 " br i1 %x, label %loop, label %exit\n"
237 "exit:\n"
238 " ret void\n"
239 "}");
240 ExpectPath(true);
241}
242
243TEST_F(IsPotentiallyReachableTest, SimpleLoop2) {
244 ParseAssembly(
245 "declare i1 @switch()\n"
246 "\n"
247 "define void @test() {\n"
248 "entry:\n"
249 " %B = bitcast i8 undef to i8\n"
250 " br label %loop\n"
251 "loop:\n"
252 " %A = bitcast i8 undef to i8\n"
253 " %x = call i1 @switch()\n"
254 " br i1 %x, label %loop, label %exit\n"
255 "exit:\n"
256 " ret void\n"
257 "}");
258 ExpectPath(false);
259}
260
261TEST_F(IsPotentiallyReachableTest, SimpleLoop3) {
262 ParseAssembly(
263 "declare i1 @switch()\n"
264 "\n"
265 "define void @test() {\n"
266 "entry:\n"
267 " br label %loop\n"
268 "loop:\n"
269 " %B = bitcast i8 undef to i8\n"
270 " %x = call i1 @switch()\n"
271 " br i1 %x, label %loop, label %exit\n"
272 "exit:\n"
273 " %A = bitcast i8 undef to i8\n"
274 " ret void\n"
275 "}");
276 ExpectPath(false);
277}
278
279
280TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther1) {
281 ParseAssembly(
282 "declare i1 @switch()\n"
283 "\n"
284 "define void @test() {\n"
285 "entry:\n"
286 " br label %loop1\n"
287 "loop1:\n"
288 " %A = bitcast i8 undef to i8\n"
289 " %x = call i1 @switch()\n"
290 " br i1 %x, label %loop1, label %loop1exit\n"
291 "loop1exit:\n"
292 " br label %loop2\n"
293 "loop2:\n"
294 " %B = bitcast i8 undef to i8\n"
295 " %y = call i1 @switch()\n"
296 " br i1 %x, label %loop2, label %loop2exit\n"
297 "loop2exit:"
298 " ret void\n"
299 "}");
300 ExpectPath(true);
301}
302
303TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther2) {
304 ParseAssembly(
305 "declare i1 @switch()\n"
306 "\n"
307 "define void @test() {\n"
308 "entry:\n"
309 " br label %loop1\n"
310 "loop1:\n"
311 " %B = bitcast i8 undef to i8\n"
312 " %x = call i1 @switch()\n"
313 " br i1 %x, label %loop1, label %loop1exit\n"
314 "loop1exit:\n"
315 " br label %loop2\n"
316 "loop2:\n"
317 " %A = bitcast i8 undef to i8\n"
318 " %y = call i1 @switch()\n"
319 " br i1 %x, label %loop2, label %loop2exit\n"
320 "loop2exit:"
321 " ret void\n"
322 "}");
323 ExpectPath(false);
324}
325
326TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOtherInsideAThirdLoop) {
327 ParseAssembly(
328 "declare i1 @switch()\n"
329 "\n"
330 "define void @test() {\n"
331 "entry:\n"
332 " br label %outerloop3\n"
333 "outerloop3:\n"
334 " br label %innerloop1\n"
335 "innerloop1:\n"
336 " %B = bitcast i8 undef to i8\n"
337 " %x = call i1 @switch()\n"
338 " br i1 %x, label %innerloop1, label %innerloop1exit\n"
339 "innerloop1exit:\n"
340 " br label %innerloop2\n"
341 "innerloop2:\n"
342 " %A = bitcast i8 undef to i8\n"
343 " %y = call i1 @switch()\n"
344 " br i1 %x, label %innerloop2, label %innerloop2exit\n"
345 "innerloop2exit:"
346 " ;; In outer loop3 now.\n"
347 " %z = call i1 @switch()\n"
348 " br i1 %z, label %outerloop3, label %exit\n"
349 "exit:\n"
350 " ret void\n"
351 "}");
352 ExpectPath(true);
353}
354
Benjamin Kramer3c29c072014-02-10 14:17:42 +0000355static const char *BranchInsideLoopIR =
356 "declare i1 @switch()\n"
357 "\n"
358 "define void @test() {\n"
359 "entry:\n"
360 " br label %loop\n"
361 "loop:\n"
362 " %x = call i1 @switch()\n"
363 " br i1 %x, label %nextloopblock, label %exit\n"
364 "nextloopblock:\n"
365 " %y = call i1 @switch()\n"
366 " br i1 %y, label %left, label %right\n"
367 "left:\n"
368 " %A = bitcast i8 undef to i8\n"
369 " br label %loop\n"
370 "right:\n"
371 " %B = bitcast i8 undef to i8\n"
372 " br label %loop\n"
373 "exit:\n"
374 " ret void\n"
375 "}";
376
Nick Lewycky0b682452013-07-27 01:24:00 +0000377TEST_F(IsPotentiallyReachableTest, BranchInsideLoop) {
Benjamin Kramer3c29c072014-02-10 14:17:42 +0000378 ParseAssembly(BranchInsideLoopIR);
379 ExpectPath(true);
380}
381
382TEST_F(IsPotentiallyReachableTest, ModifyTest) {
383 ParseAssembly(BranchInsideLoopIR);
384
385 succ_iterator S = succ_begin(++M->getFunction("test")->begin());
386 BasicBlock *OldBB = S[0];
387 S[0] = S[1];
388 ExpectPath(false);
389 S[0] = OldBB;
Nick Lewycky0b682452013-07-27 01:24:00 +0000390 ExpectPath(true);
391}