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