xref: /llvm-project/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp (revision ae8a8c2db6c176b4dae679b77e566c656c2a27c6)
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