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"
103642d388SSimon Pilgrim #include "llvm/Analysis/AliasAnalysis.h"
11ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/AssumptionCache.h"
12ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h"
13ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/LoopInfo.h"
14ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h"
152ce38b3fSdfukalov #include "llvm/Analysis/TargetLibraryInfo.h"
16ae8a8c2dSTsang Whitney W.H #include "llvm/AsmParser/Parser.h"
17ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h"
18ae8a8c2dSTsang Whitney W.H #include "llvm/IR/LLVMContext.h"
19*74deadf1SNikita Popov #include "llvm/IR/Module.h"
20ae8a8c2dSTsang Whitney W.H #include "llvm/Support/SourceMgr.h"
21bcbd26bfSFlorian Hahn #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
22ae8a8c2dSTsang Whitney W.H #include "gtest/gtest.h"
23ae8a8c2dSTsang Whitney W.H
24ae8a8c2dSTsang Whitney W.H using namespace llvm;
25ae8a8c2dSTsang Whitney W.H
parseIR(LLVMContext & C,const char * IR)26ae8a8c2dSTsang Whitney W.H static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
27ae8a8c2dSTsang Whitney W.H SMDiagnostic Err;
28ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
29ae8a8c2dSTsang Whitney W.H if (!Mod)
30ae8a8c2dSTsang Whitney W.H Err.print("CodeMoverUtilsTests", errs());
31ae8a8c2dSTsang Whitney W.H return Mod;
32ae8a8c2dSTsang Whitney W.H }
33ae8a8c2dSTsang Whitney W.H
run(Module & M,StringRef FuncName,function_ref<void (Function & F,DominatorTree & DT,PostDominatorTree & PDT,DependenceInfo & DI)> Test)34ae8a8c2dSTsang Whitney W.H static void run(Module &M, StringRef FuncName,
35ae8a8c2dSTsang Whitney W.H function_ref<void(Function &F, DominatorTree &DT,
36ae8a8c2dSTsang Whitney W.H PostDominatorTree &PDT, DependenceInfo &DI)>
37ae8a8c2dSTsang Whitney W.H Test) {
38ae8a8c2dSTsang Whitney W.H auto *F = M.getFunction(FuncName);
39ae8a8c2dSTsang Whitney W.H DominatorTree DT(*F);
40ae8a8c2dSTsang Whitney W.H PostDominatorTree PDT(*F);
41ae8a8c2dSTsang Whitney W.H TargetLibraryInfoImpl TLII;
42ae8a8c2dSTsang Whitney W.H TargetLibraryInfo TLI(TLII);
43ae8a8c2dSTsang Whitney W.H AssumptionCache AC(*F);
44ae8a8c2dSTsang Whitney W.H AliasAnalysis AA(TLI);
45ae8a8c2dSTsang Whitney W.H LoopInfo LI(DT);
46ae8a8c2dSTsang Whitney W.H ScalarEvolution SE(*F, TLI, AC, DT, LI);
47ae8a8c2dSTsang Whitney W.H DependenceInfo DI(F, &AA, &SE, &LI);
48ae8a8c2dSTsang Whitney W.H Test(*F, DT, PDT, DI);
49ae8a8c2dSTsang Whitney W.H }
50ae8a8c2dSTsang Whitney W.H
getBasicBlockByName(Function & F,StringRef Name)5178dc6498SWhitney Tsang static BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
5278dc6498SWhitney Tsang for (BasicBlock &BB : F)
5378dc6498SWhitney Tsang if (BB.getName() == Name)
5478dc6498SWhitney Tsang return &BB;
5578dc6498SWhitney Tsang llvm_unreachable("Expected to find basic block!");
5678dc6498SWhitney Tsang }
5778dc6498SWhitney Tsang
getInstructionByName(Function & F,StringRef Name)5878dc6498SWhitney Tsang static Instruction *getInstructionByName(Function &F, StringRef Name) {
5978dc6498SWhitney Tsang for (BasicBlock &BB : F)
6078dc6498SWhitney Tsang for (Instruction &I : BB)
6178dc6498SWhitney Tsang if (I.getName() == Name)
6278dc6498SWhitney Tsang return &I;
6378dc6498SWhitney Tsang llvm_unreachable("Expected to find instruction!");
6478dc6498SWhitney Tsang }
6578dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentSimpleTest)6678dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentSimpleTest) {
6778dc6498SWhitney Tsang LLVMContext C;
6878dc6498SWhitney Tsang
6978dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) {
7078dc6498SWhitney Tsang // if (cond1)
7178dc6498SWhitney Tsang // i = 1;
7278dc6498SWhitney Tsang // if (cond1)
7378dc6498SWhitney Tsang // i = 2;
7478dc6498SWhitney Tsang // if (cond2)
7578dc6498SWhitney Tsang // i = 3;
7678dc6498SWhitney Tsang // }
7778dc6498SWhitney Tsang std::unique_ptr<Module> M =
7878dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
7978dc6498SWhitney Tsang entry:
8078dc6498SWhitney Tsang br i1 %cond1, label %if.first, label %if.first.end
8178dc6498SWhitney Tsang if.first:
8278dc6498SWhitney Tsang store i32 1, i32* %i, align 4
8378dc6498SWhitney Tsang br label %if.first.end
8478dc6498SWhitney Tsang if.first.end:
8578dc6498SWhitney Tsang br i1 %cond1, label %if.second, label %if.second.end
8678dc6498SWhitney Tsang if.second:
8778dc6498SWhitney Tsang store i32 2, i32* %i, align 4
8878dc6498SWhitney Tsang br label %if.second.end
8978dc6498SWhitney Tsang if.second.end:
9078dc6498SWhitney Tsang br i1 %cond2, label %if.third, label %if.third.end
9178dc6498SWhitney Tsang if.third:
9278dc6498SWhitney Tsang store i32 3, i32* %i, align 4
9378dc6498SWhitney Tsang br label %if.third.end
9478dc6498SWhitney Tsang if.third.end:
9578dc6498SWhitney Tsang ret void
9678dc6498SWhitney Tsang })");
9778dc6498SWhitney Tsang run(*M, "foo",
9878dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
9978dc6498SWhitney Tsang DependenceInfo &DI) {
10078dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
10178dc6498SWhitney Tsang EXPECT_TRUE(
10278dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *FirstIfBody, DT, PDT));
10378dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
10478dc6498SWhitney Tsang EXPECT_TRUE(
10578dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
10678dc6498SWhitney Tsang
10778dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
10878dc6498SWhitney Tsang EXPECT_FALSE(
10978dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
11078dc6498SWhitney Tsang EXPECT_FALSE(
11178dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
11278dc6498SWhitney Tsang });
11378dc6498SWhitney Tsang }
11478dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentOppositeCondTest)11578dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentOppositeCondTest) {
11678dc6498SWhitney Tsang LLVMContext C;
11778dc6498SWhitney Tsang
11878dc6498SWhitney Tsang // void foo(int &i, unsigned X, unsigned Y) {
11978dc6498SWhitney Tsang // if (X < Y)
12078dc6498SWhitney Tsang // i = 1;
12178dc6498SWhitney Tsang // if (Y > X)
12278dc6498SWhitney Tsang // i = 2;
12378dc6498SWhitney Tsang // if (X >= Y)
12478dc6498SWhitney Tsang // i = 3;
12578dc6498SWhitney Tsang // else
12678dc6498SWhitney Tsang // i = 4;
12778dc6498SWhitney Tsang // if (X == Y)
12878dc6498SWhitney Tsang // i = 5;
12978dc6498SWhitney Tsang // if (Y == X)
13078dc6498SWhitney Tsang // i = 6;
13178dc6498SWhitney Tsang // else
13278dc6498SWhitney Tsang // i = 7;
13378dc6498SWhitney Tsang // if (X != Y)
13478dc6498SWhitney Tsang // i = 8;
13578dc6498SWhitney Tsang // else
13678dc6498SWhitney Tsang // i = 9;
13778dc6498SWhitney Tsang // }
13878dc6498SWhitney Tsang std::unique_ptr<Module> M =
13978dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i32 %X, i32 %Y) {
14078dc6498SWhitney Tsang entry:
14178dc6498SWhitney Tsang %cmp1 = icmp ult i32 %X, %Y
14278dc6498SWhitney Tsang br i1 %cmp1, label %if.first, label %if.first.end
14378dc6498SWhitney Tsang if.first:
14478dc6498SWhitney Tsang store i32 1, i32* %i, align 4
14578dc6498SWhitney Tsang br label %if.first.end
14678dc6498SWhitney Tsang if.first.end:
14778dc6498SWhitney Tsang %cmp2 = icmp ugt i32 %Y, %X
14878dc6498SWhitney Tsang br i1 %cmp2, label %if.second, label %if.second.end
14978dc6498SWhitney Tsang if.second:
15078dc6498SWhitney Tsang store i32 2, i32* %i, align 4
15178dc6498SWhitney Tsang br label %if.second.end
15278dc6498SWhitney Tsang if.second.end:
15378dc6498SWhitney Tsang %cmp3 = icmp uge i32 %X, %Y
15478dc6498SWhitney Tsang br i1 %cmp3, label %if.third, label %if.third.else
15578dc6498SWhitney Tsang if.third:
15678dc6498SWhitney Tsang store i32 3, i32* %i, align 4
15778dc6498SWhitney Tsang br label %if.third.end
15878dc6498SWhitney Tsang if.third.else:
15978dc6498SWhitney Tsang store i32 4, i32* %i, align 4
16078dc6498SWhitney Tsang br label %if.third.end
16178dc6498SWhitney Tsang if.third.end:
16278dc6498SWhitney Tsang %cmp4 = icmp eq i32 %X, %Y
16378dc6498SWhitney Tsang br i1 %cmp4, label %if.fourth, label %if.fourth.end
16478dc6498SWhitney Tsang if.fourth:
16578dc6498SWhitney Tsang store i32 5, i32* %i, align 4
16678dc6498SWhitney Tsang br label %if.fourth.end
16778dc6498SWhitney Tsang if.fourth.end:
16878dc6498SWhitney Tsang %cmp5 = icmp eq i32 %Y, %X
16978dc6498SWhitney Tsang br i1 %cmp5, label %if.fifth, label %if.fifth.else
17078dc6498SWhitney Tsang if.fifth:
17178dc6498SWhitney Tsang store i32 6, i32* %i, align 4
17278dc6498SWhitney Tsang br label %if.fifth.end
17378dc6498SWhitney Tsang if.fifth.else:
17478dc6498SWhitney Tsang store i32 7, i32* %i, align 4
17578dc6498SWhitney Tsang br label %if.fifth.end
17678dc6498SWhitney Tsang if.fifth.end:
17778dc6498SWhitney Tsang %cmp6 = icmp ne i32 %X, %Y
17878dc6498SWhitney Tsang br i1 %cmp6, label %if.sixth, label %if.sixth.else
17978dc6498SWhitney Tsang if.sixth:
18078dc6498SWhitney Tsang store i32 8, i32* %i, align 4
18178dc6498SWhitney Tsang br label %if.sixth.end
18278dc6498SWhitney Tsang if.sixth.else:
18378dc6498SWhitney Tsang store i32 9, i32* %i, align 4
18478dc6498SWhitney Tsang br label %if.sixth.end
18578dc6498SWhitney Tsang if.sixth.end:
18678dc6498SWhitney Tsang ret void
18778dc6498SWhitney Tsang })");
18878dc6498SWhitney Tsang run(*M, "foo",
18978dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
19078dc6498SWhitney Tsang DependenceInfo &DI) {
19178dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
19278dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
19378dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
19478dc6498SWhitney Tsang BasicBlock *ThirdElseBody = getBasicBlockByName(F, "if.third.else");
19578dc6498SWhitney Tsang EXPECT_TRUE(
19678dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdElseBody, DT, PDT));
19778dc6498SWhitney Tsang EXPECT_TRUE(
19878dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdElseBody, DT, PDT));
19978dc6498SWhitney Tsang EXPECT_FALSE(
20078dc6498SWhitney Tsang isControlFlowEquivalent(*ThirdIfBody, *ThirdElseBody, DT, PDT));
20178dc6498SWhitney Tsang
20278dc6498SWhitney Tsang BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
20378dc6498SWhitney Tsang BasicBlock *FifthIfBody = getBasicBlockByName(F, "if.fifth");
20478dc6498SWhitney Tsang BasicBlock *FifthElseBody = getBasicBlockByName(F, "if.fifth.else");
20578dc6498SWhitney Tsang EXPECT_FALSE(
20678dc6498SWhitney Tsang isControlFlowEquivalent(*FifthIfBody, *FifthElseBody, DT, PDT));
20778dc6498SWhitney Tsang BasicBlock *SixthIfBody = getBasicBlockByName(F, "if.sixth");
20878dc6498SWhitney Tsang EXPECT_TRUE(
20978dc6498SWhitney Tsang isControlFlowEquivalent(*FifthElseBody, *SixthIfBody, DT, PDT));
21078dc6498SWhitney Tsang BasicBlock *SixthElseBody = getBasicBlockByName(F, "if.sixth.else");
21178dc6498SWhitney Tsang EXPECT_TRUE(
21278dc6498SWhitney Tsang isControlFlowEquivalent(*FourthIfBody, *SixthElseBody, DT, PDT));
21378dc6498SWhitney Tsang EXPECT_TRUE(
21478dc6498SWhitney Tsang isControlFlowEquivalent(*FifthIfBody, *SixthElseBody, DT, PDT));
21578dc6498SWhitney Tsang });
21678dc6498SWhitney Tsang }
21778dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentCondNestTest)21878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentCondNestTest) {
21978dc6498SWhitney Tsang LLVMContext C;
22078dc6498SWhitney Tsang
22178dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) {
22278dc6498SWhitney Tsang // if (cond1)
22378dc6498SWhitney Tsang // if (cond2)
22478dc6498SWhitney Tsang // i = 1;
22578dc6498SWhitney Tsang // if (cond2)
22678dc6498SWhitney Tsang // if (cond1)
22778dc6498SWhitney Tsang // i = 2;
22878dc6498SWhitney Tsang // }
22978dc6498SWhitney Tsang std::unique_ptr<Module> M =
23078dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) {
23178dc6498SWhitney Tsang entry:
23278dc6498SWhitney Tsang br i1 %cond1, label %if.outer.first, label %if.first.end
23378dc6498SWhitney Tsang if.outer.first:
23478dc6498SWhitney Tsang br i1 %cond2, label %if.inner.first, label %if.first.end
23578dc6498SWhitney Tsang if.inner.first:
23678dc6498SWhitney Tsang store i32 1, i32* %i, align 4
23778dc6498SWhitney Tsang br label %if.first.end
23878dc6498SWhitney Tsang if.first.end:
23978dc6498SWhitney Tsang br i1 %cond2, label %if.outer.second, label %if.second.end
24078dc6498SWhitney Tsang if.outer.second:
24178dc6498SWhitney Tsang br i1 %cond1, label %if.inner.second, label %if.second.end
24278dc6498SWhitney Tsang if.inner.second:
24378dc6498SWhitney Tsang store i32 2, i32* %i, align 4
24478dc6498SWhitney Tsang br label %if.second.end
24578dc6498SWhitney Tsang if.second.end:
24678dc6498SWhitney Tsang ret void
24778dc6498SWhitney Tsang })");
24878dc6498SWhitney Tsang run(*M, "foo",
24978dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
25078dc6498SWhitney Tsang DependenceInfo &DI) {
25178dc6498SWhitney Tsang BasicBlock *FirstOuterIfBody = getBasicBlockByName(F, "if.outer.first");
25278dc6498SWhitney Tsang BasicBlock *FirstInnerIfBody = getBasicBlockByName(F, "if.inner.first");
25378dc6498SWhitney Tsang BasicBlock *SecondOuterIfBody =
25478dc6498SWhitney Tsang getBasicBlockByName(F, "if.outer.second");
25578dc6498SWhitney Tsang BasicBlock *SecondInnerIfBody =
25678dc6498SWhitney Tsang getBasicBlockByName(F, "if.inner.second");
25778dc6498SWhitney Tsang EXPECT_TRUE(isControlFlowEquivalent(*FirstInnerIfBody,
25878dc6498SWhitney Tsang *SecondInnerIfBody, DT, PDT));
25978dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
26078dc6498SWhitney Tsang *SecondOuterIfBody, DT, PDT));
26178dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody,
26278dc6498SWhitney Tsang *SecondInnerIfBody, DT, PDT));
26378dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstInnerIfBody,
26478dc6498SWhitney Tsang *SecondOuterIfBody, DT, PDT));
26578dc6498SWhitney Tsang });
26678dc6498SWhitney Tsang }
26778dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentImbalanceTest)26878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentImbalanceTest) {
26978dc6498SWhitney Tsang LLVMContext C;
27078dc6498SWhitney Tsang
27178dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) {
27278dc6498SWhitney Tsang // if (cond1)
27378dc6498SWhitney Tsang // if (cond2)
27478dc6498SWhitney Tsang // if (cond3)
27578dc6498SWhitney Tsang // i = 1;
27678dc6498SWhitney Tsang // if (cond2)
27778dc6498SWhitney Tsang // if (cond3)
27878dc6498SWhitney Tsang // i = 2;
27978dc6498SWhitney Tsang // if (cond1)
28078dc6498SWhitney Tsang // if (cond1)
28178dc6498SWhitney Tsang // i = 3;
28278dc6498SWhitney Tsang // if (cond1)
28378dc6498SWhitney Tsang // i = 4;
28478dc6498SWhitney Tsang // }
28578dc6498SWhitney Tsang std::unique_ptr<Module> M = parseIR(
28678dc6498SWhitney Tsang C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2, i1 %cond3) {
28778dc6498SWhitney Tsang entry:
28878dc6498SWhitney Tsang br i1 %cond1, label %if.outer.first, label %if.first.end
28978dc6498SWhitney Tsang if.outer.first:
29078dc6498SWhitney Tsang br i1 %cond2, label %if.middle.first, label %if.first.end
29178dc6498SWhitney Tsang if.middle.first:
29278dc6498SWhitney Tsang br i1 %cond3, label %if.inner.first, label %if.first.end
29378dc6498SWhitney Tsang if.inner.first:
29478dc6498SWhitney Tsang store i32 1, i32* %i, align 4
29578dc6498SWhitney Tsang br label %if.first.end
29678dc6498SWhitney Tsang if.first.end:
29778dc6498SWhitney Tsang br i1 %cond2, label %if.outer.second, label %if.second.end
29878dc6498SWhitney Tsang if.outer.second:
29978dc6498SWhitney Tsang br i1 %cond3, label %if.inner.second, label %if.second.end
30078dc6498SWhitney Tsang if.inner.second:
30178dc6498SWhitney Tsang store i32 2, i32* %i, align 4
30278dc6498SWhitney Tsang br label %if.second.end
30378dc6498SWhitney Tsang if.second.end:
30478dc6498SWhitney Tsang br i1 %cond1, label %if.outer.third, label %if.third.end
30578dc6498SWhitney Tsang if.outer.third:
30678dc6498SWhitney Tsang br i1 %cond1, label %if.inner.third, label %if.third.end
30778dc6498SWhitney Tsang if.inner.third:
30878dc6498SWhitney Tsang store i32 3, i32* %i, align 4
30978dc6498SWhitney Tsang br label %if.third.end
31078dc6498SWhitney Tsang if.third.end:
31178dc6498SWhitney Tsang br i1 %cond1, label %if.fourth, label %if.fourth.end
31278dc6498SWhitney Tsang if.fourth:
31378dc6498SWhitney Tsang store i32 4, i32* %i, align 4
31478dc6498SWhitney Tsang br label %if.fourth.end
31578dc6498SWhitney Tsang if.fourth.end:
31678dc6498SWhitney Tsang ret void
31778dc6498SWhitney Tsang })");
31878dc6498SWhitney Tsang run(*M, "foo",
31978dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
32078dc6498SWhitney Tsang DependenceInfo &DI) {
32178dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.inner.first");
32278dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.inner.second");
32378dc6498SWhitney Tsang EXPECT_FALSE(
32478dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
32578dc6498SWhitney Tsang
32678dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.inner.third");
32778dc6498SWhitney Tsang BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth");
32878dc6498SWhitney Tsang EXPECT_TRUE(
32978dc6498SWhitney Tsang isControlFlowEquivalent(*ThirdIfBody, *FourthIfBody, DT, PDT));
33078dc6498SWhitney Tsang });
33178dc6498SWhitney Tsang }
33278dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentPointerTest)33378dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentPointerTest) {
33478dc6498SWhitney Tsang LLVMContext C;
33578dc6498SWhitney Tsang
33678dc6498SWhitney Tsang // void foo(int &i, int *cond) {
33778dc6498SWhitney Tsang // if (*cond)
33878dc6498SWhitney Tsang // i = 1;
33978dc6498SWhitney Tsang // if (*cond)
34078dc6498SWhitney Tsang // i = 2;
34178dc6498SWhitney Tsang // *cond = 1;
34278dc6498SWhitney Tsang // if (*cond)
34378dc6498SWhitney Tsang // i = 3;
34478dc6498SWhitney Tsang // }
34578dc6498SWhitney Tsang std::unique_ptr<Module> M =
34678dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i32* %cond) {
34778dc6498SWhitney Tsang entry:
34878dc6498SWhitney Tsang %0 = load i32, i32* %cond, align 4
34978dc6498SWhitney Tsang %tobool1 = icmp ne i32 %0, 0
35078dc6498SWhitney Tsang br i1 %tobool1, label %if.first, label %if.first.end
35178dc6498SWhitney Tsang if.first:
35278dc6498SWhitney Tsang store i32 1, i32* %i, align 4
35378dc6498SWhitney Tsang br label %if.first.end
35478dc6498SWhitney Tsang if.first.end:
35578dc6498SWhitney Tsang %1 = load i32, i32* %cond, align 4
35678dc6498SWhitney Tsang %tobool2 = icmp ne i32 %1, 0
35778dc6498SWhitney Tsang br i1 %tobool2, label %if.second, label %if.second.end
35878dc6498SWhitney Tsang if.second:
35978dc6498SWhitney Tsang store i32 2, i32* %i, align 4
36078dc6498SWhitney Tsang br label %if.second.end
36178dc6498SWhitney Tsang if.second.end:
36278dc6498SWhitney Tsang store i32 1, i32* %cond, align 4
36378dc6498SWhitney Tsang %2 = load i32, i32* %cond, align 4
36478dc6498SWhitney Tsang %tobool3 = icmp ne i32 %2, 0
36578dc6498SWhitney Tsang br i1 %tobool3, label %if.third, label %if.third.end
36678dc6498SWhitney Tsang if.third:
36778dc6498SWhitney Tsang store i32 3, i32* %i, align 4
36878dc6498SWhitney Tsang br label %if.third.end
36978dc6498SWhitney Tsang if.third.end:
37078dc6498SWhitney Tsang ret void
37178dc6498SWhitney Tsang })");
37278dc6498SWhitney Tsang run(*M, "foo",
37378dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
37478dc6498SWhitney Tsang DependenceInfo &DI) {
37578dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first");
37678dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second");
37778dc6498SWhitney Tsang // Limitation: if we can prove cond haven't been modify between %0 and
37878dc6498SWhitney Tsang // %1, then we can prove FirstIfBody and SecondIfBody are control flow
37978dc6498SWhitney Tsang // equivalent.
38078dc6498SWhitney Tsang EXPECT_FALSE(
38178dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT));
38278dc6498SWhitney Tsang
38378dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third");
38478dc6498SWhitney Tsang EXPECT_FALSE(
38578dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT));
38678dc6498SWhitney Tsang EXPECT_FALSE(
38778dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT));
38878dc6498SWhitney Tsang });
38978dc6498SWhitney Tsang }
39078dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsControlFlowEquivalentNotPostdomTest)39178dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentNotPostdomTest) {
39278dc6498SWhitney Tsang LLVMContext C;
39378dc6498SWhitney Tsang
39478dc6498SWhitney Tsang // void foo(bool cond1, bool cond2) {
39578dc6498SWhitney Tsang // if (cond1) {
39678dc6498SWhitney Tsang // if (cond2)
39778dc6498SWhitney Tsang // return;
39878dc6498SWhitney Tsang // } else
39978dc6498SWhitney Tsang // if (cond2)
40078dc6498SWhitney Tsang // return;
40178dc6498SWhitney Tsang // return;
40278dc6498SWhitney Tsang // }
40378dc6498SWhitney Tsang std::unique_ptr<Module> M =
40478dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i1 %cond1, i1 %cond2) {
40578dc6498SWhitney Tsang idom:
40678dc6498SWhitney Tsang br i1 %cond1, label %succ0, label %succ1
40778dc6498SWhitney Tsang succ0:
40878dc6498SWhitney Tsang br i1 %cond2, label %succ0ret, label %succ0succ1
40978dc6498SWhitney Tsang succ0ret:
41078dc6498SWhitney Tsang ret void
41178dc6498SWhitney Tsang succ0succ1:
41278dc6498SWhitney Tsang br label %bb
41378dc6498SWhitney Tsang succ1:
41478dc6498SWhitney Tsang br i1 %cond2, label %succ1ret, label %succ1succ1
41578dc6498SWhitney Tsang succ1ret:
41678dc6498SWhitney Tsang ret void
41778dc6498SWhitney Tsang succ1succ1:
41878dc6498SWhitney Tsang br label %bb
41978dc6498SWhitney Tsang bb:
42078dc6498SWhitney Tsang ret void
42178dc6498SWhitney Tsang })");
42278dc6498SWhitney Tsang run(*M, "foo",
42378dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
42478dc6498SWhitney Tsang DependenceInfo &DI) {
42578dc6498SWhitney Tsang BasicBlock &Idom = F.front();
42678dc6498SWhitney Tsang assert(Idom.getName() == "idom" && "Expecting BasicBlock idom");
42778dc6498SWhitney Tsang BasicBlock &BB = F.back();
42878dc6498SWhitney Tsang assert(BB.getName() == "bb" && "Expecting BasicBlock bb");
42978dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(Idom, BB, DT, PDT));
43078dc6498SWhitney Tsang });
43178dc6498SWhitney Tsang }
43278dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsSafeToMoveTest1)43378dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest1) {
434ae8a8c2dSTsang Whitney W.H LLVMContext C;
435ae8a8c2dSTsang Whitney W.H
436ae8a8c2dSTsang Whitney W.H // void safecall() noexcept willreturn nosync;
437ae8a8c2dSTsang Whitney W.H // void unsafecall();
438ae8a8c2dSTsang Whitney W.H // void foo(int * __restrict__ A, int * __restrict__ B, int * __restrict__ C,
439ae8a8c2dSTsang Whitney W.H // long N) {
440ae8a8c2dSTsang Whitney W.H // X = N / 1;
441ae8a8c2dSTsang Whitney W.H // safecall();
442ae8a8c2dSTsang Whitney W.H // unsafecall1();
443ae8a8c2dSTsang Whitney W.H // unsafecall2();
444ae8a8c2dSTsang Whitney W.H // for (long i = 0; i < N; ++i) {
445ae8a8c2dSTsang Whitney W.H // A[5] = 5;
446ae8a8c2dSTsang Whitney W.H // A[i] = 0;
447ae8a8c2dSTsang Whitney W.H // B[i] = A[i];
448ae8a8c2dSTsang Whitney W.H // C[i] = A[i];
449ae8a8c2dSTsang Whitney W.H // A[6] = 6;
450ae8a8c2dSTsang Whitney W.H // }
451ae8a8c2dSTsang Whitney W.H // }
452ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> M = parseIR(
45378dc6498SWhitney Tsang C, R"(define void @foo(i32* noalias %A, i32* noalias %B, i32* noalias %C
45478dc6498SWhitney Tsang , i64 %N) {
45578dc6498SWhitney Tsang entry:
45678dc6498SWhitney Tsang %X = sdiv i64 1, %N
45778dc6498SWhitney Tsang call void @safecall()
45878dc6498SWhitney Tsang %cmp1 = icmp slt i64 0, %N
45978dc6498SWhitney Tsang call void @unsafecall1()
46078dc6498SWhitney Tsang call void @unsafecall2()
46178dc6498SWhitney Tsang br i1 %cmp1, label %for.body, label %for.end
46278dc6498SWhitney Tsang for.body:
46378dc6498SWhitney Tsang %i = phi i64 [ 0, %entry ], [ %inc, %for.body ]
46478dc6498SWhitney Tsang %arrayidx_A5 = getelementptr inbounds i32, i32* %A, i64 5
46578dc6498SWhitney Tsang store i32 5, i32* %arrayidx_A5, align 4
46678dc6498SWhitney Tsang %arrayidx_A = getelementptr inbounds i32, i32* %A, i64 %i
46778dc6498SWhitney Tsang store i32 0, i32* %arrayidx_A, align 4
46878dc6498SWhitney Tsang %load1 = load i32, i32* %arrayidx_A, align 4
46978dc6498SWhitney Tsang %arrayidx_B = getelementptr inbounds i32, i32* %B, i64 %i
47078dc6498SWhitney Tsang store i32 %load1, i32* %arrayidx_B, align 4
47178dc6498SWhitney Tsang %load2 = load i32, i32* %arrayidx_A, align 4
47278dc6498SWhitney Tsang %arrayidx_C = getelementptr inbounds i32, i32* %C, i64 %i
47378dc6498SWhitney Tsang store i32 %load2, i32* %arrayidx_C, align 4
47478dc6498SWhitney Tsang %arrayidx_A6 = getelementptr inbounds i32, i32* %A, i64 6
47578dc6498SWhitney Tsang store i32 6, i32* %arrayidx_A6, align 4
47678dc6498SWhitney Tsang %inc = add nsw i64 %i, 1
47778dc6498SWhitney Tsang %cmp = icmp slt i64 %inc, %N
47878dc6498SWhitney Tsang br i1 %cmp, label %for.body, label %for.end
47978dc6498SWhitney Tsang for.end:
48078dc6498SWhitney Tsang ret void
48178dc6498SWhitney Tsang }
48278dc6498SWhitney Tsang declare void @safecall() nounwind nosync willreturn
48378dc6498SWhitney Tsang declare void @unsafecall1()
48478dc6498SWhitney Tsang declare void @unsafecall2())");
485ae8a8c2dSTsang Whitney W.H
486ae8a8c2dSTsang Whitney W.H run(*M, "foo",
487ae8a8c2dSTsang Whitney W.H [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
488ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) {
48978dc6498SWhitney Tsang BasicBlock *Entry = getBasicBlockByName(F, "entry");
490ae8a8c2dSTsang Whitney W.H Instruction *CI_safecall = Entry->front().getNextNode();
4915e40f2cfSVitaly Buka assert(isa<CallInst>(CI_safecall) &&
4925e40f2cfSVitaly Buka "Expecting CI_safecall to be a CallInst");
493ae8a8c2dSTsang Whitney W.H Instruction *CI_unsafecall = CI_safecall->getNextNode()->getNextNode();
4945e40f2cfSVitaly Buka assert(isa<CallInst>(CI_unsafecall) &&
4955e40f2cfSVitaly Buka "Expecting CI_unsafecall to be a CallInst");
49678dc6498SWhitney Tsang BasicBlock *ForBody = getBasicBlockByName(F, "for.body");
497ae8a8c2dSTsang Whitney W.H Instruction &PN = ForBody->front();
498ae8a8c2dSTsang Whitney W.H assert(isa<PHINode>(PN) && "Expecting PN to be a PHINode");
49978dc6498SWhitney Tsang Instruction *SI_A5 =
50078dc6498SWhitney Tsang getInstructionByName(F, "arrayidx_A5")->getNextNode();
50178dc6498SWhitney Tsang Instruction *SI = getInstructionByName(F, "arrayidx_A")->getNextNode();
50278dc6498SWhitney Tsang Instruction *LI1 = getInstructionByName(F, "load1");
50378dc6498SWhitney Tsang Instruction *LI2 = getInstructionByName(F, "load2");
5045e40f2cfSVitaly Buka Instruction *SI_A6 =
50578dc6498SWhitney Tsang getInstructionByName(F, "arrayidx_A6")->getNextNode();
506ae8a8c2dSTsang Whitney W.H
5075e40f2cfSVitaly Buka // Can move after CI_safecall, as it does not throw, not synchronize, or
5085e40f2cfSVitaly Buka // must return.
5095e40f2cfSVitaly Buka EXPECT_TRUE(isSafeToMoveBefore(*CI_safecall->getPrevNode(),
510082e3952SSharmaRithik *CI_safecall->getNextNode(), DT, &PDT,
511082e3952SSharmaRithik &DI));
512ae8a8c2dSTsang Whitney W.H
513ae8a8c2dSTsang Whitney W.H // Cannot move CI_unsafecall, as it may throw.
5145e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*CI_unsafecall->getNextNode(),
515082e3952SSharmaRithik *CI_unsafecall, DT, &PDT, &DI));
516ae8a8c2dSTsang Whitney W.H
517ae8a8c2dSTsang Whitney W.H // Moving instruction to non control flow equivalent places are not
518ae8a8c2dSTsang Whitney W.H // supported.
519167cac31SSharmaRithik EXPECT_FALSE(
520167cac31SSharmaRithik isSafeToMoveBefore(*SI_A5, *Entry->getTerminator(), DT, &PDT, &DI));
521ae8a8c2dSTsang Whitney W.H
522ae8a8c2dSTsang Whitney W.H // Moving PHINode is not supported.
5235e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(PN, *PN.getNextNode()->getNextNode(),
524082e3952SSharmaRithik DT, &PDT, &DI));
525ae8a8c2dSTsang Whitney W.H
526ae8a8c2dSTsang Whitney W.H // Cannot move non-PHINode before PHINode.
527082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*PN.getNextNode(), PN, DT, &PDT, &DI));
528ae8a8c2dSTsang Whitney W.H
529ae8a8c2dSTsang Whitney W.H // Moving Terminator is not supported.
5305e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*Entry->getTerminator(),
531082e3952SSharmaRithik *PN.getNextNode(), DT, &PDT, &DI));
532ae8a8c2dSTsang Whitney W.H
533ae8a8c2dSTsang Whitney W.H // Cannot move %arrayidx_A after SI, as SI is its user.
5345e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*SI->getPrevNode(), *SI->getNextNode(),
535082e3952SSharmaRithik DT, &PDT, &DI));
536ae8a8c2dSTsang Whitney W.H
537ae8a8c2dSTsang Whitney W.H // Cannot move SI before %arrayidx_A, as %arrayidx_A is its operand.
538082e3952SSharmaRithik EXPECT_FALSE(
539082e3952SSharmaRithik isSafeToMoveBefore(*SI, *SI->getPrevNode(), DT, &PDT, &DI));
540ae8a8c2dSTsang Whitney W.H
541ae8a8c2dSTsang Whitney W.H // Cannot move LI2 after SI_A6, as there is a flow dependence.
5425e40f2cfSVitaly Buka EXPECT_FALSE(
543082e3952SSharmaRithik isSafeToMoveBefore(*LI2, *SI_A6->getNextNode(), DT, &PDT, &DI));
544ae8a8c2dSTsang Whitney W.H
545ae8a8c2dSTsang Whitney W.H // Cannot move SI after LI1, as there is a anti dependence.
546082e3952SSharmaRithik EXPECT_FALSE(
547082e3952SSharmaRithik isSafeToMoveBefore(*SI, *LI1->getNextNode(), DT, &PDT, &DI));
548ae8a8c2dSTsang Whitney W.H
549ae8a8c2dSTsang Whitney W.H // Cannot move SI_A5 after SI, as there is a output dependence.
550082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*SI_A5, *LI1, DT, &PDT, &DI));
551ae8a8c2dSTsang Whitney W.H
552ae8a8c2dSTsang Whitney W.H // Can move LI2 before LI1, as there is only an input dependence.
553082e3952SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LI2, *LI1, DT, &PDT, &DI));
554ae8a8c2dSTsang Whitney W.H });
555ae8a8c2dSTsang Whitney W.H }
55678dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsSafeToMoveTest2)55778dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest2) {
55878dc6498SWhitney Tsang LLVMContext C;
55978dc6498SWhitney Tsang
56078dc6498SWhitney Tsang std::unique_ptr<Module> M =
56178dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) {
56278dc6498SWhitney Tsang entry:
56378dc6498SWhitney Tsang br i1 %cond, label %if.then.first, label %if.end.first
56478dc6498SWhitney Tsang if.then.first:
56578dc6498SWhitney Tsang %add = add i32 %op0, %op1
56678dc6498SWhitney Tsang %user = add i32 %add, 1
56778dc6498SWhitney Tsang br label %if.end.first
56878dc6498SWhitney Tsang if.end.first:
56978dc6498SWhitney Tsang br i1 %cond, label %if.then.second, label %if.end.second
57078dc6498SWhitney Tsang if.then.second:
57178dc6498SWhitney Tsang %sub_op0 = add i32 %op0, 1
57278dc6498SWhitney Tsang %sub = sub i32 %sub_op0, %op1
57378dc6498SWhitney Tsang br label %if.end.second
57478dc6498SWhitney Tsang if.end.second:
57578dc6498SWhitney Tsang ret void
57678dc6498SWhitney Tsang })");
57778dc6498SWhitney Tsang
57878dc6498SWhitney Tsang run(*M, "foo",
57978dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
58078dc6498SWhitney Tsang DependenceInfo &DI) {
58178dc6498SWhitney Tsang Instruction *AddInst = getInstructionByName(F, "add");
58278dc6498SWhitney Tsang Instruction *SubInst = getInstructionByName(F, "sub");
58378dc6498SWhitney Tsang
58478dc6498SWhitney Tsang // Cannot move as %user uses %add and %sub doesn't dominates %user.
585082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, &PDT, &DI));
58678dc6498SWhitney Tsang
58778dc6498SWhitney Tsang // Cannot move as %sub_op0 is an operand of %sub and %add doesn't
58878dc6498SWhitney Tsang // dominates %sub_op0.
589082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, &PDT, &DI));
59078dc6498SWhitney Tsang });
59178dc6498SWhitney Tsang }
59278dc6498SWhitney Tsang
TEST(CodeMoverUtils,IsSafeToMoveTest3)59378dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest3) {
59478dc6498SWhitney Tsang LLVMContext C;
59578dc6498SWhitney Tsang
59678dc6498SWhitney Tsang std::unique_ptr<Module> M = parseIR(C, R"(define void @foo(i64 %N) {
59778dc6498SWhitney Tsang entry:
59878dc6498SWhitney Tsang br label %for.body
59978dc6498SWhitney Tsang for.body:
60078dc6498SWhitney Tsang %i = phi i64 [ 0, %entry ], [ %inc, %for.latch ]
60178dc6498SWhitney Tsang %inc = add nsw i64 %i, 1
60278dc6498SWhitney Tsang br label %for.latch
60378dc6498SWhitney Tsang for.latch:
60478dc6498SWhitney Tsang %cmp = icmp slt i64 %inc, %N
605751be2a0SCongzhe Cao %add = add i64 100, %N
606751be2a0SCongzhe Cao %add2 = add i64 %add, %N
60778dc6498SWhitney Tsang br i1 %cmp, label %for.body, label %for.end
60878dc6498SWhitney Tsang for.end:
60978dc6498SWhitney Tsang ret void
61078dc6498SWhitney Tsang })");
61178dc6498SWhitney Tsang
61278dc6498SWhitney Tsang run(*M, "foo",
61378dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
61478dc6498SWhitney Tsang DependenceInfo &DI) {
61578dc6498SWhitney Tsang Instruction *IncInst = getInstructionByName(F, "inc");
61678dc6498SWhitney Tsang Instruction *CmpInst = getInstructionByName(F, "cmp");
617751be2a0SCongzhe Cao BasicBlock *BB0 = getBasicBlockByName(F, "for.body");
618751be2a0SCongzhe Cao BasicBlock *BB1 = getBasicBlockByName(F, "for.latch");
61978dc6498SWhitney Tsang
62078dc6498SWhitney Tsang // Can move as the incoming block of %inc for %i (%for.latch) dominated
62178dc6498SWhitney Tsang // by %cmp.
622082e3952SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*IncInst, *CmpInst, DT, &PDT, &DI));
623751be2a0SCongzhe Cao
624751be2a0SCongzhe Cao // Can move as the operands of instructions in BB1 either dominate
625751be2a0SCongzhe Cao // InsertPoint or appear before that instruction, e.g., %add appears
626751be2a0SCongzhe Cao // before %add2 although %add does not dominate InsertPoint.
627751be2a0SCongzhe Cao EXPECT_TRUE(
628751be2a0SCongzhe Cao isSafeToMoveBefore(*BB1, *BB0->getTerminator(), DT, &PDT, &DI));
62978dc6498SWhitney Tsang });
63078dc6498SWhitney Tsang }
631eadf2959SRithik Sharma
TEST(CodeMoverUtils,IsSafeToMoveTest4)632eadf2959SRithik Sharma TEST(CodeMoverUtils, IsSafeToMoveTest4) {
633eadf2959SRithik Sharma LLVMContext C;
634eadf2959SRithik Sharma
635eadf2959SRithik Sharma std::unique_ptr<Module> M =
636eadf2959SRithik Sharma parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) {
637eadf2959SRithik Sharma entry:
638eadf2959SRithik Sharma br i1 %cond, label %if.end.first, label %if.then.first
639eadf2959SRithik Sharma if.then.first:
640eadf2959SRithik Sharma %add = add i32 %op0, %op1
641eadf2959SRithik Sharma %user = add i32 %add, 1
642c4277275SCongzhe Cao %add2 = add i32 %op0, 1
643eadf2959SRithik Sharma br label %if.end.first
644eadf2959SRithik Sharma if.end.first:
645eadf2959SRithik Sharma br i1 %cond, label %if.end.second, label %if.then.second
646eadf2959SRithik Sharma if.then.second:
647eadf2959SRithik Sharma %sub_op0 = add i32 %op0, 1
648eadf2959SRithik Sharma %sub = sub i32 %sub_op0, %op1
649c4277275SCongzhe Cao %sub2 = sub i32 %op0, 1
650eadf2959SRithik Sharma br label %if.end.second
651eadf2959SRithik Sharma if.end.second:
652eadf2959SRithik Sharma ret void
653eadf2959SRithik Sharma })");
654eadf2959SRithik Sharma
655eadf2959SRithik Sharma run(*M, "foo",
656eadf2959SRithik Sharma [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
657eadf2959SRithik Sharma DependenceInfo &DI) {
658eadf2959SRithik Sharma Instruction *AddInst = getInstructionByName(F, "add");
659c4277275SCongzhe Cao Instruction *AddInst2 = getInstructionByName(F, "add2");
660eadf2959SRithik Sharma Instruction *SubInst = getInstructionByName(F, "sub");
661c4277275SCongzhe Cao Instruction *SubInst2 = getInstructionByName(F, "sub2");
662eadf2959SRithik Sharma
663eadf2959SRithik Sharma // Cannot move as %user uses %add and %sub doesn't dominates %user.
664082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, &PDT, &DI));
665eadf2959SRithik Sharma
666eadf2959SRithik Sharma // Cannot move as %sub_op0 is an operand of %sub and %add doesn't
667eadf2959SRithik Sharma // dominates %sub_op0.
668082e3952SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, &PDT, &DI));
669c4277275SCongzhe Cao
670c4277275SCongzhe Cao // Can move as %add2 and %sub2 are control flow equivalent,
671c4277275SCongzhe Cao // although %add2 does not strictly dominate %sub2.
672c4277275SCongzhe Cao EXPECT_TRUE(isSafeToMoveBefore(*AddInst2, *SubInst2, DT, &PDT, &DI));
673c4277275SCongzhe Cao
674c4277275SCongzhe Cao // Can move as %add2 and %sub2 are control flow equivalent,
675c4277275SCongzhe Cao // although %add2 does not strictly dominate %sub2.
676c4277275SCongzhe Cao EXPECT_TRUE(isSafeToMoveBefore(*SubInst2, *AddInst2, DT, &PDT, &DI));
677b0662a7aSCongzhe
678b0662a7aSCongzhe BasicBlock *BB0 = getBasicBlockByName(F, "if.then.first");
679b0662a7aSCongzhe BasicBlock *BB1 = getBasicBlockByName(F, "if.then.second");
680b0662a7aSCongzhe EXPECT_TRUE(
681b0662a7aSCongzhe isSafeToMoveBefore(*BB0, *BB1->getTerminator(), DT, &PDT, &DI));
682eadf2959SRithik Sharma });
683eadf2959SRithik Sharma }
684167cac31SSharmaRithik
TEST(CodeMoverUtils,IsSafeToMoveTest5)685167cac31SSharmaRithik TEST(CodeMoverUtils, IsSafeToMoveTest5) {
686167cac31SSharmaRithik LLVMContext C;
687167cac31SSharmaRithik
688167cac31SSharmaRithik std::unique_ptr<Module> M =
689167cac31SSharmaRithik parseIR(C, R"(define void @dependence(i32* noalias %A, i32* noalias %B){
690167cac31SSharmaRithik entry:
691167cac31SSharmaRithik store i32 0, i32* %A, align 4 ; storeA0
692167cac31SSharmaRithik store i32 2, i32* %A, align 4 ; storeA1
693167cac31SSharmaRithik %tmp0 = load i32, i32* %A, align 4 ; loadA0
694167cac31SSharmaRithik store i32 1, i32* %B, align 4 ; storeB0
695167cac31SSharmaRithik %tmp1 = load i32, i32* %A, align 4 ; loadA1
696167cac31SSharmaRithik store i32 2, i32* %A, align 4 ; storeA2
697167cac31SSharmaRithik store i32 4, i32* %B, align 4 ; StoreB1
698167cac31SSharmaRithik %tmp2 = load i32, i32* %A, align 4 ; loadA2
699167cac31SSharmaRithik %tmp3 = load i32, i32* %A, align 4 ; loadA3
700167cac31SSharmaRithik %tmp4 = load i32, i32* %B, align 4 ; loadB2
701167cac31SSharmaRithik %tmp5 = load i32, i32* %B, align 4 ; loadB3
702167cac31SSharmaRithik ret void
703167cac31SSharmaRithik })");
704167cac31SSharmaRithik
705167cac31SSharmaRithik run(*M, "dependence",
706167cac31SSharmaRithik [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
707167cac31SSharmaRithik DependenceInfo &DI) {
708167cac31SSharmaRithik Instruction *LoadA0 = getInstructionByName(F, "tmp0");
709167cac31SSharmaRithik Instruction *LoadA1 = getInstructionByName(F, "tmp1");
710167cac31SSharmaRithik Instruction *LoadA2 = getInstructionByName(F, "tmp2");
711167cac31SSharmaRithik Instruction *LoadA3 = getInstructionByName(F, "tmp3");
712167cac31SSharmaRithik Instruction *LoadB2 = getInstructionByName(F, "tmp4");
713167cac31SSharmaRithik Instruction *LoadB3 = getInstructionByName(F, "tmp5");
714167cac31SSharmaRithik Instruction *StoreA1 = LoadA0->getPrevNode();
715167cac31SSharmaRithik Instruction *StoreA0 = StoreA1->getPrevNode();
716167cac31SSharmaRithik Instruction *StoreB0 = LoadA0->getNextNode();
717167cac31SSharmaRithik Instruction *StoreB1 = LoadA2->getPrevNode();
718167cac31SSharmaRithik Instruction *StoreA2 = StoreB1->getPrevNode();
719167cac31SSharmaRithik
720167cac31SSharmaRithik // Input forward dependency
721167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA2, *LoadB2, DT, &PDT, &DI));
722167cac31SSharmaRithik // Input backward dependency
723167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA3, *LoadA2, DT, &PDT, &DI));
724167cac31SSharmaRithik
725167cac31SSharmaRithik // Output forward dependency
726167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*StoreA0, *LoadA0, DT, &PDT, &DI));
727167cac31SSharmaRithik // Output backward dependency
728167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*StoreA1, *StoreA0, DT, &PDT, &DI));
729167cac31SSharmaRithik
730167cac31SSharmaRithik // Flow forward dependency
731167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*StoreA1, *StoreB0, DT, &PDT, &DI));
732167cac31SSharmaRithik // Flow backward dependency
733167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*LoadA0, *StoreA1, DT, &PDT, &DI));
734167cac31SSharmaRithik
735167cac31SSharmaRithik // Anti forward dependency
736167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*LoadA1, *StoreB1, DT, &PDT, &DI));
737167cac31SSharmaRithik // Anti backward dependency
738167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*StoreA2, *LoadA1, DT, &PDT, &DI));
739167cac31SSharmaRithik
740167cac31SSharmaRithik // No input backward dependency
741167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadB2, *LoadA3, DT, &PDT, &DI));
742167cac31SSharmaRithik // No input forward dependency
743167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA3, *LoadB3, DT, &PDT, &DI));
744167cac31SSharmaRithik
745167cac31SSharmaRithik // No Output forward dependency
746167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*StoreA2, *LoadA2, DT, &PDT, &DI));
747167cac31SSharmaRithik // No Output backward dependency
748167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*StoreB1, *StoreA2, DT, &PDT, &DI));
749167cac31SSharmaRithik
750167cac31SSharmaRithik // No flow forward dependency
751167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*StoreB0, *StoreA2, DT, &PDT, &DI));
752167cac31SSharmaRithik // No flow backward dependency
753167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA1, *StoreB0, DT, &PDT, &DI));
754167cac31SSharmaRithik
755167cac31SSharmaRithik // No anti backward dependency
756167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*StoreB0, *LoadA0, DT, &PDT, &DI));
757167cac31SSharmaRithik // No anti forward dependency
758167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA0, *LoadA1, DT, &PDT, &DI));
759167cac31SSharmaRithik });
760167cac31SSharmaRithik }
761167cac31SSharmaRithik
TEST(CodeMoverUtils,IsSafeToMoveTest6)762167cac31SSharmaRithik TEST(CodeMoverUtils, IsSafeToMoveTest6) {
763167cac31SSharmaRithik LLVMContext C;
764167cac31SSharmaRithik
765167cac31SSharmaRithik std::unique_ptr<Module> M = parseIR(
766167cac31SSharmaRithik C, R"(define void @dependence(i1 %cond, i32* noalias %A, i32* noalias %B){
767167cac31SSharmaRithik entry:
768167cac31SSharmaRithik br i1 %cond, label %bb0, label %bb1
769167cac31SSharmaRithik bb0:
770167cac31SSharmaRithik br label %bb1
771167cac31SSharmaRithik bb1:
772167cac31SSharmaRithik store i32 0, i32* %A, align 4 ; storeA0
773167cac31SSharmaRithik br i1 %cond, label %bb2, label %bb3
774167cac31SSharmaRithik bb2:
775167cac31SSharmaRithik br label %bb3
776167cac31SSharmaRithik bb3:
777167cac31SSharmaRithik store i32 2, i32* %A, align 4 ; storeA1
778167cac31SSharmaRithik br i1 %cond, label %bb4, label %bb5
779167cac31SSharmaRithik bb4:
780167cac31SSharmaRithik br label %bb5
781167cac31SSharmaRithik bb5:
782167cac31SSharmaRithik %tmp0 = load i32, i32* %A, align 4 ; loadA0
783167cac31SSharmaRithik br i1 %cond, label %bb6, label %bb7
784167cac31SSharmaRithik bb6:
785167cac31SSharmaRithik br label %bb7
786167cac31SSharmaRithik bb7:
787167cac31SSharmaRithik store i32 1, i32* %B, align 4 ; storeB0
788167cac31SSharmaRithik br i1 %cond, label %bb8, label %bb9
789167cac31SSharmaRithik bb8:
790167cac31SSharmaRithik br label %bb9
791167cac31SSharmaRithik bb9:
792167cac31SSharmaRithik %tmp1 = load i32, i32* %A, align 4 ; loadA1
793167cac31SSharmaRithik br i1 %cond, label %bb10, label %bb11
794167cac31SSharmaRithik bb10:
795167cac31SSharmaRithik br label %bb11
796167cac31SSharmaRithik bb11:
797167cac31SSharmaRithik store i32 2, i32* %A, align 4 ; storeA2
798167cac31SSharmaRithik br i1 %cond, label %bb12, label %bb13
799167cac31SSharmaRithik bb12:
800167cac31SSharmaRithik br label %bb13
801167cac31SSharmaRithik bb13:
802167cac31SSharmaRithik store i32 4, i32* %B, align 4 ; StoreB1
803167cac31SSharmaRithik br i1 %cond, label %bb14, label %bb15
804167cac31SSharmaRithik bb14:
805167cac31SSharmaRithik br label %bb15
806167cac31SSharmaRithik bb15:
807167cac31SSharmaRithik %tmp2 = load i32, i32* %A, align 4 ; loadA2
808167cac31SSharmaRithik br i1 %cond, label %bb16, label %bb17
809167cac31SSharmaRithik bb16:
810167cac31SSharmaRithik br label %bb17
811167cac31SSharmaRithik bb17:
812167cac31SSharmaRithik %tmp3 = load i32, i32* %A, align 4 ; loadA3
813167cac31SSharmaRithik br i1 %cond, label %bb18, label %bb19
814167cac31SSharmaRithik bb18:
815167cac31SSharmaRithik br label %bb19
816167cac31SSharmaRithik bb19:
817167cac31SSharmaRithik %tmp4 = load i32, i32* %B, align 4 ; loadB2
818167cac31SSharmaRithik br i1 %cond, label %bb20, label %bb21
819167cac31SSharmaRithik bb20:
820167cac31SSharmaRithik br label %bb21
821167cac31SSharmaRithik bb21:
822167cac31SSharmaRithik %tmp5 = load i32, i32* %B, align 4 ; loadB3
823167cac31SSharmaRithik ret void
824167cac31SSharmaRithik })");
825167cac31SSharmaRithik run(*M, "dependence",
826167cac31SSharmaRithik [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
827167cac31SSharmaRithik DependenceInfo &DI) {
828167cac31SSharmaRithik BasicBlock *BB1 = getBasicBlockByName(F, "bb1");
829167cac31SSharmaRithik BasicBlock *BB3 = getBasicBlockByName(F, "bb3");
830167cac31SSharmaRithik BasicBlock *BB7 = getBasicBlockByName(F, "bb7");
831167cac31SSharmaRithik BasicBlock *BB11 = getBasicBlockByName(F, "bb11");
832167cac31SSharmaRithik BasicBlock *BB13 = getBasicBlockByName(F, "bb13");
833167cac31SSharmaRithik Instruction *LoadA0 = getInstructionByName(F, "tmp0");
834167cac31SSharmaRithik Instruction *LoadA1 = getInstructionByName(F, "tmp1");
835167cac31SSharmaRithik Instruction *LoadA2 = getInstructionByName(F, "tmp2");
836167cac31SSharmaRithik Instruction *LoadA3 = getInstructionByName(F, "tmp3");
837167cac31SSharmaRithik Instruction *LoadB2 = getInstructionByName(F, "tmp4");
838167cac31SSharmaRithik Instruction *LoadB3 = getInstructionByName(F, "tmp5");
839167cac31SSharmaRithik Instruction &StoreA1 = BB3->front();
840167cac31SSharmaRithik Instruction &StoreA0 = BB1->front();
841167cac31SSharmaRithik Instruction &StoreB0 = BB7->front();
842167cac31SSharmaRithik Instruction &StoreB1 = BB13->front();
843167cac31SSharmaRithik Instruction &StoreA2 = BB11->front();
844167cac31SSharmaRithik
845167cac31SSharmaRithik // Input forward dependency
846167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA2, *LoadB2, DT, &PDT, &DI));
847167cac31SSharmaRithik // Input backward dependency
848167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA3, *LoadA2, DT, &PDT, &DI));
849167cac31SSharmaRithik
850167cac31SSharmaRithik // Output forward dependency
851167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(StoreA0, *LoadA0, DT, &PDT, &DI));
852167cac31SSharmaRithik // Output backward dependency
853167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(StoreA1, StoreA0, DT, &PDT, &DI));
854167cac31SSharmaRithik
855167cac31SSharmaRithik // Flow forward dependency
856167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(StoreA1, StoreB0, DT, &PDT, &DI));
857167cac31SSharmaRithik // Flow backward dependency
858167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*LoadA0, StoreA1, DT, &PDT, &DI));
859167cac31SSharmaRithik
860167cac31SSharmaRithik // Anti forward dependency
861167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(*LoadA1, StoreB1, DT, &PDT, &DI));
862167cac31SSharmaRithik // Anti backward dependency
863167cac31SSharmaRithik EXPECT_FALSE(isSafeToMoveBefore(StoreA2, *LoadA1, DT, &PDT, &DI));
864167cac31SSharmaRithik
865167cac31SSharmaRithik // No input backward dependency
866167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadB2, *LoadA3, DT, &PDT, &DI));
867167cac31SSharmaRithik // No input forward dependency
868167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA3, *LoadB3, DT, &PDT, &DI));
869167cac31SSharmaRithik
870167cac31SSharmaRithik // No Output forward dependency
871167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(StoreA2, *LoadA2, DT, &PDT, &DI));
872167cac31SSharmaRithik // No Output backward dependency
873167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(StoreB1, StoreA2, DT, &PDT, &DI));
874167cac31SSharmaRithik
875167cac31SSharmaRithik // No flow forward dependency
876167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(StoreB0, StoreA2, DT, &PDT, &DI));
877167cac31SSharmaRithik // No flow backward dependency
878167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA1, StoreB0, DT, &PDT, &DI));
879167cac31SSharmaRithik
880167cac31SSharmaRithik // No anti backward dependency
881167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(StoreB0, *LoadA0, DT, &PDT, &DI));
882167cac31SSharmaRithik // No anti forward dependency
883167cac31SSharmaRithik EXPECT_TRUE(isSafeToMoveBefore(*LoadA0, *LoadA1, DT, &PDT, &DI));
884167cac31SSharmaRithik });
885167cac31SSharmaRithik }
886