1ae8a8c2dSTsang Whitney W.H //===- CodeMoverUtils.cpp - Unit tests for CodeMoverUtils ---------------===// 2ae8a8c2dSTsang Whitney W.H // 3ae8a8c2dSTsang Whitney W.H // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ae8a8c2dSTsang Whitney W.H // See https://llvm.org/LICENSE.txt for license information. 5ae8a8c2dSTsang Whitney W.H // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ae8a8c2dSTsang Whitney W.H // 7ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 8ae8a8c2dSTsang Whitney W.H 9ae8a8c2dSTsang Whitney W.H #include "llvm/Transforms/Utils/CodeMoverUtils.h" 10ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/AssumptionCache.h" 11ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h" 12ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/LoopInfo.h" 13ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h" 14ae8a8c2dSTsang Whitney W.H #include "llvm/AsmParser/Parser.h" 15ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h" 16ae8a8c2dSTsang Whitney W.H #include "llvm/IR/LLVMContext.h" 17ae8a8c2dSTsang Whitney W.H #include "llvm/Support/SourceMgr.h" 18bcbd26bfSFlorian Hahn #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" 19ae8a8c2dSTsang Whitney W.H #include "gtest/gtest.h" 20ae8a8c2dSTsang Whitney W.H 21ae8a8c2dSTsang Whitney W.H using namespace llvm; 22ae8a8c2dSTsang Whitney W.H 23ae8a8c2dSTsang Whitney W.H static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 24ae8a8c2dSTsang Whitney W.H SMDiagnostic Err; 25ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 26ae8a8c2dSTsang Whitney W.H if (!Mod) 27ae8a8c2dSTsang Whitney W.H Err.print("CodeMoverUtilsTests", errs()); 28ae8a8c2dSTsang Whitney W.H return Mod; 29ae8a8c2dSTsang Whitney W.H } 30ae8a8c2dSTsang Whitney W.H 31ae8a8c2dSTsang Whitney W.H static void run(Module &M, StringRef FuncName, 32ae8a8c2dSTsang Whitney W.H function_ref<void(Function &F, DominatorTree &DT, 33ae8a8c2dSTsang Whitney W.H PostDominatorTree &PDT, DependenceInfo &DI)> 34ae8a8c2dSTsang Whitney W.H Test) { 35ae8a8c2dSTsang Whitney W.H auto *F = M.getFunction(FuncName); 36ae8a8c2dSTsang Whitney W.H DominatorTree DT(*F); 37ae8a8c2dSTsang Whitney W.H PostDominatorTree PDT(*F); 38ae8a8c2dSTsang Whitney W.H TargetLibraryInfoImpl TLII; 39ae8a8c2dSTsang Whitney W.H TargetLibraryInfo TLI(TLII); 40ae8a8c2dSTsang Whitney W.H AssumptionCache AC(*F); 41ae8a8c2dSTsang Whitney W.H AliasAnalysis AA(TLI); 42ae8a8c2dSTsang Whitney W.H LoopInfo LI(DT); 43ae8a8c2dSTsang Whitney W.H ScalarEvolution SE(*F, TLI, AC, DT, LI); 44ae8a8c2dSTsang Whitney W.H DependenceInfo DI(F, &AA, &SE, &LI); 45ae8a8c2dSTsang Whitney W.H Test(*F, DT, PDT, DI); 46ae8a8c2dSTsang Whitney W.H } 47ae8a8c2dSTsang Whitney W.H 4878dc6498SWhitney Tsang static BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { 4978dc6498SWhitney Tsang for (BasicBlock &BB : F) 5078dc6498SWhitney Tsang if (BB.getName() == Name) 5178dc6498SWhitney Tsang return &BB; 5278dc6498SWhitney Tsang llvm_unreachable("Expected to find basic block!"); 5378dc6498SWhitney Tsang } 5478dc6498SWhitney Tsang 5578dc6498SWhitney Tsang static Instruction *getInstructionByName(Function &F, StringRef Name) { 5678dc6498SWhitney Tsang for (BasicBlock &BB : F) 5778dc6498SWhitney Tsang for (Instruction &I : BB) 5878dc6498SWhitney Tsang if (I.getName() == Name) 5978dc6498SWhitney Tsang return &I; 6078dc6498SWhitney Tsang llvm_unreachable("Expected to find instruction!"); 6178dc6498SWhitney Tsang } 6278dc6498SWhitney Tsang 6378dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentSimpleTest) { 6478dc6498SWhitney Tsang LLVMContext C; 6578dc6498SWhitney Tsang 6678dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) { 6778dc6498SWhitney Tsang // if (cond1) 6878dc6498SWhitney Tsang // i = 1; 6978dc6498SWhitney Tsang // if (cond1) 7078dc6498SWhitney Tsang // i = 2; 7178dc6498SWhitney Tsang // if (cond2) 7278dc6498SWhitney Tsang // i = 3; 7378dc6498SWhitney Tsang // } 7478dc6498SWhitney Tsang std::unique_ptr<Module> M = 7578dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) { 7678dc6498SWhitney Tsang entry: 7778dc6498SWhitney Tsang br i1 %cond1, label %if.first, label %if.first.end 7878dc6498SWhitney Tsang if.first: 7978dc6498SWhitney Tsang store i32 1, i32* %i, align 4 8078dc6498SWhitney Tsang br label %if.first.end 8178dc6498SWhitney Tsang if.first.end: 8278dc6498SWhitney Tsang br i1 %cond1, label %if.second, label %if.second.end 8378dc6498SWhitney Tsang if.second: 8478dc6498SWhitney Tsang store i32 2, i32* %i, align 4 8578dc6498SWhitney Tsang br label %if.second.end 8678dc6498SWhitney Tsang if.second.end: 8778dc6498SWhitney Tsang br i1 %cond2, label %if.third, label %if.third.end 8878dc6498SWhitney Tsang if.third: 8978dc6498SWhitney Tsang store i32 3, i32* %i, align 4 9078dc6498SWhitney Tsang br label %if.third.end 9178dc6498SWhitney Tsang if.third.end: 9278dc6498SWhitney Tsang ret void 9378dc6498SWhitney Tsang })"); 9478dc6498SWhitney Tsang run(*M, "foo", 9578dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 9678dc6498SWhitney Tsang DependenceInfo &DI) { 9778dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first"); 9878dc6498SWhitney Tsang EXPECT_TRUE( 9978dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *FirstIfBody, DT, PDT)); 10078dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second"); 10178dc6498SWhitney Tsang EXPECT_TRUE( 10278dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT)); 10378dc6498SWhitney Tsang 10478dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third"); 10578dc6498SWhitney Tsang EXPECT_FALSE( 10678dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT)); 10778dc6498SWhitney Tsang EXPECT_FALSE( 10878dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT)); 10978dc6498SWhitney Tsang }); 11078dc6498SWhitney Tsang } 11178dc6498SWhitney Tsang 11278dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentOppositeCondTest) { 11378dc6498SWhitney Tsang LLVMContext C; 11478dc6498SWhitney Tsang 11578dc6498SWhitney Tsang // void foo(int &i, unsigned X, unsigned Y) { 11678dc6498SWhitney Tsang // if (X < Y) 11778dc6498SWhitney Tsang // i = 1; 11878dc6498SWhitney Tsang // if (Y > X) 11978dc6498SWhitney Tsang // i = 2; 12078dc6498SWhitney Tsang // if (X >= Y) 12178dc6498SWhitney Tsang // i = 3; 12278dc6498SWhitney Tsang // else 12378dc6498SWhitney Tsang // i = 4; 12478dc6498SWhitney Tsang // if (X == Y) 12578dc6498SWhitney Tsang // i = 5; 12678dc6498SWhitney Tsang // if (Y == X) 12778dc6498SWhitney Tsang // i = 6; 12878dc6498SWhitney Tsang // else 12978dc6498SWhitney Tsang // i = 7; 13078dc6498SWhitney Tsang // if (X != Y) 13178dc6498SWhitney Tsang // i = 8; 13278dc6498SWhitney Tsang // else 13378dc6498SWhitney Tsang // i = 9; 13478dc6498SWhitney Tsang // } 13578dc6498SWhitney Tsang std::unique_ptr<Module> M = 13678dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i32 %X, i32 %Y) { 13778dc6498SWhitney Tsang entry: 13878dc6498SWhitney Tsang %cmp1 = icmp ult i32 %X, %Y 13978dc6498SWhitney Tsang br i1 %cmp1, label %if.first, label %if.first.end 14078dc6498SWhitney Tsang if.first: 14178dc6498SWhitney Tsang store i32 1, i32* %i, align 4 14278dc6498SWhitney Tsang br label %if.first.end 14378dc6498SWhitney Tsang if.first.end: 14478dc6498SWhitney Tsang %cmp2 = icmp ugt i32 %Y, %X 14578dc6498SWhitney Tsang br i1 %cmp2, label %if.second, label %if.second.end 14678dc6498SWhitney Tsang if.second: 14778dc6498SWhitney Tsang store i32 2, i32* %i, align 4 14878dc6498SWhitney Tsang br label %if.second.end 14978dc6498SWhitney Tsang if.second.end: 15078dc6498SWhitney Tsang %cmp3 = icmp uge i32 %X, %Y 15178dc6498SWhitney Tsang br i1 %cmp3, label %if.third, label %if.third.else 15278dc6498SWhitney Tsang if.third: 15378dc6498SWhitney Tsang store i32 3, i32* %i, align 4 15478dc6498SWhitney Tsang br label %if.third.end 15578dc6498SWhitney Tsang if.third.else: 15678dc6498SWhitney Tsang store i32 4, i32* %i, align 4 15778dc6498SWhitney Tsang br label %if.third.end 15878dc6498SWhitney Tsang if.third.end: 15978dc6498SWhitney Tsang %cmp4 = icmp eq i32 %X, %Y 16078dc6498SWhitney Tsang br i1 %cmp4, label %if.fourth, label %if.fourth.end 16178dc6498SWhitney Tsang if.fourth: 16278dc6498SWhitney Tsang store i32 5, i32* %i, align 4 16378dc6498SWhitney Tsang br label %if.fourth.end 16478dc6498SWhitney Tsang if.fourth.end: 16578dc6498SWhitney Tsang %cmp5 = icmp eq i32 %Y, %X 16678dc6498SWhitney Tsang br i1 %cmp5, label %if.fifth, label %if.fifth.else 16778dc6498SWhitney Tsang if.fifth: 16878dc6498SWhitney Tsang store i32 6, i32* %i, align 4 16978dc6498SWhitney Tsang br label %if.fifth.end 17078dc6498SWhitney Tsang if.fifth.else: 17178dc6498SWhitney Tsang store i32 7, i32* %i, align 4 17278dc6498SWhitney Tsang br label %if.fifth.end 17378dc6498SWhitney Tsang if.fifth.end: 17478dc6498SWhitney Tsang %cmp6 = icmp ne i32 %X, %Y 17578dc6498SWhitney Tsang br i1 %cmp6, label %if.sixth, label %if.sixth.else 17678dc6498SWhitney Tsang if.sixth: 17778dc6498SWhitney Tsang store i32 8, i32* %i, align 4 17878dc6498SWhitney Tsang br label %if.sixth.end 17978dc6498SWhitney Tsang if.sixth.else: 18078dc6498SWhitney Tsang store i32 9, i32* %i, align 4 18178dc6498SWhitney Tsang br label %if.sixth.end 18278dc6498SWhitney Tsang if.sixth.end: 18378dc6498SWhitney Tsang ret void 18478dc6498SWhitney Tsang })"); 18578dc6498SWhitney Tsang run(*M, "foo", 18678dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 18778dc6498SWhitney Tsang DependenceInfo &DI) { 18878dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first"); 18978dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second"); 19078dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third"); 19178dc6498SWhitney Tsang BasicBlock *ThirdElseBody = getBasicBlockByName(F, "if.third.else"); 19278dc6498SWhitney Tsang EXPECT_TRUE( 19378dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdElseBody, DT, PDT)); 19478dc6498SWhitney Tsang EXPECT_TRUE( 19578dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdElseBody, DT, PDT)); 19678dc6498SWhitney Tsang EXPECT_FALSE( 19778dc6498SWhitney Tsang isControlFlowEquivalent(*ThirdIfBody, *ThirdElseBody, DT, PDT)); 19878dc6498SWhitney Tsang 19978dc6498SWhitney Tsang BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth"); 20078dc6498SWhitney Tsang BasicBlock *FifthIfBody = getBasicBlockByName(F, "if.fifth"); 20178dc6498SWhitney Tsang BasicBlock *FifthElseBody = getBasicBlockByName(F, "if.fifth.else"); 20278dc6498SWhitney Tsang EXPECT_FALSE( 20378dc6498SWhitney Tsang isControlFlowEquivalent(*FifthIfBody, *FifthElseBody, DT, PDT)); 20478dc6498SWhitney Tsang BasicBlock *SixthIfBody = getBasicBlockByName(F, "if.sixth"); 20578dc6498SWhitney Tsang EXPECT_TRUE( 20678dc6498SWhitney Tsang isControlFlowEquivalent(*FifthElseBody, *SixthIfBody, DT, PDT)); 20778dc6498SWhitney Tsang BasicBlock *SixthElseBody = getBasicBlockByName(F, "if.sixth.else"); 20878dc6498SWhitney Tsang EXPECT_TRUE( 20978dc6498SWhitney Tsang isControlFlowEquivalent(*FourthIfBody, *SixthElseBody, DT, PDT)); 21078dc6498SWhitney Tsang EXPECT_TRUE( 21178dc6498SWhitney Tsang isControlFlowEquivalent(*FifthIfBody, *SixthElseBody, DT, PDT)); 21278dc6498SWhitney Tsang }); 21378dc6498SWhitney Tsang } 21478dc6498SWhitney Tsang 21578dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentCondNestTest) { 21678dc6498SWhitney Tsang LLVMContext C; 21778dc6498SWhitney Tsang 21878dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) { 21978dc6498SWhitney Tsang // if (cond1) 22078dc6498SWhitney Tsang // if (cond2) 22178dc6498SWhitney Tsang // i = 1; 22278dc6498SWhitney Tsang // if (cond2) 22378dc6498SWhitney Tsang // if (cond1) 22478dc6498SWhitney Tsang // i = 2; 22578dc6498SWhitney Tsang // } 22678dc6498SWhitney Tsang std::unique_ptr<Module> M = 22778dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2) { 22878dc6498SWhitney Tsang entry: 22978dc6498SWhitney Tsang br i1 %cond1, label %if.outer.first, label %if.first.end 23078dc6498SWhitney Tsang if.outer.first: 23178dc6498SWhitney Tsang br i1 %cond2, label %if.inner.first, label %if.first.end 23278dc6498SWhitney Tsang if.inner.first: 23378dc6498SWhitney Tsang store i32 1, i32* %i, align 4 23478dc6498SWhitney Tsang br label %if.first.end 23578dc6498SWhitney Tsang if.first.end: 23678dc6498SWhitney Tsang br i1 %cond2, label %if.outer.second, label %if.second.end 23778dc6498SWhitney Tsang if.outer.second: 23878dc6498SWhitney Tsang br i1 %cond1, label %if.inner.second, label %if.second.end 23978dc6498SWhitney Tsang if.inner.second: 24078dc6498SWhitney Tsang store i32 2, i32* %i, align 4 24178dc6498SWhitney Tsang br label %if.second.end 24278dc6498SWhitney Tsang if.second.end: 24378dc6498SWhitney Tsang ret void 24478dc6498SWhitney Tsang })"); 24578dc6498SWhitney Tsang run(*M, "foo", 24678dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 24778dc6498SWhitney Tsang DependenceInfo &DI) { 24878dc6498SWhitney Tsang BasicBlock *FirstOuterIfBody = getBasicBlockByName(F, "if.outer.first"); 24978dc6498SWhitney Tsang BasicBlock *FirstInnerIfBody = getBasicBlockByName(F, "if.inner.first"); 25078dc6498SWhitney Tsang BasicBlock *SecondOuterIfBody = 25178dc6498SWhitney Tsang getBasicBlockByName(F, "if.outer.second"); 25278dc6498SWhitney Tsang BasicBlock *SecondInnerIfBody = 25378dc6498SWhitney Tsang getBasicBlockByName(F, "if.inner.second"); 25478dc6498SWhitney Tsang EXPECT_TRUE(isControlFlowEquivalent(*FirstInnerIfBody, 25578dc6498SWhitney Tsang *SecondInnerIfBody, DT, PDT)); 25678dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody, 25778dc6498SWhitney Tsang *SecondOuterIfBody, DT, PDT)); 25878dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstOuterIfBody, 25978dc6498SWhitney Tsang *SecondInnerIfBody, DT, PDT)); 26078dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(*FirstInnerIfBody, 26178dc6498SWhitney Tsang *SecondOuterIfBody, DT, PDT)); 26278dc6498SWhitney Tsang }); 26378dc6498SWhitney Tsang } 26478dc6498SWhitney Tsang 26578dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentImbalanceTest) { 26678dc6498SWhitney Tsang LLVMContext C; 26778dc6498SWhitney Tsang 26878dc6498SWhitney Tsang // void foo(int &i, bool cond1, bool cond2) { 26978dc6498SWhitney Tsang // if (cond1) 27078dc6498SWhitney Tsang // if (cond2) 27178dc6498SWhitney Tsang // if (cond3) 27278dc6498SWhitney Tsang // i = 1; 27378dc6498SWhitney Tsang // if (cond2) 27478dc6498SWhitney Tsang // if (cond3) 27578dc6498SWhitney Tsang // i = 2; 27678dc6498SWhitney Tsang // if (cond1) 27778dc6498SWhitney Tsang // if (cond1) 27878dc6498SWhitney Tsang // i = 3; 27978dc6498SWhitney Tsang // if (cond1) 28078dc6498SWhitney Tsang // i = 4; 28178dc6498SWhitney Tsang // } 28278dc6498SWhitney Tsang std::unique_ptr<Module> M = parseIR( 28378dc6498SWhitney Tsang C, R"(define void @foo(i32* %i, i1 %cond1, i1 %cond2, i1 %cond3) { 28478dc6498SWhitney Tsang entry: 28578dc6498SWhitney Tsang br i1 %cond1, label %if.outer.first, label %if.first.end 28678dc6498SWhitney Tsang if.outer.first: 28778dc6498SWhitney Tsang br i1 %cond2, label %if.middle.first, label %if.first.end 28878dc6498SWhitney Tsang if.middle.first: 28978dc6498SWhitney Tsang br i1 %cond3, label %if.inner.first, label %if.first.end 29078dc6498SWhitney Tsang if.inner.first: 29178dc6498SWhitney Tsang store i32 1, i32* %i, align 4 29278dc6498SWhitney Tsang br label %if.first.end 29378dc6498SWhitney Tsang if.first.end: 29478dc6498SWhitney Tsang br i1 %cond2, label %if.outer.second, label %if.second.end 29578dc6498SWhitney Tsang if.outer.second: 29678dc6498SWhitney Tsang br i1 %cond3, label %if.inner.second, label %if.second.end 29778dc6498SWhitney Tsang if.inner.second: 29878dc6498SWhitney Tsang store i32 2, i32* %i, align 4 29978dc6498SWhitney Tsang br label %if.second.end 30078dc6498SWhitney Tsang if.second.end: 30178dc6498SWhitney Tsang br i1 %cond1, label %if.outer.third, label %if.third.end 30278dc6498SWhitney Tsang if.outer.third: 30378dc6498SWhitney Tsang br i1 %cond1, label %if.inner.third, label %if.third.end 30478dc6498SWhitney Tsang if.inner.third: 30578dc6498SWhitney Tsang store i32 3, i32* %i, align 4 30678dc6498SWhitney Tsang br label %if.third.end 30778dc6498SWhitney Tsang if.third.end: 30878dc6498SWhitney Tsang br i1 %cond1, label %if.fourth, label %if.fourth.end 30978dc6498SWhitney Tsang if.fourth: 31078dc6498SWhitney Tsang store i32 4, i32* %i, align 4 31178dc6498SWhitney Tsang br label %if.fourth.end 31278dc6498SWhitney Tsang if.fourth.end: 31378dc6498SWhitney Tsang ret void 31478dc6498SWhitney Tsang })"); 31578dc6498SWhitney Tsang run(*M, "foo", 31678dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 31778dc6498SWhitney Tsang DependenceInfo &DI) { 31878dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.inner.first"); 31978dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.inner.second"); 32078dc6498SWhitney Tsang EXPECT_FALSE( 32178dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT)); 32278dc6498SWhitney Tsang 32378dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.inner.third"); 32478dc6498SWhitney Tsang BasicBlock *FourthIfBody = getBasicBlockByName(F, "if.fourth"); 32578dc6498SWhitney Tsang EXPECT_TRUE( 32678dc6498SWhitney Tsang isControlFlowEquivalent(*ThirdIfBody, *FourthIfBody, DT, PDT)); 32778dc6498SWhitney Tsang }); 32878dc6498SWhitney Tsang } 32978dc6498SWhitney Tsang 33078dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentPointerTest) { 33178dc6498SWhitney Tsang LLVMContext C; 33278dc6498SWhitney Tsang 33378dc6498SWhitney Tsang // void foo(int &i, int *cond) { 33478dc6498SWhitney Tsang // if (*cond) 33578dc6498SWhitney Tsang // i = 1; 33678dc6498SWhitney Tsang // if (*cond) 33778dc6498SWhitney Tsang // i = 2; 33878dc6498SWhitney Tsang // *cond = 1; 33978dc6498SWhitney Tsang // if (*cond) 34078dc6498SWhitney Tsang // i = 3; 34178dc6498SWhitney Tsang // } 34278dc6498SWhitney Tsang std::unique_ptr<Module> M = 34378dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i32* %i, i32* %cond) { 34478dc6498SWhitney Tsang entry: 34578dc6498SWhitney Tsang %0 = load i32, i32* %cond, align 4 34678dc6498SWhitney Tsang %tobool1 = icmp ne i32 %0, 0 34778dc6498SWhitney Tsang br i1 %tobool1, label %if.first, label %if.first.end 34878dc6498SWhitney Tsang if.first: 34978dc6498SWhitney Tsang store i32 1, i32* %i, align 4 35078dc6498SWhitney Tsang br label %if.first.end 35178dc6498SWhitney Tsang if.first.end: 35278dc6498SWhitney Tsang %1 = load i32, i32* %cond, align 4 35378dc6498SWhitney Tsang %tobool2 = icmp ne i32 %1, 0 35478dc6498SWhitney Tsang br i1 %tobool2, label %if.second, label %if.second.end 35578dc6498SWhitney Tsang if.second: 35678dc6498SWhitney Tsang store i32 2, i32* %i, align 4 35778dc6498SWhitney Tsang br label %if.second.end 35878dc6498SWhitney Tsang if.second.end: 35978dc6498SWhitney Tsang store i32 1, i32* %cond, align 4 36078dc6498SWhitney Tsang %2 = load i32, i32* %cond, align 4 36178dc6498SWhitney Tsang %tobool3 = icmp ne i32 %2, 0 36278dc6498SWhitney Tsang br i1 %tobool3, label %if.third, label %if.third.end 36378dc6498SWhitney Tsang if.third: 36478dc6498SWhitney Tsang store i32 3, i32* %i, align 4 36578dc6498SWhitney Tsang br label %if.third.end 36678dc6498SWhitney Tsang if.third.end: 36778dc6498SWhitney Tsang ret void 36878dc6498SWhitney Tsang })"); 36978dc6498SWhitney Tsang run(*M, "foo", 37078dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 37178dc6498SWhitney Tsang DependenceInfo &DI) { 37278dc6498SWhitney Tsang BasicBlock *FirstIfBody = getBasicBlockByName(F, "if.first"); 37378dc6498SWhitney Tsang BasicBlock *SecondIfBody = getBasicBlockByName(F, "if.second"); 37478dc6498SWhitney Tsang // Limitation: if we can prove cond haven't been modify between %0 and 37578dc6498SWhitney Tsang // %1, then we can prove FirstIfBody and SecondIfBody are control flow 37678dc6498SWhitney Tsang // equivalent. 37778dc6498SWhitney Tsang EXPECT_FALSE( 37878dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *SecondIfBody, DT, PDT)); 37978dc6498SWhitney Tsang 38078dc6498SWhitney Tsang BasicBlock *ThirdIfBody = getBasicBlockByName(F, "if.third"); 38178dc6498SWhitney Tsang EXPECT_FALSE( 38278dc6498SWhitney Tsang isControlFlowEquivalent(*FirstIfBody, *ThirdIfBody, DT, PDT)); 38378dc6498SWhitney Tsang EXPECT_FALSE( 38478dc6498SWhitney Tsang isControlFlowEquivalent(*SecondIfBody, *ThirdIfBody, DT, PDT)); 38578dc6498SWhitney Tsang }); 38678dc6498SWhitney Tsang } 38778dc6498SWhitney Tsang 38878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsControlFlowEquivalentNotPostdomTest) { 38978dc6498SWhitney Tsang LLVMContext C; 39078dc6498SWhitney Tsang 39178dc6498SWhitney Tsang // void foo(bool cond1, bool cond2) { 39278dc6498SWhitney Tsang // if (cond1) { 39378dc6498SWhitney Tsang // if (cond2) 39478dc6498SWhitney Tsang // return; 39578dc6498SWhitney Tsang // } else 39678dc6498SWhitney Tsang // if (cond2) 39778dc6498SWhitney Tsang // return; 39878dc6498SWhitney Tsang // return; 39978dc6498SWhitney Tsang // } 40078dc6498SWhitney Tsang std::unique_ptr<Module> M = 40178dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i1 %cond1, i1 %cond2) { 40278dc6498SWhitney Tsang idom: 40378dc6498SWhitney Tsang br i1 %cond1, label %succ0, label %succ1 40478dc6498SWhitney Tsang succ0: 40578dc6498SWhitney Tsang br i1 %cond2, label %succ0ret, label %succ0succ1 40678dc6498SWhitney Tsang succ0ret: 40778dc6498SWhitney Tsang ret void 40878dc6498SWhitney Tsang succ0succ1: 40978dc6498SWhitney Tsang br label %bb 41078dc6498SWhitney Tsang succ1: 41178dc6498SWhitney Tsang br i1 %cond2, label %succ1ret, label %succ1succ1 41278dc6498SWhitney Tsang succ1ret: 41378dc6498SWhitney Tsang ret void 41478dc6498SWhitney Tsang succ1succ1: 41578dc6498SWhitney Tsang br label %bb 41678dc6498SWhitney Tsang bb: 41778dc6498SWhitney Tsang ret void 41878dc6498SWhitney Tsang })"); 41978dc6498SWhitney Tsang run(*M, "foo", 42078dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 42178dc6498SWhitney Tsang DependenceInfo &DI) { 42278dc6498SWhitney Tsang BasicBlock &Idom = F.front(); 42378dc6498SWhitney Tsang assert(Idom.getName() == "idom" && "Expecting BasicBlock idom"); 42478dc6498SWhitney Tsang BasicBlock &BB = F.back(); 42578dc6498SWhitney Tsang assert(BB.getName() == "bb" && "Expecting BasicBlock bb"); 42678dc6498SWhitney Tsang EXPECT_FALSE(isControlFlowEquivalent(Idom, BB, DT, PDT)); 42778dc6498SWhitney Tsang }); 42878dc6498SWhitney Tsang } 42978dc6498SWhitney Tsang 43078dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest1) { 431ae8a8c2dSTsang Whitney W.H LLVMContext C; 432ae8a8c2dSTsang Whitney W.H 433ae8a8c2dSTsang Whitney W.H // void safecall() noexcept willreturn nosync; 434ae8a8c2dSTsang Whitney W.H // void unsafecall(); 435ae8a8c2dSTsang Whitney W.H // void foo(int * __restrict__ A, int * __restrict__ B, int * __restrict__ C, 436ae8a8c2dSTsang Whitney W.H // long N) { 437ae8a8c2dSTsang Whitney W.H // X = N / 1; 438ae8a8c2dSTsang Whitney W.H // safecall(); 439ae8a8c2dSTsang Whitney W.H // unsafecall1(); 440ae8a8c2dSTsang Whitney W.H // unsafecall2(); 441ae8a8c2dSTsang Whitney W.H // for (long i = 0; i < N; ++i) { 442ae8a8c2dSTsang Whitney W.H // A[5] = 5; 443ae8a8c2dSTsang Whitney W.H // A[i] = 0; 444ae8a8c2dSTsang Whitney W.H // B[i] = A[i]; 445ae8a8c2dSTsang Whitney W.H // C[i] = A[i]; 446ae8a8c2dSTsang Whitney W.H // A[6] = 6; 447ae8a8c2dSTsang Whitney W.H // } 448ae8a8c2dSTsang Whitney W.H // } 449ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> M = parseIR( 45078dc6498SWhitney Tsang C, R"(define void @foo(i32* noalias %A, i32* noalias %B, i32* noalias %C 45178dc6498SWhitney Tsang , i64 %N) { 45278dc6498SWhitney Tsang entry: 45378dc6498SWhitney Tsang %X = sdiv i64 1, %N 45478dc6498SWhitney Tsang call void @safecall() 45578dc6498SWhitney Tsang %cmp1 = icmp slt i64 0, %N 45678dc6498SWhitney Tsang call void @unsafecall1() 45778dc6498SWhitney Tsang call void @unsafecall2() 45878dc6498SWhitney Tsang br i1 %cmp1, label %for.body, label %for.end 45978dc6498SWhitney Tsang for.body: 46078dc6498SWhitney Tsang %i = phi i64 [ 0, %entry ], [ %inc, %for.body ] 46178dc6498SWhitney Tsang %arrayidx_A5 = getelementptr inbounds i32, i32* %A, i64 5 46278dc6498SWhitney Tsang store i32 5, i32* %arrayidx_A5, align 4 46378dc6498SWhitney Tsang %arrayidx_A = getelementptr inbounds i32, i32* %A, i64 %i 46478dc6498SWhitney Tsang store i32 0, i32* %arrayidx_A, align 4 46578dc6498SWhitney Tsang %load1 = load i32, i32* %arrayidx_A, align 4 46678dc6498SWhitney Tsang %arrayidx_B = getelementptr inbounds i32, i32* %B, i64 %i 46778dc6498SWhitney Tsang store i32 %load1, i32* %arrayidx_B, align 4 46878dc6498SWhitney Tsang %load2 = load i32, i32* %arrayidx_A, align 4 46978dc6498SWhitney Tsang %arrayidx_C = getelementptr inbounds i32, i32* %C, i64 %i 47078dc6498SWhitney Tsang store i32 %load2, i32* %arrayidx_C, align 4 47178dc6498SWhitney Tsang %arrayidx_A6 = getelementptr inbounds i32, i32* %A, i64 6 47278dc6498SWhitney Tsang store i32 6, i32* %arrayidx_A6, align 4 47378dc6498SWhitney Tsang %inc = add nsw i64 %i, 1 47478dc6498SWhitney Tsang %cmp = icmp slt i64 %inc, %N 47578dc6498SWhitney Tsang br i1 %cmp, label %for.body, label %for.end 47678dc6498SWhitney Tsang for.end: 47778dc6498SWhitney Tsang ret void 47878dc6498SWhitney Tsang } 47978dc6498SWhitney Tsang declare void @safecall() nounwind nosync willreturn 48078dc6498SWhitney Tsang declare void @unsafecall1() 48178dc6498SWhitney Tsang declare void @unsafecall2())"); 482ae8a8c2dSTsang Whitney W.H 483ae8a8c2dSTsang Whitney W.H run(*M, "foo", 484ae8a8c2dSTsang Whitney W.H [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 485ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) { 48678dc6498SWhitney Tsang BasicBlock *Entry = getBasicBlockByName(F, "entry"); 487ae8a8c2dSTsang Whitney W.H Instruction *CI_safecall = Entry->front().getNextNode(); 4885e40f2cfSVitaly Buka assert(isa<CallInst>(CI_safecall) && 4895e40f2cfSVitaly Buka "Expecting CI_safecall to be a CallInst"); 490ae8a8c2dSTsang Whitney W.H Instruction *CI_unsafecall = CI_safecall->getNextNode()->getNextNode(); 4915e40f2cfSVitaly Buka assert(isa<CallInst>(CI_unsafecall) && 4925e40f2cfSVitaly Buka "Expecting CI_unsafecall to be a CallInst"); 49378dc6498SWhitney Tsang BasicBlock *ForBody = getBasicBlockByName(F, "for.body"); 494ae8a8c2dSTsang Whitney W.H Instruction &PN = ForBody->front(); 495ae8a8c2dSTsang Whitney W.H assert(isa<PHINode>(PN) && "Expecting PN to be a PHINode"); 49678dc6498SWhitney Tsang Instruction *SI_A5 = 49778dc6498SWhitney Tsang getInstructionByName(F, "arrayidx_A5")->getNextNode(); 49878dc6498SWhitney Tsang Instruction *SI = getInstructionByName(F, "arrayidx_A")->getNextNode(); 49978dc6498SWhitney Tsang Instruction *LI1 = getInstructionByName(F, "load1"); 50078dc6498SWhitney Tsang Instruction *LI2 = getInstructionByName(F, "load2"); 5015e40f2cfSVitaly Buka Instruction *SI_A6 = 50278dc6498SWhitney Tsang getInstructionByName(F, "arrayidx_A6")->getNextNode(); 503ae8a8c2dSTsang Whitney W.H 5045e40f2cfSVitaly Buka // Can move after CI_safecall, as it does not throw, not synchronize, or 5055e40f2cfSVitaly Buka // must return. 5065e40f2cfSVitaly Buka EXPECT_TRUE(isSafeToMoveBefore(*CI_safecall->getPrevNode(), 5075e40f2cfSVitaly Buka *CI_safecall->getNextNode(), DT, PDT, 5085e40f2cfSVitaly Buka DI)); 509ae8a8c2dSTsang Whitney W.H 510ae8a8c2dSTsang Whitney W.H // Cannot move CI_unsafecall, as it may throw. 5115e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*CI_unsafecall->getNextNode(), 5125e40f2cfSVitaly Buka *CI_unsafecall, DT, PDT, DI)); 513ae8a8c2dSTsang Whitney W.H 514ae8a8c2dSTsang Whitney W.H // Moving instruction to non control flow equivalent places are not 515ae8a8c2dSTsang Whitney W.H // supported. 5165e40f2cfSVitaly Buka EXPECT_FALSE( 5175e40f2cfSVitaly Buka isSafeToMoveBefore(*SI_A5, *Entry->getTerminator(), DT, PDT, DI)); 518ae8a8c2dSTsang Whitney W.H 519ae8a8c2dSTsang Whitney W.H // Moving PHINode is not supported. 5205e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(PN, *PN.getNextNode()->getNextNode(), 5215e40f2cfSVitaly Buka DT, PDT, DI)); 522ae8a8c2dSTsang Whitney W.H 523ae8a8c2dSTsang Whitney W.H // Cannot move non-PHINode before PHINode. 524ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*PN.getNextNode(), PN, DT, PDT, DI)); 525ae8a8c2dSTsang Whitney W.H 526ae8a8c2dSTsang Whitney W.H // Moving Terminator is not supported. 5275e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*Entry->getTerminator(), 5285e40f2cfSVitaly Buka *PN.getNextNode(), DT, PDT, DI)); 529ae8a8c2dSTsang Whitney W.H 530ae8a8c2dSTsang Whitney W.H // Cannot move %arrayidx_A after SI, as SI is its user. 5315e40f2cfSVitaly Buka EXPECT_FALSE(isSafeToMoveBefore(*SI->getPrevNode(), *SI->getNextNode(), 5325e40f2cfSVitaly Buka DT, PDT, DI)); 533ae8a8c2dSTsang Whitney W.H 534ae8a8c2dSTsang Whitney W.H // Cannot move SI before %arrayidx_A, as %arrayidx_A is its operand. 535ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI, *SI->getPrevNode(), DT, PDT, DI)); 536ae8a8c2dSTsang Whitney W.H 537ae8a8c2dSTsang Whitney W.H // Cannot move LI2 after SI_A6, as there is a flow dependence. 5385e40f2cfSVitaly Buka EXPECT_FALSE( 5395e40f2cfSVitaly Buka isSafeToMoveBefore(*LI2, *SI_A6->getNextNode(), DT, PDT, DI)); 540ae8a8c2dSTsang Whitney W.H 541ae8a8c2dSTsang Whitney W.H // Cannot move SI after LI1, as there is a anti dependence. 542ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI, *LI1->getNextNode(), DT, PDT, DI)); 543ae8a8c2dSTsang Whitney W.H 544ae8a8c2dSTsang Whitney W.H // Cannot move SI_A5 after SI, as there is a output dependence. 545ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI_A5, *LI1, DT, PDT, DI)); 546ae8a8c2dSTsang Whitney W.H 547ae8a8c2dSTsang Whitney W.H // Can move LI2 before LI1, as there is only an input dependence. 548ae8a8c2dSTsang Whitney W.H EXPECT_TRUE(isSafeToMoveBefore(*LI2, *LI1, DT, PDT, DI)); 549ae8a8c2dSTsang Whitney W.H }); 550ae8a8c2dSTsang Whitney W.H } 55178dc6498SWhitney Tsang 55278dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest2) { 55378dc6498SWhitney Tsang LLVMContext C; 55478dc6498SWhitney Tsang 55578dc6498SWhitney Tsang std::unique_ptr<Module> M = 55678dc6498SWhitney Tsang parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) { 55778dc6498SWhitney Tsang entry: 55878dc6498SWhitney Tsang br i1 %cond, label %if.then.first, label %if.end.first 55978dc6498SWhitney Tsang if.then.first: 56078dc6498SWhitney Tsang %add = add i32 %op0, %op1 56178dc6498SWhitney Tsang %user = add i32 %add, 1 56278dc6498SWhitney Tsang br label %if.end.first 56378dc6498SWhitney Tsang if.end.first: 56478dc6498SWhitney Tsang br i1 %cond, label %if.then.second, label %if.end.second 56578dc6498SWhitney Tsang if.then.second: 56678dc6498SWhitney Tsang %sub_op0 = add i32 %op0, 1 56778dc6498SWhitney Tsang %sub = sub i32 %sub_op0, %op1 56878dc6498SWhitney Tsang br label %if.end.second 56978dc6498SWhitney Tsang if.end.second: 57078dc6498SWhitney Tsang ret void 57178dc6498SWhitney Tsang })"); 57278dc6498SWhitney Tsang 57378dc6498SWhitney Tsang run(*M, "foo", 57478dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 57578dc6498SWhitney Tsang DependenceInfo &DI) { 57678dc6498SWhitney Tsang Instruction *AddInst = getInstructionByName(F, "add"); 57778dc6498SWhitney Tsang Instruction *SubInst = getInstructionByName(F, "sub"); 57878dc6498SWhitney Tsang 57978dc6498SWhitney Tsang // Cannot move as %user uses %add and %sub doesn't dominates %user. 58078dc6498SWhitney Tsang EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, PDT, DI)); 58178dc6498SWhitney Tsang 58278dc6498SWhitney Tsang // Cannot move as %sub_op0 is an operand of %sub and %add doesn't 58378dc6498SWhitney Tsang // dominates %sub_op0. 58478dc6498SWhitney Tsang EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, PDT, DI)); 58578dc6498SWhitney Tsang }); 58678dc6498SWhitney Tsang } 58778dc6498SWhitney Tsang 58878dc6498SWhitney Tsang TEST(CodeMoverUtils, IsSafeToMoveTest3) { 58978dc6498SWhitney Tsang LLVMContext C; 59078dc6498SWhitney Tsang 59178dc6498SWhitney Tsang std::unique_ptr<Module> M = parseIR(C, R"(define void @foo(i64 %N) { 59278dc6498SWhitney Tsang entry: 59378dc6498SWhitney Tsang br label %for.body 59478dc6498SWhitney Tsang for.body: 59578dc6498SWhitney Tsang %i = phi i64 [ 0, %entry ], [ %inc, %for.latch ] 59678dc6498SWhitney Tsang %inc = add nsw i64 %i, 1 59778dc6498SWhitney Tsang br label %for.latch 59878dc6498SWhitney Tsang for.latch: 59978dc6498SWhitney Tsang %cmp = icmp slt i64 %inc, %N 60078dc6498SWhitney Tsang br i1 %cmp, label %for.body, label %for.end 60178dc6498SWhitney Tsang for.end: 60278dc6498SWhitney Tsang ret void 60378dc6498SWhitney Tsang })"); 60478dc6498SWhitney Tsang 60578dc6498SWhitney Tsang run(*M, "foo", 60678dc6498SWhitney Tsang [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 60778dc6498SWhitney Tsang DependenceInfo &DI) { 60878dc6498SWhitney Tsang Instruction *IncInst = getInstructionByName(F, "inc"); 60978dc6498SWhitney Tsang Instruction *CmpInst = getInstructionByName(F, "cmp"); 61078dc6498SWhitney Tsang 61178dc6498SWhitney Tsang // Can move as the incoming block of %inc for %i (%for.latch) dominated 61278dc6498SWhitney Tsang // by %cmp. 61378dc6498SWhitney Tsang EXPECT_TRUE(isSafeToMoveBefore(*IncInst, *CmpInst, DT, PDT, DI)); 61478dc6498SWhitney Tsang }); 61578dc6498SWhitney Tsang } 616*eadf2959SRithik Sharma 617*eadf2959SRithik Sharma TEST(CodeMoverUtils, IsSafeToMoveTest4) { 618*eadf2959SRithik Sharma LLVMContext C; 619*eadf2959SRithik Sharma 620*eadf2959SRithik Sharma std::unique_ptr<Module> M = 621*eadf2959SRithik Sharma parseIR(C, R"(define void @foo(i1 %cond, i32 %op0, i32 %op1) { 622*eadf2959SRithik Sharma entry: 623*eadf2959SRithik Sharma br i1 %cond, label %if.end.first, label %if.then.first 624*eadf2959SRithik Sharma if.then.first: 625*eadf2959SRithik Sharma %add = add i32 %op0, %op1 626*eadf2959SRithik Sharma %user = add i32 %add, 1 627*eadf2959SRithik Sharma br label %if.end.first 628*eadf2959SRithik Sharma if.end.first: 629*eadf2959SRithik Sharma br i1 %cond, label %if.end.second, label %if.then.second 630*eadf2959SRithik Sharma if.then.second: 631*eadf2959SRithik Sharma %sub_op0 = add i32 %op0, 1 632*eadf2959SRithik Sharma %sub = sub i32 %sub_op0, %op1 633*eadf2959SRithik Sharma br label %if.end.second 634*eadf2959SRithik Sharma if.end.second: 635*eadf2959SRithik Sharma ret void 636*eadf2959SRithik Sharma })"); 637*eadf2959SRithik Sharma 638*eadf2959SRithik Sharma run(*M, "foo", 639*eadf2959SRithik Sharma [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 640*eadf2959SRithik Sharma DependenceInfo &DI) { 641*eadf2959SRithik Sharma Instruction *AddInst = getInstructionByName(F, "add"); 642*eadf2959SRithik Sharma Instruction *SubInst = getInstructionByName(F, "sub"); 643*eadf2959SRithik Sharma 644*eadf2959SRithik Sharma // Cannot move as %user uses %add and %sub doesn't dominates %user. 645*eadf2959SRithik Sharma EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, PDT, DI)); 646*eadf2959SRithik Sharma 647*eadf2959SRithik Sharma // Cannot move as %sub_op0 is an operand of %sub and %add doesn't 648*eadf2959SRithik Sharma // dominates %sub_op0. 649*eadf2959SRithik Sharma EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, PDT, DI)); 650*eadf2959SRithik Sharma }); 651*eadf2959SRithik Sharma } 652