xref: /llvm-project/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp (revision eadf2959567c89bebff153feac873cbc1b71eb04)
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"
14ae8a8c2dSTsang Whitney W.H #include "llvm/AsmParser/Parser.h"
15ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h"
16ae8a8c2dSTsang Whitney W.H #include "llvm/IR/LLVMContext.h"
17ae8a8c2dSTsang Whitney W.H #include "llvm/Support/SourceMgr.h"
18bcbd26bfSFlorian Hahn #include "llvm/Transforms/Utils/ScalarEvolutionExpander.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 
4878dc6498SWhitney Tsang static BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
4978dc6498SWhitney Tsang   for (BasicBlock &BB : F)
5078dc6498SWhitney Tsang     if (BB.getName() == Name)
5178dc6498SWhitney Tsang       return &BB;
5278dc6498SWhitney Tsang   llvm_unreachable("Expected to find basic block!");
5378dc6498SWhitney Tsang }
5478dc6498SWhitney Tsang 
5578dc6498SWhitney Tsang static Instruction *getInstructionByName(Function &F, StringRef Name) {
5678dc6498SWhitney Tsang   for (BasicBlock &BB : F)
5778dc6498SWhitney Tsang     for (Instruction &I : BB)
5878dc6498SWhitney Tsang       if (I.getName() == Name)
5978dc6498SWhitney Tsang         return &I;
6078dc6498SWhitney Tsang   llvm_unreachable("Expected to find instruction!");
6178dc6498SWhitney Tsang }
6278dc6498SWhitney Tsang 
6378dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentSimpleTest) {
6478dc6498SWhitney Tsang   LLVMContext C;
6578dc6498SWhitney Tsang 
6678dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
6778dc6498SWhitney Tsang   //   if (cond1)
6878dc6498SWhitney Tsang   //     i = 1;
6978dc6498SWhitney Tsang   //   if (cond1)
7078dc6498SWhitney Tsang   //     i = 2;
7178dc6498SWhitney Tsang   //   if (cond2)
7278dc6498SWhitney Tsang   //     i = 3;
7378dc6498SWhitney Tsang   // }
7478dc6498SWhitney Tsang   std::unique_ptr<Module> M =
7578dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
7678dc6498SWhitney Tsang                  entry:
7778dc6498SWhitney Tsang                    br i1 %cond1, label %if.first, label %if.first.end
7878dc6498SWhitney Tsang                  if.first:
7978dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
8078dc6498SWhitney Tsang                    br label %if.first.end
8178dc6498SWhitney Tsang                  if.first.end:
8278dc6498SWhitney Tsang                    br i1 %cond1, label %if.second, label %if.second.end
8378dc6498SWhitney Tsang                  if.second:
8478dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
8578dc6498SWhitney Tsang                    br label %if.second.end
8678dc6498SWhitney Tsang                  if.second.end:
8778dc6498SWhitney Tsang                    br i1 %cond2, label %if.third, label %if.third.end
8878dc6498SWhitney Tsang                  if.third:
8978dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
9078dc6498SWhitney Tsang                    br label %if.third.end
9178dc6498SWhitney Tsang                  if.third.end:
9278dc6498SWhitney Tsang                    ret void
9378dc6498SWhitney Tsang                  })");
9478dc6498SWhitney Tsang   run(*M, "foo",
9578dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
9678dc6498SWhitney Tsang           DependenceInfo &DI) {
9778dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
9878dc6498SWhitney Tsang         EXPECT_TRUE(
9978dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *FirstIfBody, DT, PDT));
10078dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
10178dc6498SWhitney Tsang         EXPECT_TRUE(
10278dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
10378dc6498SWhitney Tsang 
10478dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
10578dc6498SWhitney Tsang         EXPECT_FALSE(
10678dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
10778dc6498SWhitney Tsang         EXPECT_FALSE(
10878dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
10978dc6498SWhitney Tsang       });
11078dc6498SWhitney Tsang }
11178dc6498SWhitney Tsang 
11278dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentOppositeCondTest) {
11378dc6498SWhitney Tsang   LLVMContext C;
11478dc6498SWhitney Tsang 
11578dc6498SWhitney Tsang   // void foo(int &i, unsigned X, unsigned Y) {
11678dc6498SWhitney Tsang   //   if (X < Y)
11778dc6498SWhitney Tsang   //     i = 1;
11878dc6498SWhitney Tsang   //   if (Y > X)
11978dc6498SWhitney Tsang   //     i = 2;
12078dc6498SWhitney Tsang   //   if (X >= Y)
12178dc6498SWhitney Tsang   //     i = 3;
12278dc6498SWhitney Tsang   //   else
12378dc6498SWhitney Tsang   //     i = 4;
12478dc6498SWhitney Tsang   //   if (X == Y)
12578dc6498SWhitney Tsang   //     i = 5;
12678dc6498SWhitney Tsang   //   if (Y == X)
12778dc6498SWhitney Tsang   //     i = 6;
12878dc6498SWhitney Tsang   //   else
12978dc6498SWhitney Tsang   //     i = 7;
13078dc6498SWhitney Tsang   //   if (X != Y)
13178dc6498SWhitney Tsang   //     i = 8;
13278dc6498SWhitney Tsang   //   else
13378dc6498SWhitney Tsang   //     i = 9;
13478dc6498SWhitney Tsang   // }
13578dc6498SWhitney Tsang   std::unique_ptr<Module> M =
13678dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i32 %X, i32 %Y) {
13778dc6498SWhitney Tsang                  entry:
13878dc6498SWhitney Tsang                    %cmp1 = icmp ult i32 %X, %Y
13978dc6498SWhitney Tsang                    br i1 %cmp1, label %if.first, label %if.first.end
14078dc6498SWhitney Tsang                  if.first:
14178dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
14278dc6498SWhitney Tsang                    br label %if.first.end
14378dc6498SWhitney Tsang                  if.first.end:
14478dc6498SWhitney Tsang                    %cmp2 = icmp ugt i32 %Y, %X
14578dc6498SWhitney Tsang                    br i1 %cmp2, label %if.second, label %if.second.end
14678dc6498SWhitney Tsang                  if.second:
14778dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
14878dc6498SWhitney Tsang                    br label %if.second.end
14978dc6498SWhitney Tsang                  if.second.end:
15078dc6498SWhitney Tsang                    %cmp3 = icmp uge i32 %X, %Y
15178dc6498SWhitney Tsang                    br i1 %cmp3, label %if.third, label %if.third.else
15278dc6498SWhitney Tsang                  if.third:
15378dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
15478dc6498SWhitney Tsang                    br label %if.third.end
15578dc6498SWhitney Tsang                  if.third.else:
15678dc6498SWhitney Tsang                    store i32 4, i32* %i, align 4
15778dc6498SWhitney Tsang                    br label %if.third.end
15878dc6498SWhitney Tsang                  if.third.end:
15978dc6498SWhitney Tsang                    %cmp4 = icmp eq i32 %X, %Y
16078dc6498SWhitney Tsang                    br i1 %cmp4, label %if.fourth, label %if.fourth.end
16178dc6498SWhitney Tsang                  if.fourth:
16278dc6498SWhitney Tsang                    store i32 5, i32* %i, align 4
16378dc6498SWhitney Tsang                    br label %if.fourth.end
16478dc6498SWhitney Tsang                  if.fourth.end:
16578dc6498SWhitney Tsang                    %cmp5 = icmp eq i32 %Y, %X
16678dc6498SWhitney Tsang                    br i1 %cmp5, label %if.fifth, label %if.fifth.else
16778dc6498SWhitney Tsang                  if.fifth:
16878dc6498SWhitney Tsang                    store i32 6, i32* %i, align 4
16978dc6498SWhitney Tsang                    br label %if.fifth.end
17078dc6498SWhitney Tsang                  if.fifth.else:
17178dc6498SWhitney Tsang                    store i32 7, i32* %i, align 4
17278dc6498SWhitney Tsang                    br label %if.fifth.end
17378dc6498SWhitney Tsang                  if.fifth.end:
17478dc6498SWhitney Tsang                    %cmp6 = icmp ne i32 %X, %Y
17578dc6498SWhitney Tsang                    br i1 %cmp6, label %if.sixth, label %if.sixth.else
17678dc6498SWhitney Tsang                  if.sixth:
17778dc6498SWhitney Tsang                    store i32 8, i32* %i, align 4
17878dc6498SWhitney Tsang                    br label %if.sixth.end
17978dc6498SWhitney Tsang                  if.sixth.else:
18078dc6498SWhitney Tsang                    store i32 9, i32* %i, align 4
18178dc6498SWhitney Tsang                    br label %if.sixth.end
18278dc6498SWhitney Tsang                  if.sixth.end:
18378dc6498SWhitney Tsang                    ret void
18478dc6498SWhitney Tsang                  })");
18578dc6498SWhitney Tsang   run(*M, "foo",
18678dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
18778dc6498SWhitney Tsang           DependenceInfo &DI) {
18878dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
18978dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
19078dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
19178dc6498SWhitney Tsang         BasicBlock *ThirdElseBody = getBasicBlockByName(F, "if.third.else");
19278dc6498SWhitney Tsang         EXPECT_TRUE(
19378dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdElseBody, DT, PDT));
19478dc6498SWhitney Tsang         EXPECT_TRUE(
19578dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdElseBody, DT, PDT));
19678dc6498SWhitney Tsang         EXPECT_FALSE(
19778dc6498SWhitney Tsang             isControlFlowEquivalent(*ThirdIfBody, *ThirdElseBody, DT, PDT));
19878dc6498SWhitney Tsang 
19978dc6498SWhitney Tsang         BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
20078dc6498SWhitney Tsang         BasicBlock *FifthIfBody = getBasicBlockByName(F, "if.fifth");
20178dc6498SWhitney Tsang         BasicBlock *FifthElseBody = getBasicBlockByName(F, "if.fifth.else");
20278dc6498SWhitney Tsang         EXPECT_FALSE(
20378dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthIfBody, *FifthElseBody, DT, PDT));
20478dc6498SWhitney Tsang         BasicBlock *SixthIfBody = getBasicBlockByName(F, "if.sixth");
20578dc6498SWhitney Tsang         EXPECT_TRUE(
20678dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthElseBody, *SixthIfBody, DT, PDT));
20778dc6498SWhitney Tsang         BasicBlock *SixthElseBody = getBasicBlockByName(F, "if.sixth.else");
20878dc6498SWhitney Tsang         EXPECT_TRUE(
20978dc6498SWhitney Tsang             isControlFlowEquivalent(*FourthIfBody, *SixthElseBody, DT, PDT));
21078dc6498SWhitney Tsang         EXPECT_TRUE(
21178dc6498SWhitney Tsang             isControlFlowEquivalent(*FifthIfBody, *SixthElseBody, DT, PDT));
21278dc6498SWhitney Tsang       });
21378dc6498SWhitney Tsang }
21478dc6498SWhitney Tsang 
21578dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentCondNestTest) {
21678dc6498SWhitney Tsang   LLVMContext C;
21778dc6498SWhitney Tsang 
21878dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
21978dc6498SWhitney Tsang   //   if (cond1)
22078dc6498SWhitney Tsang   //     if (cond2)
22178dc6498SWhitney Tsang   //       i = 1;
22278dc6498SWhitney Tsang   //   if (cond2)
22378dc6498SWhitney Tsang   //     if (cond1)
22478dc6498SWhitney Tsang   //       i = 2;
22578dc6498SWhitney Tsang   // }
22678dc6498SWhitney Tsang   std::unique_ptr<Module> M =
22778dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
22878dc6498SWhitney Tsang          entry:
22978dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.first, label %if.first.end
23078dc6498SWhitney Tsang          if.outer.first:
23178dc6498SWhitney Tsang            br i1 %cond2, label %if.inner.first, label %if.first.end
23278dc6498SWhitney Tsang          if.inner.first:
23378dc6498SWhitney Tsang            store i32 1, i32* %i, align 4
23478dc6498SWhitney Tsang            br label %if.first.end
23578dc6498SWhitney Tsang          if.first.end:
23678dc6498SWhitney Tsang            br i1 %cond2, label %if.outer.second, label %if.second.end
23778dc6498SWhitney Tsang          if.outer.second:
23878dc6498SWhitney Tsang            br i1 %cond1, label %if.inner.second, label %if.second.end
23978dc6498SWhitney Tsang          if.inner.second:
24078dc6498SWhitney Tsang            store i32 2, i32* %i, align 4
24178dc6498SWhitney Tsang            br label %if.second.end
24278dc6498SWhitney Tsang          if.second.end:
24378dc6498SWhitney Tsang            ret void
24478dc6498SWhitney Tsang          })");
24578dc6498SWhitney Tsang   run(*M, "foo",
24678dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
24778dc6498SWhitney Tsang           DependenceInfo &DI) {
24878dc6498SWhitney Tsang         BasicBlock *FirstOuterIfBody = getBasicBlockByName(F, "if.outer.first");
24978dc6498SWhitney Tsang         BasicBlock *FirstInnerIfBody = getBasicBlockByName(F, "if.inner.first");
25078dc6498SWhitney Tsang         BasicBlock *SecondOuterIfBody =
25178dc6498SWhitney Tsang             getBasicBlockByName(F, "if.outer.second");
25278dc6498SWhitney Tsang         BasicBlock *SecondInnerIfBody =
25378dc6498SWhitney Tsang             getBasicBlockByName(F, "if.inner.second");
25478dc6498SWhitney Tsang         EXPECT_TRUE(isControlFlowEquivalent(*FirstInnerIfBody,
25578dc6498SWhitney Tsang                                             *SecondInnerIfBody, DT, PDT));
25678dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
25778dc6498SWhitney Tsang                                              *SecondOuterIfBody, DT, PDT));
25878dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
25978dc6498SWhitney Tsang                                              *SecondInnerIfBody, DT, PDT));
26078dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(*FirstInnerIfBody,
26178dc6498SWhitney Tsang                                              *SecondOuterIfBody, DT, PDT));
26278dc6498SWhitney Tsang       });
26378dc6498SWhitney Tsang }
26478dc6498SWhitney Tsang 
26578dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentImbalanceTest) {
26678dc6498SWhitney Tsang   LLVMContext C;
26778dc6498SWhitney Tsang 
26878dc6498SWhitney Tsang   // void foo(int &i, bool cond1, bool cond2) {
26978dc6498SWhitney Tsang   //   if (cond1)
27078dc6498SWhitney Tsang   //     if (cond2)
27178dc6498SWhitney Tsang   //       if (cond3)
27278dc6498SWhitney Tsang   //         i = 1;
27378dc6498SWhitney Tsang   //   if (cond2)
27478dc6498SWhitney Tsang   //     if (cond3)
27578dc6498SWhitney Tsang   //       i = 2;
27678dc6498SWhitney Tsang   //   if (cond1)
27778dc6498SWhitney Tsang   //     if (cond1)
27878dc6498SWhitney Tsang   //       i = 3;
27978dc6498SWhitney Tsang   //   if (cond1)
28078dc6498SWhitney Tsang   //     i = 4;
28178dc6498SWhitney Tsang   // }
28278dc6498SWhitney Tsang   std::unique_ptr<Module> M = parseIR(
28378dc6498SWhitney Tsang       C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2, i1 %cond3) {
28478dc6498SWhitney Tsang          entry:
28578dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.first, label %if.first.end
28678dc6498SWhitney Tsang          if.outer.first:
28778dc6498SWhitney Tsang            br i1 %cond2, label %if.middle.first, label %if.first.end
28878dc6498SWhitney Tsang          if.middle.first:
28978dc6498SWhitney Tsang            br i1 %cond3, label %if.inner.first, label %if.first.end
29078dc6498SWhitney Tsang          if.inner.first:
29178dc6498SWhitney Tsang            store i32 1, i32* %i, align 4
29278dc6498SWhitney Tsang            br label %if.first.end
29378dc6498SWhitney Tsang          if.first.end:
29478dc6498SWhitney Tsang            br i1 %cond2, label %if.outer.second, label %if.second.end
29578dc6498SWhitney Tsang          if.outer.second:
29678dc6498SWhitney Tsang            br i1 %cond3, label %if.inner.second, label %if.second.end
29778dc6498SWhitney Tsang          if.inner.second:
29878dc6498SWhitney Tsang            store i32 2, i32* %i, align 4
29978dc6498SWhitney Tsang            br label %if.second.end
30078dc6498SWhitney Tsang          if.second.end:
30178dc6498SWhitney Tsang            br i1 %cond1, label %if.outer.third, label %if.third.end
30278dc6498SWhitney Tsang          if.outer.third:
30378dc6498SWhitney Tsang            br i1 %cond1, label %if.inner.third, label %if.third.end
30478dc6498SWhitney Tsang          if.inner.third:
30578dc6498SWhitney Tsang            store i32 3, i32* %i, align 4
30678dc6498SWhitney Tsang            br label %if.third.end
30778dc6498SWhitney Tsang          if.third.end:
30878dc6498SWhitney Tsang            br i1 %cond1, label %if.fourth, label %if.fourth.end
30978dc6498SWhitney Tsang          if.fourth:
31078dc6498SWhitney Tsang            store i32 4, i32* %i, align 4
31178dc6498SWhitney Tsang            br label %if.fourth.end
31278dc6498SWhitney Tsang          if.fourth.end:
31378dc6498SWhitney Tsang            ret void
31478dc6498SWhitney Tsang          })");
31578dc6498SWhitney Tsang   run(*M, "foo",
31678dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
31778dc6498SWhitney Tsang           DependenceInfo &DI) {
31878dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.inner.first");
31978dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.inner.second");
32078dc6498SWhitney Tsang         EXPECT_FALSE(
32178dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
32278dc6498SWhitney Tsang 
32378dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.inner.third");
32478dc6498SWhitney Tsang         BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
32578dc6498SWhitney Tsang         EXPECT_TRUE(
32678dc6498SWhitney Tsang             isControlFlowEquivalent(*ThirdIfBody, *FourthIfBody, DT, PDT));
32778dc6498SWhitney Tsang       });
32878dc6498SWhitney Tsang }
32978dc6498SWhitney Tsang 
33078dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentPointerTest) {
33178dc6498SWhitney Tsang   LLVMContext C;
33278dc6498SWhitney Tsang 
33378dc6498SWhitney Tsang   // void foo(int &i, int *cond) {
33478dc6498SWhitney Tsang   //   if (*cond)
33578dc6498SWhitney Tsang   //     i = 1;
33678dc6498SWhitney Tsang   //   if (*cond)
33778dc6498SWhitney Tsang   //     i = 2;
33878dc6498SWhitney Tsang   //   *cond = 1;
33978dc6498SWhitney Tsang   //   if (*cond)
34078dc6498SWhitney Tsang   //     i = 3;
34178dc6498SWhitney Tsang   // }
34278dc6498SWhitney Tsang   std::unique_ptr<Module> M =
34378dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i32* %i, i32* %cond) {
34478dc6498SWhitney Tsang                  entry:
34578dc6498SWhitney Tsang                    %0 = load i32, i32* %cond, align 4
34678dc6498SWhitney Tsang                    %tobool1 = icmp ne i32 %0, 0
34778dc6498SWhitney Tsang                    br i1 %tobool1, label %if.first, label %if.first.end
34878dc6498SWhitney Tsang                  if.first:
34978dc6498SWhitney Tsang                    store i32 1, i32* %i, align 4
35078dc6498SWhitney Tsang                    br label %if.first.end
35178dc6498SWhitney Tsang                  if.first.end:
35278dc6498SWhitney Tsang                    %1 = load i32, i32* %cond, align 4
35378dc6498SWhitney Tsang                    %tobool2 = icmp ne i32 %1, 0
35478dc6498SWhitney Tsang                    br i1 %tobool2, label %if.second, label %if.second.end
35578dc6498SWhitney Tsang                  if.second:
35678dc6498SWhitney Tsang                    store i32 2, i32* %i, align 4
35778dc6498SWhitney Tsang                    br label %if.second.end
35878dc6498SWhitney Tsang                  if.second.end:
35978dc6498SWhitney Tsang                    store i32 1, i32* %cond, align 4
36078dc6498SWhitney Tsang                    %2 = load i32, i32* %cond, align 4
36178dc6498SWhitney Tsang                    %tobool3 = icmp ne i32 %2, 0
36278dc6498SWhitney Tsang                    br i1 %tobool3, label %if.third, label %if.third.end
36378dc6498SWhitney Tsang                  if.third:
36478dc6498SWhitney Tsang                    store i32 3, i32* %i, align 4
36578dc6498SWhitney Tsang                    br label %if.third.end
36678dc6498SWhitney Tsang                  if.third.end:
36778dc6498SWhitney Tsang                    ret void
36878dc6498SWhitney Tsang                  })");
36978dc6498SWhitney Tsang   run(*M, "foo",
37078dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
37178dc6498SWhitney Tsang           DependenceInfo &DI) {
37278dc6498SWhitney Tsang         BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
37378dc6498SWhitney Tsang         BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
37478dc6498SWhitney Tsang         // Limitation: if we can prove cond haven't been modify between %0 and
37578dc6498SWhitney Tsang         // %1, then we can prove FirstIfBody and SecondIfBody are control flow
37678dc6498SWhitney Tsang         // equivalent.
37778dc6498SWhitney Tsang         EXPECT_FALSE(
37878dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
37978dc6498SWhitney Tsang 
38078dc6498SWhitney Tsang         BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
38178dc6498SWhitney Tsang         EXPECT_FALSE(
38278dc6498SWhitney Tsang             isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
38378dc6498SWhitney Tsang         EXPECT_FALSE(
38478dc6498SWhitney Tsang             isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
38578dc6498SWhitney Tsang       });
38678dc6498SWhitney Tsang }
38778dc6498SWhitney Tsang 
38878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentNotPostdomTest) {
38978dc6498SWhitney Tsang   LLVMContext C;
39078dc6498SWhitney Tsang 
39178dc6498SWhitney Tsang   // void foo(bool cond1, bool cond2) {
39278dc6498SWhitney Tsang   //   if (cond1) {
39378dc6498SWhitney Tsang   //     if (cond2)
39478dc6498SWhitney Tsang   //       return;
39578dc6498SWhitney Tsang   //   } else
39678dc6498SWhitney Tsang   //     if (cond2)
39778dc6498SWhitney Tsang   //       return;
39878dc6498SWhitney Tsang   //   return;
39978dc6498SWhitney Tsang   // }
40078dc6498SWhitney Tsang   std::unique_ptr<Module> M =
40178dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i1 %cond1, i1 %cond2) {
40278dc6498SWhitney Tsang                  idom:
40378dc6498SWhitney Tsang                    br i1 %cond1, label %succ0, label %succ1
40478dc6498SWhitney Tsang                  succ0:
40578dc6498SWhitney Tsang                    br i1 %cond2, label %succ0ret, label %succ0succ1
40678dc6498SWhitney Tsang                  succ0ret:
40778dc6498SWhitney Tsang                    ret void
40878dc6498SWhitney Tsang                  succ0succ1:
40978dc6498SWhitney Tsang                    br label %bb
41078dc6498SWhitney Tsang                  succ1:
41178dc6498SWhitney Tsang                    br i1 %cond2, label %succ1ret, label %succ1succ1
41278dc6498SWhitney Tsang                  succ1ret:
41378dc6498SWhitney Tsang                    ret void
41478dc6498SWhitney Tsang                  succ1succ1:
41578dc6498SWhitney Tsang                    br label %bb
41678dc6498SWhitney Tsang                  bb:
41778dc6498SWhitney Tsang                    ret void
41878dc6498SWhitney Tsang                  })");
41978dc6498SWhitney Tsang   run(*M, "foo",
42078dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
42178dc6498SWhitney Tsang           DependenceInfo &DI) {
42278dc6498SWhitney Tsang         BasicBlock &Idom = F.front();
42378dc6498SWhitney Tsang         assert(Idom.getName() == "idom" && "Expecting BasicBlock idom");
42478dc6498SWhitney Tsang         BasicBlock &BB = F.back();
42578dc6498SWhitney Tsang         assert(BB.getName() == "bb" && "Expecting BasicBlock bb");
42678dc6498SWhitney Tsang         EXPECT_FALSE(isControlFlowEquivalent(Idom, BB, DT, PDT));
42778dc6498SWhitney Tsang       });
42878dc6498SWhitney Tsang }
42978dc6498SWhitney Tsang 
43078dc6498SWhitney 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(
45078dc6498SWhitney Tsang       C, R"(define void @foo(i32* noalias %A, i32* noalias %B, i32* noalias %C
45178dc6498SWhitney Tsang                            , i64 %N) {
45278dc6498SWhitney Tsang          entry:
45378dc6498SWhitney Tsang            %X = sdiv i64 1, %N
45478dc6498SWhitney Tsang            call void @safecall()
45578dc6498SWhitney Tsang            %cmp1 = icmp slt i64 0, %N
45678dc6498SWhitney Tsang            call void @unsafecall1()
45778dc6498SWhitney Tsang            call void @unsafecall2()
45878dc6498SWhitney Tsang            br i1 %cmp1, label %for.body, label %for.end
45978dc6498SWhitney Tsang          for.body:
46078dc6498SWhitney Tsang            %i = phi i64 [ 0, %entry ], [ %inc, %for.body ]
46178dc6498SWhitney Tsang            %arrayidx_A5 = getelementptr inbounds i32, i32* %A, i64 5
46278dc6498SWhitney Tsang            store i32 5, i32* %arrayidx_A5, align 4
46378dc6498SWhitney Tsang            %arrayidx_A = getelementptr inbounds i32, i32* %A, i64 %i
46478dc6498SWhitney Tsang            store i32 0, i32* %arrayidx_A, align 4
46578dc6498SWhitney Tsang            %load1 = load i32, i32* %arrayidx_A, align 4
46678dc6498SWhitney Tsang            %arrayidx_B = getelementptr inbounds i32, i32* %B, i64 %i
46778dc6498SWhitney Tsang            store i32 %load1, i32* %arrayidx_B, align 4
46878dc6498SWhitney Tsang            %load2 = load i32, i32* %arrayidx_A, align 4
46978dc6498SWhitney Tsang            %arrayidx_C = getelementptr inbounds i32, i32* %C, i64 %i
47078dc6498SWhitney Tsang            store i32 %load2, i32* %arrayidx_C, align 4
47178dc6498SWhitney Tsang            %arrayidx_A6 = getelementptr inbounds i32, i32* %A, i64 6
47278dc6498SWhitney Tsang            store i32 6, i32* %arrayidx_A6, align 4
47378dc6498SWhitney Tsang            %inc = add nsw i64 %i, 1
47478dc6498SWhitney Tsang            %cmp = icmp slt i64 %inc, %N
47578dc6498SWhitney Tsang            br i1 %cmp, label %for.body, label %for.end
47678dc6498SWhitney Tsang          for.end:
47778dc6498SWhitney Tsang            ret void
47878dc6498SWhitney Tsang          }
47978dc6498SWhitney Tsang          declare void @safecall() nounwind nosync willreturn
48078dc6498SWhitney Tsang          declare void @unsafecall1()
48178dc6498SWhitney 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) {
48678dc6498SWhitney 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");
49378dc6498SWhitney 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");
49678dc6498SWhitney Tsang         Instruction *SI_A5 =
49778dc6498SWhitney Tsang             getInstructionByName(F, "arrayidx_A5")->getNextNode();
49878dc6498SWhitney Tsang         Instruction *SI = getInstructionByName(F, "arrayidx_A")->getNextNode();
49978dc6498SWhitney Tsang         Instruction *LI1 = getInstructionByName(F, "load1");
50078dc6498SWhitney Tsang         Instruction *LI2 = getInstructionByName(F, "load2");
5015e40f2cfSVitaly Buka         Instruction *SI_A6 =
50278dc6498SWhitney 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 }
55178dc6498SWhitney Tsang 
55278dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest2) {
55378dc6498SWhitney Tsang   LLVMContext C;
55478dc6498SWhitney Tsang 
55578dc6498SWhitney Tsang   std::unique_ptr<Module> M =
55678dc6498SWhitney Tsang       parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) {
55778dc6498SWhitney Tsang                  entry:
55878dc6498SWhitney Tsang                    br i1 %cond, label %if.then.first, label %if.end.first
55978dc6498SWhitney Tsang                  if.then.first:
56078dc6498SWhitney Tsang                    %add = add i32 %op0, %op1
56178dc6498SWhitney Tsang                    %user = add i32 %add, 1
56278dc6498SWhitney Tsang                    br label %if.end.first
56378dc6498SWhitney Tsang                  if.end.first:
56478dc6498SWhitney Tsang                    br i1 %cond, label %if.then.second, label %if.end.second
56578dc6498SWhitney Tsang                  if.then.second:
56678dc6498SWhitney Tsang                    %sub_op0 = add i32 %op0, 1
56778dc6498SWhitney Tsang                    %sub = sub i32 %sub_op0, %op1
56878dc6498SWhitney Tsang                    br label %if.end.second
56978dc6498SWhitney Tsang                  if.end.second:
57078dc6498SWhitney Tsang                    ret void
57178dc6498SWhitney Tsang                  })");
57278dc6498SWhitney Tsang 
57378dc6498SWhitney Tsang   run(*M, "foo",
57478dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
57578dc6498SWhitney Tsang           DependenceInfo &DI) {
57678dc6498SWhitney Tsang         Instruction *AddInst = getInstructionByName(F, "add");
57778dc6498SWhitney Tsang         Instruction *SubInst = getInstructionByName(F, "sub");
57878dc6498SWhitney Tsang 
57978dc6498SWhitney Tsang         // Cannot move as %user uses %add and %sub doesn't dominates %user.
58078dc6498SWhitney Tsang         EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, PDT, DI));
58178dc6498SWhitney Tsang 
58278dc6498SWhitney Tsang         // Cannot move as %sub_op0 is an operand of %sub and %add doesn't
58378dc6498SWhitney Tsang         // dominates %sub_op0.
58478dc6498SWhitney Tsang         EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, PDT, DI));
58578dc6498SWhitney Tsang       });
58678dc6498SWhitney Tsang }
58778dc6498SWhitney Tsang 
58878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest3) {
58978dc6498SWhitney Tsang   LLVMContext C;
59078dc6498SWhitney Tsang 
59178dc6498SWhitney Tsang   std::unique_ptr<Module> M = parseIR(C, R"(define void @foo(i64 %N) {
59278dc6498SWhitney Tsang                  entry:
59378dc6498SWhitney Tsang                    br label %for.body
59478dc6498SWhitney Tsang                  for.body:
59578dc6498SWhitney Tsang                    %i = phi i64 [ 0, %entry ], [ %inc, %for.latch ]
59678dc6498SWhitney Tsang                    %inc = add nsw i64 %i, 1
59778dc6498SWhitney Tsang                    br label %for.latch
59878dc6498SWhitney Tsang                  for.latch:
59978dc6498SWhitney Tsang                    %cmp = icmp slt i64 %inc, %N
60078dc6498SWhitney Tsang                    br i1 %cmp, label %for.body, label %for.end
60178dc6498SWhitney Tsang                  for.end:
60278dc6498SWhitney Tsang                    ret void
60378dc6498SWhitney Tsang                  })");
60478dc6498SWhitney Tsang 
60578dc6498SWhitney Tsang   run(*M, "foo",
60678dc6498SWhitney Tsang       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
60778dc6498SWhitney Tsang           DependenceInfo &DI) {
60878dc6498SWhitney Tsang         Instruction *IncInst = getInstructionByName(F, "inc");
60978dc6498SWhitney Tsang         Instruction *CmpInst = getInstructionByName(F, "cmp");
61078dc6498SWhitney Tsang 
61178dc6498SWhitney Tsang         // Can move as the incoming block of %inc for %i (%for.latch) dominated
61278dc6498SWhitney Tsang         // by %cmp.
61378dc6498SWhitney Tsang         EXPECT_TRUE(isSafeToMoveBefore(*IncInst, *CmpInst, DT, PDT, DI));
61478dc6498SWhitney Tsang       });
61578dc6498SWhitney Tsang }
616*eadf2959SRithik Sharma 
617*eadf2959SRithik Sharma TEST(CodeMoverUtils, IsSafeToMoveTest4) {
618*eadf2959SRithik Sharma   LLVMContext C;
619*eadf2959SRithik Sharma 
620*eadf2959SRithik Sharma   std::unique_ptr<Module> M =
621*eadf2959SRithik Sharma       parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) {
622*eadf2959SRithik Sharma                  entry:
623*eadf2959SRithik Sharma                    br i1 %cond, label %if.end.first, label %if.then.first
624*eadf2959SRithik Sharma                  if.then.first:
625*eadf2959SRithik Sharma                    %add = add i32 %op0, %op1
626*eadf2959SRithik Sharma                    %user = add i32 %add, 1
627*eadf2959SRithik Sharma                    br label %if.end.first
628*eadf2959SRithik Sharma                  if.end.first:
629*eadf2959SRithik Sharma                    br i1 %cond, label %if.end.second, label %if.then.second
630*eadf2959SRithik Sharma                  if.then.second:
631*eadf2959SRithik Sharma                    %sub_op0 = add i32 %op0, 1
632*eadf2959SRithik Sharma                    %sub = sub i32 %sub_op0, %op1
633*eadf2959SRithik Sharma                    br label %if.end.second
634*eadf2959SRithik Sharma                  if.end.second:
635*eadf2959SRithik Sharma                    ret void
636*eadf2959SRithik Sharma                  })");
637*eadf2959SRithik Sharma 
638*eadf2959SRithik Sharma   run(*M, "foo",
639*eadf2959SRithik Sharma       [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
640*eadf2959SRithik Sharma           DependenceInfo &DI) {
641*eadf2959SRithik Sharma         Instruction *AddInst = getInstructionByName(F, "add");
642*eadf2959SRithik Sharma         Instruction *SubInst = getInstructionByName(F, "sub");
643*eadf2959SRithik Sharma 
644*eadf2959SRithik Sharma         // Cannot move as %user uses %add and %sub doesn't dominates %user.
645*eadf2959SRithik Sharma         EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, PDT, DI));
646*eadf2959SRithik Sharma 
647*eadf2959SRithik Sharma         // Cannot move as %sub_op0 is an operand of %sub and %add doesn't
648*eadf2959SRithik Sharma         // dominates %sub_op0.
649*eadf2959SRithik Sharma         EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, PDT, DI));
650*eadf2959SRithik Sharma       });
651*eadf2959SRithik Sharma }
652