1*ae8a8c2dSTsang Whitney W.H //===- CodeMoverUtils.cpp - Unit tests for CodeMoverUtils ---------------===// 2*ae8a8c2dSTsang Whitney W.H // 3*ae8a8c2dSTsang Whitney W.H // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*ae8a8c2dSTsang Whitney W.H // See https://llvm.org/LICENSE.txt for license information. 5*ae8a8c2dSTsang Whitney W.H // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*ae8a8c2dSTsang Whitney W.H // 7*ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 8*ae8a8c2dSTsang Whitney W.H 9*ae8a8c2dSTsang Whitney W.H #include "llvm/Transforms/Utils/CodeMoverUtils.h" 10*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/AssumptionCache.h" 11*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h" 12*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/LoopInfo.h" 13*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h" 14*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/ScalarEvolutionExpander.h" 15*ae8a8c2dSTsang Whitney W.H #include "llvm/AsmParser/Parser.h" 16*ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h" 17*ae8a8c2dSTsang Whitney W.H #include "llvm/IR/LLVMContext.h" 18*ae8a8c2dSTsang Whitney W.H #include "llvm/Support/SourceMgr.h" 19*ae8a8c2dSTsang Whitney W.H #include "gtest/gtest.h" 20*ae8a8c2dSTsang Whitney W.H 21*ae8a8c2dSTsang Whitney W.H using namespace llvm; 22*ae8a8c2dSTsang Whitney W.H 23*ae8a8c2dSTsang Whitney W.H static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 24*ae8a8c2dSTsang Whitney W.H SMDiagnostic Err; 25*ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 26*ae8a8c2dSTsang Whitney W.H if (!Mod) 27*ae8a8c2dSTsang Whitney W.H Err.print("CodeMoverUtilsTests", errs()); 28*ae8a8c2dSTsang Whitney W.H return Mod; 29*ae8a8c2dSTsang Whitney W.H } 30*ae8a8c2dSTsang Whitney W.H 31*ae8a8c2dSTsang Whitney W.H static void run(Module &M, StringRef FuncName, 32*ae8a8c2dSTsang Whitney W.H function_ref<void(Function &F, DominatorTree &DT, 33*ae8a8c2dSTsang Whitney W.H PostDominatorTree &PDT, DependenceInfo &DI)> 34*ae8a8c2dSTsang Whitney W.H Test) { 35*ae8a8c2dSTsang Whitney W.H auto *F = M.getFunction(FuncName); 36*ae8a8c2dSTsang Whitney W.H DominatorTree DT(*F); 37*ae8a8c2dSTsang Whitney W.H PostDominatorTree PDT(*F); 38*ae8a8c2dSTsang Whitney W.H TargetLibraryInfoImpl TLII; 39*ae8a8c2dSTsang Whitney W.H TargetLibraryInfo TLI(TLII); 40*ae8a8c2dSTsang Whitney W.H AssumptionCache AC(*F); 41*ae8a8c2dSTsang Whitney W.H AliasAnalysis AA(TLI); 42*ae8a8c2dSTsang Whitney W.H LoopInfo LI(DT); 43*ae8a8c2dSTsang Whitney W.H ScalarEvolution SE(*F, TLI, AC, DT, LI); 44*ae8a8c2dSTsang Whitney W.H DependenceInfo DI(F, &AA, &SE, &LI); 45*ae8a8c2dSTsang Whitney W.H Test(*F, DT, PDT, DI); 46*ae8a8c2dSTsang Whitney W.H } 47*ae8a8c2dSTsang Whitney W.H 48*ae8a8c2dSTsang Whitney W.H TEST(CodeMoverUtils, BasicTest) { 49*ae8a8c2dSTsang Whitney W.H LLVMContext C; 50*ae8a8c2dSTsang Whitney W.H 51*ae8a8c2dSTsang Whitney W.H // void safecall() noexcept willreturn nosync; 52*ae8a8c2dSTsang Whitney W.H // void unsafecall(); 53*ae8a8c2dSTsang Whitney W.H // void foo(int * __restrict__ A, int * __restrict__ B, int * __restrict__ C, 54*ae8a8c2dSTsang Whitney W.H // long N) { 55*ae8a8c2dSTsang Whitney W.H // X = N / 1; 56*ae8a8c2dSTsang Whitney W.H // safecall(); 57*ae8a8c2dSTsang Whitney W.H // unsafecall1(); 58*ae8a8c2dSTsang Whitney W.H // unsafecall2(); 59*ae8a8c2dSTsang Whitney W.H // for (long i = 0; i < N; ++i) { 60*ae8a8c2dSTsang Whitney W.H // A[5] = 5; 61*ae8a8c2dSTsang Whitney W.H // A[i] = 0; 62*ae8a8c2dSTsang Whitney W.H // B[i] = A[i]; 63*ae8a8c2dSTsang Whitney W.H // C[i] = A[i]; 64*ae8a8c2dSTsang Whitney W.H // A[6] = 6; 65*ae8a8c2dSTsang Whitney W.H // } 66*ae8a8c2dSTsang Whitney W.H // } 67*ae8a8c2dSTsang Whitney W.H std::unique_ptr<Module> M = parseIR( 68*ae8a8c2dSTsang Whitney W.H C, 69*ae8a8c2dSTsang Whitney W.H "define void @foo(i32* noalias %A, i32* noalias %B, i32* noalias %C\n" 70*ae8a8c2dSTsang Whitney W.H " , i64 %N) {\n" 71*ae8a8c2dSTsang Whitney W.H "entry:\n" 72*ae8a8c2dSTsang Whitney W.H " %X = sdiv i64 1, %N\n" 73*ae8a8c2dSTsang Whitney W.H " call void @safecall()\n" 74*ae8a8c2dSTsang Whitney W.H " %cmp1 = icmp slt i64 0, %N\n" 75*ae8a8c2dSTsang Whitney W.H " call void @unsafecall1()\n" 76*ae8a8c2dSTsang Whitney W.H " call void @unsafecall2()\n" 77*ae8a8c2dSTsang Whitney W.H " br i1 %cmp1, label %for.body, label %for.end\n" 78*ae8a8c2dSTsang Whitney W.H "for.body:\n" 79*ae8a8c2dSTsang Whitney W.H " %i = phi i64 [ 0, %entry ], [ %inc, %for.body ]\n" 80*ae8a8c2dSTsang Whitney W.H " %arrayidx_A5 = getelementptr inbounds i32, i32* %A, i64 5\n" 81*ae8a8c2dSTsang Whitney W.H " store i32 5, i32* %arrayidx_A5, align 4\n" 82*ae8a8c2dSTsang Whitney W.H " %arrayidx_A = getelementptr inbounds i32, i32* %A, i64 %i\n" 83*ae8a8c2dSTsang Whitney W.H " store i32 0, i32* %arrayidx_A, align 4\n" 84*ae8a8c2dSTsang Whitney W.H " %load1 = load i32, i32* %arrayidx_A, align 4\n" 85*ae8a8c2dSTsang Whitney W.H " %arrayidx_B = getelementptr inbounds i32, i32* %B, i64 %i\n" 86*ae8a8c2dSTsang Whitney W.H " store i32 %load1, i32* %arrayidx_B, align 4\n" 87*ae8a8c2dSTsang Whitney W.H " %load2 = load i32, i32* %arrayidx_A, align 4\n" 88*ae8a8c2dSTsang Whitney W.H " %arrayidx_C = getelementptr inbounds i32, i32* %C, i64 %i\n" 89*ae8a8c2dSTsang Whitney W.H " store i32 %load2, i32* %arrayidx_C, align 4\n" 90*ae8a8c2dSTsang Whitney W.H " %arrayidx_A6 = getelementptr inbounds i32, i32* %A, i64 6\n" 91*ae8a8c2dSTsang Whitney W.H " store i32 6, i32* %arrayidx_A6, align 4\n" 92*ae8a8c2dSTsang Whitney W.H " %inc = add nsw i64 %i, 1\n" 93*ae8a8c2dSTsang Whitney W.H " %cmp = icmp slt i64 %inc, %N\n" 94*ae8a8c2dSTsang Whitney W.H " br i1 %cmp, label %for.body, label %for.end\n" 95*ae8a8c2dSTsang Whitney W.H "for.end:\n" 96*ae8a8c2dSTsang Whitney W.H " ret void\n" 97*ae8a8c2dSTsang Whitney W.H "}\n" 98*ae8a8c2dSTsang Whitney W.H "declare void @safecall() nounwind nosync willreturn\n" 99*ae8a8c2dSTsang Whitney W.H "declare void @unsafecall1()\n" 100*ae8a8c2dSTsang Whitney W.H "declare void @unsafecall2()\n"); 101*ae8a8c2dSTsang Whitney W.H 102*ae8a8c2dSTsang Whitney W.H run(*M, "foo", 103*ae8a8c2dSTsang Whitney W.H [&](Function &F, DominatorTree &DT, PostDominatorTree &PDT, 104*ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) { 105*ae8a8c2dSTsang Whitney W.H Function::iterator FI = F.begin(); 106*ae8a8c2dSTsang Whitney W.H BasicBlock *Entry = &*(FI++); 107*ae8a8c2dSTsang Whitney W.H assert(Entry->getName() == "entry" && "Expecting BasicBlock entry"); 108*ae8a8c2dSTsang Whitney W.H Instruction *CI_safecall = Entry->front().getNextNode(); 109*ae8a8c2dSTsang Whitney W.H assert(isa<CallInst>(CI_safecall) && "Expecting CI_safecall to be a CallInst"); 110*ae8a8c2dSTsang Whitney W.H Instruction *CI_unsafecall = CI_safecall->getNextNode()->getNextNode(); 111*ae8a8c2dSTsang Whitney W.H assert(isa<CallInst>(CI_unsafecall) && "Expecting CI_unsafecall to be a CallInst"); 112*ae8a8c2dSTsang Whitney W.H BasicBlock *ForBody = &*(FI++); 113*ae8a8c2dSTsang Whitney W.H assert(ForBody->getName() == "for.body" && 114*ae8a8c2dSTsang Whitney W.H "Expecting BasicBlock for.body"); 115*ae8a8c2dSTsang Whitney W.H Instruction &PN = ForBody->front(); 116*ae8a8c2dSTsang Whitney W.H assert(isa<PHINode>(PN) && "Expecting PN to be a PHINode"); 117*ae8a8c2dSTsang Whitney W.H Instruction *SI_A5 = PN.getNextNode()->getNextNode(); 118*ae8a8c2dSTsang Whitney W.H assert(isa<StoreInst>(SI_A5) && 119*ae8a8c2dSTsang Whitney W.H SI_A5->getOperand(1)->getName() == "arrayidx_A5" && 120*ae8a8c2dSTsang Whitney W.H "Expecting store to arrayidx_A5"); 121*ae8a8c2dSTsang Whitney W.H Instruction *SI = SI_A5->getNextNode()->getNextNode(); 122*ae8a8c2dSTsang Whitney W.H assert(isa<StoreInst>(SI) && 123*ae8a8c2dSTsang Whitney W.H SI->getOperand(1)->getName() == "arrayidx_A" && 124*ae8a8c2dSTsang Whitney W.H "Expecting store to arrayidx_A"); 125*ae8a8c2dSTsang Whitney W.H Instruction *LI1 = SI->getNextNode(); 126*ae8a8c2dSTsang Whitney W.H assert(LI1->getName() == "load1" && "Expecting LI1 to be load1"); 127*ae8a8c2dSTsang Whitney W.H Instruction *LI2 = LI1->getNextNode()->getNextNode()->getNextNode(); 128*ae8a8c2dSTsang Whitney W.H assert(LI2->getName() == "load2" && "Expecting LI2 to be load2"); 129*ae8a8c2dSTsang Whitney W.H Instruction *SI_A6 = LI2->getNextNode()->getNextNode()->getNextNode()->getNextNode(); 130*ae8a8c2dSTsang Whitney W.H assert(isa<StoreInst>(SI_A6) && 131*ae8a8c2dSTsang Whitney W.H SI_A6->getOperand(1)->getName() == "arrayidx_A6" && 132*ae8a8c2dSTsang Whitney W.H "Expecting store to arrayidx_A6"); 133*ae8a8c2dSTsang Whitney W.H 134*ae8a8c2dSTsang Whitney W.H // Can move after CI_safecall, as it does not throw, not synchronize, or must return. 135*ae8a8c2dSTsang Whitney W.H EXPECT_TRUE(isSafeToMoveBefore(*CI_safecall->getPrevNode(), *CI_safecall->getNextNode(), DT, PDT, DI)); 136*ae8a8c2dSTsang Whitney W.H 137*ae8a8c2dSTsang Whitney W.H // Cannot move CI_unsafecall, as it may throw. 138*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*CI_unsafecall->getNextNode(), *CI_unsafecall, DT, PDT, DI)); 139*ae8a8c2dSTsang Whitney W.H 140*ae8a8c2dSTsang Whitney W.H // Moving instruction to non control flow equivalent places are not 141*ae8a8c2dSTsang Whitney W.H // supported. 142*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI_A5, *Entry->getTerminator(), DT, PDT, DI)); 143*ae8a8c2dSTsang Whitney W.H 144*ae8a8c2dSTsang Whitney W.H // Moving PHINode is not supported. 145*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(PN, *PN.getPrevNode(), DT, PDT, DI)); 146*ae8a8c2dSTsang Whitney W.H 147*ae8a8c2dSTsang Whitney W.H // Cannot move non-PHINode before PHINode. 148*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*PN.getNextNode(), PN, DT, PDT, DI)); 149*ae8a8c2dSTsang Whitney W.H 150*ae8a8c2dSTsang Whitney W.H // Moving Terminator is not supported. 151*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*Entry->getTerminator(), *PN.getNextNode(), DT, 152*ae8a8c2dSTsang Whitney W.H PDT, DI)); 153*ae8a8c2dSTsang Whitney W.H 154*ae8a8c2dSTsang Whitney W.H // Cannot move %arrayidx_A after SI, as SI is its user. 155*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI->getPrevNode(), *SI->getNextNode(), DT, PDT, DI)); 156*ae8a8c2dSTsang Whitney W.H 157*ae8a8c2dSTsang Whitney W.H // Cannot move SI before %arrayidx_A, as %arrayidx_A is its operand. 158*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI, *SI->getPrevNode(), DT, PDT, DI)); 159*ae8a8c2dSTsang Whitney W.H 160*ae8a8c2dSTsang Whitney W.H // Cannot move LI2 after SI_A6, as there is a flow dependence. 161*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*LI2, *SI_A6->getNextNode(), DT, PDT, DI)); 162*ae8a8c2dSTsang Whitney W.H 163*ae8a8c2dSTsang Whitney W.H // Cannot move SI after LI1, as there is a anti dependence. 164*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI, *LI1->getNextNode(), DT, PDT, DI)); 165*ae8a8c2dSTsang Whitney W.H 166*ae8a8c2dSTsang Whitney W.H // Cannot move SI_A5 after SI, as there is a output dependence. 167*ae8a8c2dSTsang Whitney W.H EXPECT_FALSE(isSafeToMoveBefore(*SI_A5, *LI1, DT, PDT, DI)); 168*ae8a8c2dSTsang Whitney W.H 169*ae8a8c2dSTsang Whitney W.H // Can move LI2 before LI1, as there is only an input dependence. 170*ae8a8c2dSTsang Whitney W.H EXPECT_TRUE(isSafeToMoveBefore(*LI2, *LI1, DT, PDT, DI)); 171*ae8a8c2dSTsang Whitney W.H }); 172*ae8a8c2dSTsang Whitney W.H } 173