xref: /llvm-project/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp (revision 78dc64989c2f5c075ca74af9dac0c1cb4a2b1f4b)
1ae8a8c2dSTsang Whitney W.H //===- CodeMoverUtils.cpp - Unit tests for CodeMoverUtils ---------------===//
2ae8a8c2dSTsang Whitney W.H //
3ae8a8c2dSTsang Whitney W.H // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ae8a8c2dSTsang Whitney W.H // See https://llvm.org/LICENSE.txt for license information.
5ae8a8c2dSTsang Whitney W.H // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ae8a8c2dSTsang Whitney W.H //
7ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===//
8ae8a8c2dSTsang Whitney W.H 
9ae8a8c2dSTsang Whitney W.H #include "llvm/Transforms/Utils/CodeMoverUtils.h"
10ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/AssumptionCache.h"
11ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h"
12ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/LoopInfo.h"
13ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h"
14b8a3c34eSFlorian Hahn #include "llvm/Analysis/ScalarEvolutionExpander.h"
15ae8a8c2dSTsang Whitney W.H #include "llvm/AsmParser/Parser.h"
16ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h"
17ae8a8c2dSTsang Whitney W.H #include "llvm/IR/LLVMContext.h"
18ae8a8c2dSTsang Whitney W.H #include "llvm/Support/SourceMgr.h"
19ae8a8c2dSTsang Whitney W.H #include "gtest/gtest.h"
20ae8a8c2dSTsang Whitney W.H 
21ae8a8c2dSTsang Whitney W.H using namespace llvm;
22ae8a8c2dSTsang Whitney W.H 
23ae8a8c2dSTsang Whitney W.H static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
24ae8a8c2dSTsang Whitney W.H   SMDiagnostic Err;
25ae8a8c2dSTsang Whitney W.H   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
26ae8a8c2dSTsang Whitney W.H   if (!Mod)
27ae8a8c2dSTsang Whitney W.H     Err.print("CodeMoverUtilsTests", errs());
28ae8a8c2dSTsang Whitney W.H   return Mod;
29ae8a8c2dSTsang Whitney W.H }
30ae8a8c2dSTsang Whitney W.H 
31ae8a8c2dSTsang Whitney W.H static void run(Module &M, StringRef FuncName,
32ae8a8c2dSTsang Whitney W.H                 function_ref<void(Function &F, DominatorTree &DT,
33ae8a8c2dSTsang Whitney W.H                                   PostDominatorTree &PDT, DependenceInfo &DI)>
34ae8a8c2dSTsang Whitney W.H                     Test) {
35ae8a8c2dSTsang Whitney W.H   auto *F = M.getFunction(FuncName);
36ae8a8c2dSTsang Whitney W.H   DominatorTree DT(*F);
37ae8a8c2dSTsang Whitney W.H   PostDominatorTree PDT(*F);
38ae8a8c2dSTsang Whitney W.H   TargetLibraryInfoImpl TLII;
39ae8a8c2dSTsang Whitney W.H   TargetLibraryInfo TLI(TLII);
40ae8a8c2dSTsang Whitney W.H   AssumptionCache AC(*F);
41ae8a8c2dSTsang Whitney W.H   AliasAnalysis AA(TLI);
42ae8a8c2dSTsang Whitney W.H   LoopInfo LI(DT);
43ae8a8c2dSTsang Whitney W.H   ScalarEvolution SE(*F, TLI, AC, DT, LI);
44ae8a8c2dSTsang Whitney W.H   DependenceInfo DI(F, &AA, &SE, &LI);
45ae8a8c2dSTsang Whitney W.H   Test(*F, DT, PDT, DI);
46ae8a8c2dSTsang Whitney W.H }
47ae8a8c2dSTsang Whitney W.H 
48*78dc6498SWhitney Tsang static BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
49*78dc6498SWhitney Tsang   for (BasicBlock &BB : F)
50*78dc6498SWhitney Tsang     if (BB.getName() == Name)
51*78dc6498SWhitney Tsang       return &BB;
52*78dc6498SWhitney Tsang   llvm_unreachable("Expected to find basic block!");
53*78dc6498SWhitney Tsang }
54*78dc6498SWhitney Tsang 
55*78dc6498SWhitney Tsang static Instruction *getInstructionByName(Function &F, StringRef Name) {
56*78dc6498SWhitney Tsang   for (BasicBlock &BB : F)
57*78dc6498SWhitney Tsang     for (Instruction &I : BB)
58*78dc6498SWhitney Tsang       if (I.getName() == Name)
59*78dc6498SWhitney Tsang         return &I;
60*78dc6498SWhitney Tsang   llvm_unreachable("Expected to find instruction!");
61*78dc6498SWhitney Tsang }
62*78dc6498SWhitney Tsang 
63*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentSimpleTest) {
64*78dc6498SWhitney Tsang   LLVMContext C;
65*78dc6498SWhitney Tsang 
66*78dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
67*78dc6498SWhitney Tsang   //   if (cond1)
68*78dc6498SWhitney Tsang   //     i = 1;
69*78dc6498SWhitney Tsang   //   if (cond1)
70*78dc6498SWhitney Tsang   //     i = 2;
71*78dc6498SWhitney Tsang   //   if (cond2)
72*78dc6498SWhitney Tsang   //     i = 3;
73*78dc6498SWhitney Tsang   // }
74*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
75*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
76*78dc6498SWhitney Tsang                  entry:
77*78dc6498SWhitney Tsang                    br i1 %cond1, label %if.first, label %if.first.end
78*78dc6498SWhitney Tsang                  if.first:
79*78dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
80*78dc6498SWhitney Tsang                    br label %if.first.end
81*78dc6498SWhitney Tsang                  if.first.end:
82*78dc6498SWhitney Tsang                    br i1 %cond1, label %if.second, label %if.second.end
83*78dc6498SWhitney Tsang                  if.second:
84*78dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
85*78dc6498SWhitney Tsang                    br label %if.second.end
86*78dc6498SWhitney Tsang                  if.second.end:
87*78dc6498SWhitney Tsang                    br i1 %cond2, label %if.third, label %if.third.end
88*78dc6498SWhitney Tsang                  if.third:
89*78dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
90*78dc6498SWhitney Tsang                    br label %if.third.end
91*78dc6498SWhitney Tsang                  if.third.end:
92*78dc6498SWhitney Tsang                    ret void
93*78dc6498SWhitney Tsang                  })");
94*78dc6498SWhitney Tsang   run(*M, "foo",
95*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
96*78dc6498SWhitney Tsang           DependenceInfo &DI) {
97*78dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
98*78dc6498SWhitney Tsang         EXPECT_TRUE(
99*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *FirstIfBody, DT, PDT));
100*78dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
101*78dc6498SWhitney Tsang         EXPECT_TRUE(
102*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
103*78dc6498SWhitney Tsang 
104*78dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
105*78dc6498SWhitney Tsang         EXPECT_FALSE(
106*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
107*78dc6498SWhitney Tsang         EXPECT_FALSE(
108*78dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
109*78dc6498SWhitney Tsang       });
110*78dc6498SWhitney Tsang }
111*78dc6498SWhitney Tsang 
112*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentOppositeCondTest) {
113*78dc6498SWhitney Tsang   LLVMContext C;
114*78dc6498SWhitney Tsang 
115*78dc6498SWhitney Tsang   // void foo(int &i, unsigned X, unsigned Y) {
116*78dc6498SWhitney Tsang   //   if (X < Y)
117*78dc6498SWhitney Tsang   //     i = 1;
118*78dc6498SWhitney Tsang   //   if (Y > X)
119*78dc6498SWhitney Tsang   //     i = 2;
120*78dc6498SWhitney Tsang   //   if (X >= Y)
121*78dc6498SWhitney Tsang   //     i = 3;
122*78dc6498SWhitney Tsang   //   else
123*78dc6498SWhitney Tsang   //     i = 4;
124*78dc6498SWhitney Tsang   //   if (X == Y)
125*78dc6498SWhitney Tsang   //     i = 5;
126*78dc6498SWhitney Tsang   //   if (Y == X)
127*78dc6498SWhitney Tsang   //     i = 6;
128*78dc6498SWhitney Tsang   //   else
129*78dc6498SWhitney Tsang   //     i = 7;
130*78dc6498SWhitney Tsang   //   if (X != Y)
131*78dc6498SWhitney Tsang   //     i = 8;
132*78dc6498SWhitney Tsang   //   else
133*78dc6498SWhitney Tsang   //     i = 9;
134*78dc6498SWhitney Tsang   // }
135*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
136*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i32 %X, i32 %Y) {
137*78dc6498SWhitney Tsang                  entry:
138*78dc6498SWhitney Tsang                    %cmp1 = icmp ult i32 %X, %Y
139*78dc6498SWhitney Tsang                    br i1 %cmp1, label %if.first, label %if.first.end
140*78dc6498SWhitney Tsang                  if.first:
141*78dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
142*78dc6498SWhitney Tsang                    br label %if.first.end
143*78dc6498SWhitney Tsang                  if.first.end:
144*78dc6498SWhitney Tsang                    %cmp2 = icmp ugt i32 %Y, %X
145*78dc6498SWhitney Tsang                    br i1 %cmp2, label %if.second, label %if.second.end
146*78dc6498SWhitney Tsang                  if.second:
147*78dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
148*78dc6498SWhitney Tsang                    br label %if.second.end
149*78dc6498SWhitney Tsang                  if.second.end:
150*78dc6498SWhitney Tsang                    %cmp3 = icmp uge i32 %X, %Y
151*78dc6498SWhitney Tsang                    br i1 %cmp3, label %if.third, label %if.third.else
152*78dc6498SWhitney Tsang                  if.third:
153*78dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
154*78dc6498SWhitney Tsang                    br label %if.third.end
155*78dc6498SWhitney Tsang                  if.third.else:
156*78dc6498SWhitney Tsang                    store i32 4, i32* %i, align 4
157*78dc6498SWhitney Tsang                    br label %if.third.end
158*78dc6498SWhitney Tsang                  if.third.end:
159*78dc6498SWhitney Tsang                    %cmp4 = icmp eq i32 %X, %Y
160*78dc6498SWhitney Tsang                    br i1 %cmp4, label %if.fourth, label %if.fourth.end
161*78dc6498SWhitney Tsang                  if.fourth:
162*78dc6498SWhitney Tsang                    store i32 5, i32* %i, align 4
163*78dc6498SWhitney Tsang                    br label %if.fourth.end
164*78dc6498SWhitney Tsang                  if.fourth.end:
165*78dc6498SWhitney Tsang                    %cmp5 = icmp eq i32 %Y, %X
166*78dc6498SWhitney Tsang                    br i1 %cmp5, label %if.fifth, label %if.fifth.else
167*78dc6498SWhitney Tsang                  if.fifth:
168*78dc6498SWhitney Tsang                    store i32 6, i32* %i, align 4
169*78dc6498SWhitney Tsang                    br label %if.fifth.end
170*78dc6498SWhitney Tsang                  if.fifth.else:
171*78dc6498SWhitney Tsang                    store i32 7, i32* %i, align 4
172*78dc6498SWhitney Tsang                    br label %if.fifth.end
173*78dc6498SWhitney Tsang                  if.fifth.end:
174*78dc6498SWhitney Tsang                    %cmp6 = icmp ne i32 %X, %Y
175*78dc6498SWhitney Tsang                    br i1 %cmp6, label %if.sixth, label %if.sixth.else
176*78dc6498SWhitney Tsang                  if.sixth:
177*78dc6498SWhitney Tsang                    store i32 8, i32* %i, align 4
178*78dc6498SWhitney Tsang                    br label %if.sixth.end
179*78dc6498SWhitney Tsang                  if.sixth.else:
180*78dc6498SWhitney Tsang                    store i32 9, i32* %i, align 4
181*78dc6498SWhitney Tsang                    br label %if.sixth.end
182*78dc6498SWhitney Tsang                  if.sixth.end:
183*78dc6498SWhitney Tsang                    ret void
184*78dc6498SWhitney Tsang                  })");
185*78dc6498SWhitney Tsang   run(*M, "foo",
186*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
187*78dc6498SWhitney Tsang           DependenceInfo &DI) {
188*78dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
189*78dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
190*78dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
191*78dc6498SWhitney Tsang         BasicBlock *ThirdElseBody = getBasicBlockByName(F, "if.third.else");
192*78dc6498SWhitney Tsang         EXPECT_TRUE(
193*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdElseBody, DT, PDT));
194*78dc6498SWhitney Tsang         EXPECT_TRUE(
195*78dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdElseBody, DT, PDT));
196*78dc6498SWhitney Tsang         EXPECT_FALSE(
197*78dc6498SWhitney Tsang             isControlFlowEquivalent(*ThirdIfBody, *ThirdElseBody, DT, PDT));
198*78dc6498SWhitney Tsang 
199*78dc6498SWhitney Tsang         BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
200*78dc6498SWhitney Tsang         BasicBlock *FifthIfBody = getBasicBlockByName(F, "if.fifth");
201*78dc6498SWhitney Tsang         BasicBlock *FifthElseBody = getBasicBlockByName(F, "if.fifth.else");
202*78dc6498SWhitney Tsang         EXPECT_FALSE(
203*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthIfBody, *FifthElseBody, DT, PDT));
204*78dc6498SWhitney Tsang         BasicBlock *SixthIfBody = getBasicBlockByName(F, "if.sixth");
205*78dc6498SWhitney Tsang         EXPECT_TRUE(
206*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthElseBody, *SixthIfBody, DT, PDT));
207*78dc6498SWhitney Tsang         BasicBlock *SixthElseBody = getBasicBlockByName(F, "if.sixth.else");
208*78dc6498SWhitney Tsang         EXPECT_TRUE(
209*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FourthIfBody, *SixthElseBody, DT, PDT));
210*78dc6498SWhitney Tsang         EXPECT_TRUE(
211*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthIfBody, *SixthElseBody, DT, PDT));
212*78dc6498SWhitney Tsang       });
213*78dc6498SWhitney Tsang }
214*78dc6498SWhitney Tsang 
215*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentCondNestTest) {
216*78dc6498SWhitney Tsang   LLVMContext C;
217*78dc6498SWhitney Tsang 
218*78dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
219*78dc6498SWhitney Tsang   //   if (cond1)
220*78dc6498SWhitney Tsang   //     if (cond2)
221*78dc6498SWhitney Tsang   //       i = 1;
222*78dc6498SWhitney Tsang   //   if (cond2)
223*78dc6498SWhitney Tsang   //     if (cond1)
224*78dc6498SWhitney Tsang   //       i = 2;
225*78dc6498SWhitney Tsang   // }
226*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
227*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
228*78dc6498SWhitney Tsang          entry:
229*78dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.first, label %if.first.end
230*78dc6498SWhitney Tsang          if.outer.first:
231*78dc6498SWhitney Tsang            br i1 %cond2, label %if.inner.first, label %if.first.end
232*78dc6498SWhitney Tsang          if.inner.first:
233*78dc6498SWhitney Tsang            store i32 1, i32* %i, align 4
234*78dc6498SWhitney Tsang            br label %if.first.end
235*78dc6498SWhitney Tsang          if.first.end:
236*78dc6498SWhitney Tsang            br i1 %cond2, label %if.outer.second, label %if.second.end
237*78dc6498SWhitney Tsang          if.outer.second:
238*78dc6498SWhitney Tsang            br i1 %cond1, label %if.inner.second, label %if.second.end
239*78dc6498SWhitney Tsang          if.inner.second:
240*78dc6498SWhitney Tsang            store i32 2, i32* %i, align 4
241*78dc6498SWhitney Tsang            br label %if.second.end
242*78dc6498SWhitney Tsang          if.second.end:
243*78dc6498SWhitney Tsang            ret void
244*78dc6498SWhitney Tsang          })");
245*78dc6498SWhitney Tsang   run(*M, "foo",
246*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
247*78dc6498SWhitney Tsang           DependenceInfo &DI) {
248*78dc6498SWhitney Tsang         BasicBlock *FirstOuterIfBody = getBasicBlockByName(F, "if.outer.first");
249*78dc6498SWhitney Tsang         BasicBlock *FirstInnerIfBody = getBasicBlockByName(F, "if.inner.first");
250*78dc6498SWhitney Tsang         BasicBlock *SecondOuterIfBody =
251*78dc6498SWhitney Tsang             getBasicBlockByName(F, "if.outer.second");
252*78dc6498SWhitney Tsang         BasicBlock *SecondInnerIfBody =
253*78dc6498SWhitney Tsang             getBasicBlockByName(F, "if.inner.second");
254*78dc6498SWhitney Tsang         EXPECT_TRUE(isControlFlowEquivalent(*FirstInnerIfBody,
255*78dc6498SWhitney Tsang                                             *SecondInnerIfBody, DT, PDT));
256*78dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
257*78dc6498SWhitney Tsang                                              *SecondOuterIfBody, DT, PDT));
258*78dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
259*78dc6498SWhitney Tsang                                              *SecondInnerIfBody, DT, PDT));
260*78dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstInnerIfBody,
261*78dc6498SWhitney Tsang                                              *SecondOuterIfBody, DT, PDT));
262*78dc6498SWhitney Tsang       });
263*78dc6498SWhitney Tsang }
264*78dc6498SWhitney Tsang 
265*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentImbalanceTest) {
266*78dc6498SWhitney Tsang   LLVMContext C;
267*78dc6498SWhitney Tsang 
268*78dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
269*78dc6498SWhitney Tsang   //   if (cond1)
270*78dc6498SWhitney Tsang   //     if (cond2)
271*78dc6498SWhitney Tsang   //       if (cond3)
272*78dc6498SWhitney Tsang   //         i = 1;
273*78dc6498SWhitney Tsang   //   if (cond2)
274*78dc6498SWhitney Tsang   //     if (cond3)
275*78dc6498SWhitney Tsang   //       i = 2;
276*78dc6498SWhitney Tsang   //   if (cond1)
277*78dc6498SWhitney Tsang   //     if (cond1)
278*78dc6498SWhitney Tsang   //       i = 3;
279*78dc6498SWhitney Tsang   //   if (cond1)
280*78dc6498SWhitney Tsang   //     i = 4;
281*78dc6498SWhitney Tsang   // }
282*78dc6498SWhitney Tsang   std::unique_ptr<Module> M = parseIR(
283*78dc6498SWhitney Tsang       C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2, i1 %cond3) {
284*78dc6498SWhitney Tsang          entry:
285*78dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.first, label %if.first.end
286*78dc6498SWhitney Tsang          if.outer.first:
287*78dc6498SWhitney Tsang            br i1 %cond2, label %if.middle.first, label %if.first.end
288*78dc6498SWhitney Tsang          if.middle.first:
289*78dc6498SWhitney Tsang            br i1 %cond3, label %if.inner.first, label %if.first.end
290*78dc6498SWhitney Tsang          if.inner.first:
291*78dc6498SWhitney Tsang            store i32 1, i32* %i, align 4
292*78dc6498SWhitney Tsang            br label %if.first.end
293*78dc6498SWhitney Tsang          if.first.end:
294*78dc6498SWhitney Tsang            br i1 %cond2, label %if.outer.second, label %if.second.end
295*78dc6498SWhitney Tsang          if.outer.second:
296*78dc6498SWhitney Tsang            br i1 %cond3, label %if.inner.second, label %if.second.end
297*78dc6498SWhitney Tsang          if.inner.second:
298*78dc6498SWhitney Tsang            store i32 2, i32* %i, align 4
299*78dc6498SWhitney Tsang            br label %if.second.end
300*78dc6498SWhitney Tsang          if.second.end:
301*78dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.third, label %if.third.end
302*78dc6498SWhitney Tsang          if.outer.third:
303*78dc6498SWhitney Tsang            br i1 %cond1, label %if.inner.third, label %if.third.end
304*78dc6498SWhitney Tsang          if.inner.third:
305*78dc6498SWhitney Tsang            store i32 3, i32* %i, align 4
306*78dc6498SWhitney Tsang            br label %if.third.end
307*78dc6498SWhitney Tsang          if.third.end:
308*78dc6498SWhitney Tsang            br i1 %cond1, label %if.fourth, label %if.fourth.end
309*78dc6498SWhitney Tsang          if.fourth:
310*78dc6498SWhitney Tsang            store i32 4, i32* %i, align 4
311*78dc6498SWhitney Tsang            br label %if.fourth.end
312*78dc6498SWhitney Tsang          if.fourth.end:
313*78dc6498SWhitney Tsang            ret void
314*78dc6498SWhitney Tsang          })");
315*78dc6498SWhitney Tsang   run(*M, "foo",
316*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
317*78dc6498SWhitney Tsang           DependenceInfo &DI) {
318*78dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.inner.first");
319*78dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.inner.second");
320*78dc6498SWhitney Tsang         EXPECT_FALSE(
321*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
322*78dc6498SWhitney Tsang 
323*78dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.inner.third");
324*78dc6498SWhitney Tsang         BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
325*78dc6498SWhitney Tsang         EXPECT_TRUE(
326*78dc6498SWhitney Tsang             isControlFlowEquivalent(*ThirdIfBody, *FourthIfBody, DT, PDT));
327*78dc6498SWhitney Tsang       });
328*78dc6498SWhitney Tsang }
329*78dc6498SWhitney Tsang 
330*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentPointerTest) {
331*78dc6498SWhitney Tsang   LLVMContext C;
332*78dc6498SWhitney Tsang 
333*78dc6498SWhitney Tsang   // void foo(int &i, int *cond) {
334*78dc6498SWhitney Tsang   //   if (*cond)
335*78dc6498SWhitney Tsang   //     i = 1;
336*78dc6498SWhitney Tsang   //   if (*cond)
337*78dc6498SWhitney Tsang   //     i = 2;
338*78dc6498SWhitney Tsang   //   *cond = 1;
339*78dc6498SWhitney Tsang   //   if (*cond)
340*78dc6498SWhitney Tsang   //     i = 3;
341*78dc6498SWhitney Tsang   // }
342*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
343*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i32* %cond) {
344*78dc6498SWhitney Tsang                  entry:
345*78dc6498SWhitney Tsang                    %0 = load i32, i32* %cond, align 4
346*78dc6498SWhitney Tsang                    %tobool1 = icmp ne i32 %0, 0
347*78dc6498SWhitney Tsang                    br i1 %tobool1, label %if.first, label %if.first.end
348*78dc6498SWhitney Tsang                  if.first:
349*78dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
350*78dc6498SWhitney Tsang                    br label %if.first.end
351*78dc6498SWhitney Tsang                  if.first.end:
352*78dc6498SWhitney Tsang                    %1 = load i32, i32* %cond, align 4
353*78dc6498SWhitney Tsang                    %tobool2 = icmp ne i32 %1, 0
354*78dc6498SWhitney Tsang                    br i1 %tobool2, label %if.second, label %if.second.end
355*78dc6498SWhitney Tsang                  if.second:
356*78dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
357*78dc6498SWhitney Tsang                    br label %if.second.end
358*78dc6498SWhitney Tsang                  if.second.end:
359*78dc6498SWhitney Tsang                    store i32 1, i32* %cond, align 4
360*78dc6498SWhitney Tsang                    %2 = load i32, i32* %cond, align 4
361*78dc6498SWhitney Tsang                    %tobool3 = icmp ne i32 %2, 0
362*78dc6498SWhitney Tsang                    br i1 %tobool3, label %if.third, label %if.third.end
363*78dc6498SWhitney Tsang                  if.third:
364*78dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
365*78dc6498SWhitney Tsang                    br label %if.third.end
366*78dc6498SWhitney Tsang                  if.third.end:
367*78dc6498SWhitney Tsang                    ret void
368*78dc6498SWhitney Tsang                  })");
369*78dc6498SWhitney Tsang   run(*M, "foo",
370*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
371*78dc6498SWhitney Tsang           DependenceInfo &DI) {
372*78dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
373*78dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
374*78dc6498SWhitney Tsang         // Limitation: if we can prove cond haven't been modify between %0 and
375*78dc6498SWhitney Tsang         // %1, then we can prove FirstIfBody and SecondIfBody are control flow
376*78dc6498SWhitney Tsang         // equivalent.
377*78dc6498SWhitney Tsang         EXPECT_FALSE(
378*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
379*78dc6498SWhitney Tsang 
380*78dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
381*78dc6498SWhitney Tsang         EXPECT_FALSE(
382*78dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
383*78dc6498SWhitney Tsang         EXPECT_FALSE(
384*78dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
385*78dc6498SWhitney Tsang       });
386*78dc6498SWhitney Tsang }
387*78dc6498SWhitney Tsang 
388*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentNotPostdomTest) {
389*78dc6498SWhitney Tsang   LLVMContext C;
390*78dc6498SWhitney Tsang 
391*78dc6498SWhitney Tsang   // void foo(bool cond1, bool cond2) {
392*78dc6498SWhitney Tsang   //   if (cond1) {
393*78dc6498SWhitney Tsang   //     if (cond2)
394*78dc6498SWhitney Tsang   //       return;
395*78dc6498SWhitney Tsang   //   } else
396*78dc6498SWhitney Tsang   //     if (cond2)
397*78dc6498SWhitney Tsang   //       return;
398*78dc6498SWhitney Tsang   //   return;
399*78dc6498SWhitney Tsang   // }
400*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
401*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i1 %cond1, i1 %cond2) {
402*78dc6498SWhitney Tsang                  idom:
403*78dc6498SWhitney Tsang                    br i1 %cond1, label %succ0, label %succ1
404*78dc6498SWhitney Tsang                  succ0:
405*78dc6498SWhitney Tsang                    br i1 %cond2, label %succ0ret, label %succ0succ1
406*78dc6498SWhitney Tsang                  succ0ret:
407*78dc6498SWhitney Tsang                    ret void
408*78dc6498SWhitney Tsang                  succ0succ1:
409*78dc6498SWhitney Tsang                    br label %bb
410*78dc6498SWhitney Tsang                  succ1:
411*78dc6498SWhitney Tsang                    br i1 %cond2, label %succ1ret, label %succ1succ1
412*78dc6498SWhitney Tsang                  succ1ret:
413*78dc6498SWhitney Tsang                    ret void
414*78dc6498SWhitney Tsang                  succ1succ1:
415*78dc6498SWhitney Tsang                    br label %bb
416*78dc6498SWhitney Tsang                  bb:
417*78dc6498SWhitney Tsang                    ret void
418*78dc6498SWhitney Tsang                  })");
419*78dc6498SWhitney Tsang   run(*M, "foo",
420*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
421*78dc6498SWhitney Tsang           DependenceInfo &DI) {
422*78dc6498SWhitney Tsang         BasicBlock &Idom = F.front();
423*78dc6498SWhitney Tsang         assert(Idom.getName() == "idom" && "Expecting BasicBlock idom");
424*78dc6498SWhitney Tsang         BasicBlock &BB = F.back();
425*78dc6498SWhitney Tsang         assert(BB.getName() == "bb" && "Expecting BasicBlock bb");
426*78dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(Idom, BB, DT, PDT));
427*78dc6498SWhitney Tsang       });
428*78dc6498SWhitney Tsang }
429*78dc6498SWhitney Tsang 
430*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest1) {
431ae8a8c2dSTsang Whitney W.H   LLVMContext C;
432ae8a8c2dSTsang Whitney W.H 
433ae8a8c2dSTsang Whitney W.H   // void safecall() noexcept willreturn nosync;
434ae8a8c2dSTsang Whitney W.H   // void unsafecall();
435ae8a8c2dSTsang Whitney W.H   // void foo(int * __restrict__ A, int * __restrict__ B, int * __restrict__ C,
436ae8a8c2dSTsang Whitney W.H   //          long N) {
437ae8a8c2dSTsang Whitney W.H   //   X = N / 1;
438ae8a8c2dSTsang Whitney W.H   //   safecall();
439ae8a8c2dSTsang Whitney W.H   //   unsafecall1();
440ae8a8c2dSTsang Whitney W.H   //   unsafecall2();
441ae8a8c2dSTsang Whitney W.H   //   for (long i = 0; i < N; ++i) {
442ae8a8c2dSTsang Whitney W.H   //     A[5] = 5;
443ae8a8c2dSTsang Whitney W.H   //     A[i] = 0;
444ae8a8c2dSTsang Whitney W.H   //     B[i] = A[i];
445ae8a8c2dSTsang Whitney W.H   //     C[i] = A[i];
446ae8a8c2dSTsang Whitney W.H   //     A[6] = 6;
447ae8a8c2dSTsang Whitney W.H   //   }
448ae8a8c2dSTsang Whitney W.H   // }
449ae8a8c2dSTsang Whitney W.H   std::unique_ptr<Module> M = parseIR(
450*78dc6498SWhitney Tsang       C, R"(define void @foo(i32* noalias %A, i32* noalias %B, i32* noalias %C
451*78dc6498SWhitney Tsang                            , i64 %N) {
452*78dc6498SWhitney Tsang          entry:
453*78dc6498SWhitney Tsang            %X = sdiv i64 1, %N
454*78dc6498SWhitney Tsang            call void @safecall()
455*78dc6498SWhitney Tsang            %cmp1 = icmp slt i64 0, %N
456*78dc6498SWhitney Tsang            call void @unsafecall1()
457*78dc6498SWhitney Tsang            call void @unsafecall2()
458*78dc6498SWhitney Tsang            br i1 %cmp1, label %for.body, label %for.end
459*78dc6498SWhitney Tsang          for.body:
460*78dc6498SWhitney Tsang            %i = phi i64 [ 0, %entry ], [ %inc, %for.body ]
461*78dc6498SWhitney Tsang            %arrayidx_A5 = getelementptr inbounds i32, i32* %A, i64 5
462*78dc6498SWhitney Tsang            store i32 5, i32* %arrayidx_A5, align 4
463*78dc6498SWhitney Tsang            %arrayidx_A = getelementptr inbounds i32, i32* %A, i64 %i
464*78dc6498SWhitney Tsang            store i32 0, i32* %arrayidx_A, align 4
465*78dc6498SWhitney Tsang            %load1 = load i32, i32* %arrayidx_A, align 4
466*78dc6498SWhitney Tsang            %arrayidx_B = getelementptr inbounds i32, i32* %B, i64 %i
467*78dc6498SWhitney Tsang            store i32 %load1, i32* %arrayidx_B, align 4
468*78dc6498SWhitney Tsang            %load2 = load i32, i32* %arrayidx_A, align 4
469*78dc6498SWhitney Tsang            %arrayidx_C = getelementptr inbounds i32, i32* %C, i64 %i
470*78dc6498SWhitney Tsang            store i32 %load2, i32* %arrayidx_C, align 4
471*78dc6498SWhitney Tsang            %arrayidx_A6 = getelementptr inbounds i32, i32* %A, i64 6
472*78dc6498SWhitney Tsang            store i32 6, i32* %arrayidx_A6, align 4
473*78dc6498SWhitney Tsang            %inc = add nsw i64 %i, 1
474*78dc6498SWhitney Tsang            %cmp = icmp slt i64 %inc, %N
475*78dc6498SWhitney Tsang            br i1 %cmp, label %for.body, label %for.end
476*78dc6498SWhitney Tsang          for.end:
477*78dc6498SWhitney Tsang            ret void
478*78dc6498SWhitney Tsang          }
479*78dc6498SWhitney Tsang          declare void @safecall() nounwind nosync willreturn
480*78dc6498SWhitney Tsang          declare void @unsafecall1()
481*78dc6498SWhitney Tsang          declare void @unsafecall2())");
482ae8a8c2dSTsang Whitney W.H 
483ae8a8c2dSTsang Whitney W.H   run(*M, "foo",
484ae8a8c2dSTsang Whitney W.H       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
485ae8a8c2dSTsang Whitney W.H           DependenceInfo &DI) {
486*78dc6498SWhitney Tsang         BasicBlock *Entry = getBasicBlockByName(F, "entry");
487ae8a8c2dSTsang Whitney W.H         Instruction *CI_safecall = Entry->front().getNextNode();
4885e40f2cfSVitaly Buka         assert(isa<CallInst>(CI_safecall) &&
4895e40f2cfSVitaly Buka                "Expecting CI_safecall to be a CallInst");
490ae8a8c2dSTsang Whitney W.H         Instruction *CI_unsafecall = CI_safecall->getNextNode()->getNextNode();
4915e40f2cfSVitaly Buka         assert(isa<CallInst>(CI_unsafecall) &&
4925e40f2cfSVitaly Buka                "Expecting CI_unsafecall to be a CallInst");
493*78dc6498SWhitney Tsang         BasicBlock *ForBody = getBasicBlockByName(F, "for.body");
494ae8a8c2dSTsang Whitney W.H         Instruction &PN = ForBody->front();
495ae8a8c2dSTsang Whitney W.H         assert(isa<PHINode>(PN) && "Expecting PN to be a PHINode");
496*78dc6498SWhitney Tsang         Instruction *SI_A5 =
497*78dc6498SWhitney Tsang             getInstructionByName(F, "arrayidx_A5")->getNextNode();
498*78dc6498SWhitney Tsang         Instruction *SI = getInstructionByName(F, "arrayidx_A")->getNextNode();
499*78dc6498SWhitney Tsang         Instruction *LI1 = getInstructionByName(F, "load1");
500*78dc6498SWhitney Tsang         Instruction *LI2 = getInstructionByName(F, "load2");
5015e40f2cfSVitaly Buka         Instruction *SI_A6 =
502*78dc6498SWhitney Tsang             getInstructionByName(F, "arrayidx_A6")->getNextNode();
503ae8a8c2dSTsang Whitney W.H 
5045e40f2cfSVitaly Buka         // Can move after CI_safecall, as it does not throw, not synchronize, or
5055e40f2cfSVitaly Buka         // must return.
5065e40f2cfSVitaly Buka         EXPECT_TRUE(isSafeToMoveBefore(*CI_safecall->getPrevNode(),
5075e40f2cfSVitaly Buka                                        *CI_safecall->getNextNode(), DT, PDT,
5085e40f2cfSVitaly Buka                                        DI));
509ae8a8c2dSTsang Whitney W.H 
510ae8a8c2dSTsang Whitney W.H         // Cannot move CI_unsafecall, as it may throw.
5115e40f2cfSVitaly Buka         EXPECT_FALSE(isSafeToMoveBefore(*CI_unsafecall->getNextNode(),
5125e40f2cfSVitaly Buka                                         *CI_unsafecall, DT, PDT, DI));
513ae8a8c2dSTsang Whitney W.H 
514ae8a8c2dSTsang Whitney W.H         // Moving instruction to non control flow equivalent places are not
515ae8a8c2dSTsang Whitney W.H         // supported.
5165e40f2cfSVitaly Buka         EXPECT_FALSE(
5175e40f2cfSVitaly Buka             isSafeToMoveBefore(*SI_A5, *Entry->getTerminator(), DT, PDT, DI));
518ae8a8c2dSTsang Whitney W.H 
519ae8a8c2dSTsang Whitney W.H         // Moving PHINode is not supported.
5205e40f2cfSVitaly Buka         EXPECT_FALSE(isSafeToMoveBefore(PN, *PN.getNextNode()->getNextNode(),
5215e40f2cfSVitaly Buka                                         DT, PDT, DI));
522ae8a8c2dSTsang Whitney W.H 
523ae8a8c2dSTsang Whitney W.H         // Cannot move non-PHINode before PHINode.
524ae8a8c2dSTsang Whitney W.H         EXPECT_FALSE(isSafeToMoveBefore(*PN.getNextNode(), PN, DT, PDT, DI));
525ae8a8c2dSTsang Whitney W.H 
526ae8a8c2dSTsang Whitney W.H         // Moving Terminator is not supported.
5275e40f2cfSVitaly Buka         EXPECT_FALSE(isSafeToMoveBefore(*Entry->getTerminator(),
5285e40f2cfSVitaly Buka                                         *PN.getNextNode(), DT, PDT, DI));
529ae8a8c2dSTsang Whitney W.H 
530ae8a8c2dSTsang Whitney W.H         // Cannot move %arrayidx_A after SI, as SI is its user.
5315e40f2cfSVitaly Buka         EXPECT_FALSE(isSafeToMoveBefore(*SI->getPrevNode(), *SI->getNextNode(),
5325e40f2cfSVitaly Buka                                         DT, PDT, DI));
533ae8a8c2dSTsang Whitney W.H 
534ae8a8c2dSTsang Whitney W.H         // Cannot move SI before %arrayidx_A, as %arrayidx_A is its operand.
535ae8a8c2dSTsang Whitney W.H         EXPECT_FALSE(isSafeToMoveBefore(*SI, *SI->getPrevNode(), DT, PDT, DI));
536ae8a8c2dSTsang Whitney W.H 
537ae8a8c2dSTsang Whitney W.H         // Cannot move LI2 after SI_A6, as there is a flow dependence.
5385e40f2cfSVitaly Buka         EXPECT_FALSE(
5395e40f2cfSVitaly Buka             isSafeToMoveBefore(*LI2, *SI_A6->getNextNode(), DT, PDT, DI));
540ae8a8c2dSTsang Whitney W.H 
541ae8a8c2dSTsang Whitney W.H         // Cannot move SI after LI1, as there is a anti dependence.
542ae8a8c2dSTsang Whitney W.H         EXPECT_FALSE(isSafeToMoveBefore(*SI, *LI1->getNextNode(), DT, PDT, DI));
543ae8a8c2dSTsang Whitney W.H 
544ae8a8c2dSTsang Whitney W.H         // Cannot move SI_A5 after SI, as there is a output dependence.
545ae8a8c2dSTsang Whitney W.H         EXPECT_FALSE(isSafeToMoveBefore(*SI_A5, *LI1, DT, PDT, DI));
546ae8a8c2dSTsang Whitney W.H 
547ae8a8c2dSTsang Whitney W.H         // Can move LI2 before LI1, as there is only an input dependence.
548ae8a8c2dSTsang Whitney W.H         EXPECT_TRUE(isSafeToMoveBefore(*LI2, *LI1, DT, PDT, DI));
549ae8a8c2dSTsang Whitney W.H       });
550ae8a8c2dSTsang Whitney W.H }
551*78dc6498SWhitney Tsang 
552*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest2) {
553*78dc6498SWhitney Tsang   LLVMContext C;
554*78dc6498SWhitney Tsang 
555*78dc6498SWhitney Tsang   std::unique_ptr<Module> M =
556*78dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) {
557*78dc6498SWhitney Tsang                  entry:
558*78dc6498SWhitney Tsang                    br i1 %cond, label %if.then.first, label %if.end.first
559*78dc6498SWhitney Tsang                  if.then.first:
560*78dc6498SWhitney Tsang                    %add = add i32 %op0, %op1
561*78dc6498SWhitney Tsang                    %user = add i32 %add, 1
562*78dc6498SWhitney Tsang                    br label %if.end.first
563*78dc6498SWhitney Tsang                  if.end.first:
564*78dc6498SWhitney Tsang                    br i1 %cond, label %if.then.second, label %if.end.second
565*78dc6498SWhitney Tsang                  if.then.second:
566*78dc6498SWhitney Tsang                    %sub_op0 = add i32 %op0, 1
567*78dc6498SWhitney Tsang                    %sub = sub i32 %sub_op0, %op1
568*78dc6498SWhitney Tsang                    br label %if.end.second
569*78dc6498SWhitney Tsang                  if.end.second:
570*78dc6498SWhitney Tsang                    ret void
571*78dc6498SWhitney Tsang                  })");
572*78dc6498SWhitney Tsang 
573*78dc6498SWhitney Tsang   run(*M, "foo",
574*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
575*78dc6498SWhitney Tsang           DependenceInfo &DI) {
576*78dc6498SWhitney Tsang         Instruction *AddInst = getInstructionByName(F, "add");
577*78dc6498SWhitney Tsang         Instruction *SubInst = getInstructionByName(F, "sub");
578*78dc6498SWhitney Tsang 
579*78dc6498SWhitney Tsang         // Cannot move as %user uses %add and %sub doesn't dominates %user.
580*78dc6498SWhitney Tsang         EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, PDT, DI));
581*78dc6498SWhitney Tsang 
582*78dc6498SWhitney Tsang         // Cannot move as %sub_op0 is an operand of %sub and %add doesn't
583*78dc6498SWhitney Tsang         // dominates %sub_op0.
584*78dc6498SWhitney Tsang         EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, PDT, DI));
585*78dc6498SWhitney Tsang       });
586*78dc6498SWhitney Tsang }
587*78dc6498SWhitney Tsang 
588*78dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest3) {
589*78dc6498SWhitney Tsang   LLVMContext C;
590*78dc6498SWhitney Tsang 
591*78dc6498SWhitney Tsang   std::unique_ptr<Module> M = parseIR(C, R"(define void @foo(i64 %N) {
592*78dc6498SWhitney Tsang                  entry:
593*78dc6498SWhitney Tsang                    br label %for.body
594*78dc6498SWhitney Tsang                  for.body:
595*78dc6498SWhitney Tsang                    %i = phi i64 [ 0, %entry ], [ %inc, %for.latch ]
596*78dc6498SWhitney Tsang                    %inc = add nsw i64 %i, 1
597*78dc6498SWhitney Tsang                    br label %for.latch
598*78dc6498SWhitney Tsang                  for.latch:
599*78dc6498SWhitney Tsang                    %cmp = icmp slt i64 %inc, %N
600*78dc6498SWhitney Tsang                    br i1 %cmp, label %for.body, label %for.end
601*78dc6498SWhitney Tsang                  for.end:
602*78dc6498SWhitney Tsang                    ret void
603*78dc6498SWhitney Tsang                  })");
604*78dc6498SWhitney Tsang 
605*78dc6498SWhitney Tsang   run(*M, "foo",
606*78dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
607*78dc6498SWhitney Tsang           DependenceInfo &DI) {
608*78dc6498SWhitney Tsang         Instruction *IncInst = getInstructionByName(F, "inc");
609*78dc6498SWhitney Tsang         Instruction *CmpInst = getInstructionByName(F, "cmp");
610*78dc6498SWhitney Tsang 
611*78dc6498SWhitney Tsang         // Can move as the incoming block of %inc for %i (%for.latch) dominated
612*78dc6498SWhitney Tsang         // by %cmp.
613*78dc6498SWhitney Tsang         EXPECT_TRUE(isSafeToMoveBefore(*IncInst, *CmpInst, DT, PDT, DI));
614*78dc6498SWhitney Tsang       });
615*78dc6498SWhitney Tsang }
616