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