xref: /llvm-project/llvm/unittests/Analysis/DDGTest.cpp (revision 4169338e75cdce73d34063532db598c95ee82ae4)
10d20ed66SBardia Mahjour //===- DDGTest.cpp - DDGAnalysis unit tests -------------------------------===//
20d20ed66SBardia Mahjour //
30d20ed66SBardia Mahjour // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40d20ed66SBardia Mahjour // See https://llvm.org/LICENSE.txt for license information.
50d20ed66SBardia Mahjour // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60d20ed66SBardia Mahjour //
70d20ed66SBardia Mahjour //===----------------------------------------------------------------------===//
80d20ed66SBardia Mahjour 
90d20ed66SBardia Mahjour #include "llvm/Analysis/DDG.h"
100d20ed66SBardia Mahjour #include "llvm/Analysis/AliasAnalysis.h"
112ce38b3fSdfukalov #include "llvm/Analysis/AssumptionCache.h"
120d20ed66SBardia Mahjour #include "llvm/Analysis/BasicAliasAnalysis.h"
13a5f1f9c9SSimon Pilgrim #include "llvm/Analysis/LoopInfo.h"
140d20ed66SBardia Mahjour #include "llvm/Analysis/ScalarEvolution.h"
150d20ed66SBardia Mahjour #include "llvm/Analysis/TargetLibraryInfo.h"
160d20ed66SBardia Mahjour #include "llvm/AsmParser/Parser.h"
170d20ed66SBardia Mahjour #include "llvm/IR/Dominators.h"
18*4169338eSNikita Popov #include "llvm/IR/Module.h"
190d20ed66SBardia Mahjour #include "llvm/Support/SourceMgr.h"
200d20ed66SBardia Mahjour #include "gtest/gtest.h"
210d20ed66SBardia Mahjour 
220d20ed66SBardia Mahjour using namespace llvm;
230d20ed66SBardia Mahjour 
240d20ed66SBardia Mahjour /// Build the DDG analysis for a loop and run the given test \p Test.
runTest(Module & M,StringRef FuncName,function_ref<void (Function & F,LoopInfo & LI,DependenceInfo & DI,ScalarEvolution & SE)> Test)250d20ed66SBardia Mahjour static void runTest(Module &M, StringRef FuncName,
260d20ed66SBardia Mahjour                     function_ref<void(Function &F, LoopInfo &LI,
270d20ed66SBardia Mahjour                                       DependenceInfo &DI, ScalarEvolution &SE)>
280d20ed66SBardia Mahjour                         Test) {
290d20ed66SBardia Mahjour   auto *F = M.getFunction(FuncName);
300d20ed66SBardia Mahjour   ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
310d20ed66SBardia Mahjour 
320d20ed66SBardia Mahjour   TargetLibraryInfoImpl TLII;
330d20ed66SBardia Mahjour   TargetLibraryInfo TLI(TLII);
340d20ed66SBardia Mahjour   AssumptionCache AC(*F);
350d20ed66SBardia Mahjour   DominatorTree DT(*F);
360d20ed66SBardia Mahjour   LoopInfo LI(DT);
370d20ed66SBardia Mahjour   ScalarEvolution SE(*F, TLI, AC, DT, LI);
380d20ed66SBardia Mahjour   AAResults AA(TLI);
390d20ed66SBardia Mahjour   DependenceInfo DI(F, &AA, &SE, &LI);
400d20ed66SBardia Mahjour   Test(*F, LI, DI, SE);
410d20ed66SBardia Mahjour }
420d20ed66SBardia Mahjour 
makeLLVMModule(LLVMContext & Context,const char * ModuleStr)430d20ed66SBardia Mahjour static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
440d20ed66SBardia Mahjour                                               const char *ModuleStr) {
450d20ed66SBardia Mahjour   SMDiagnostic Err;
460d20ed66SBardia Mahjour   return parseAssemblyString(ModuleStr, Err, Context);
470d20ed66SBardia Mahjour }
480d20ed66SBardia Mahjour 
TEST(DDGTest,getDependencies)490d20ed66SBardia Mahjour TEST(DDGTest, getDependencies) {
500d20ed66SBardia Mahjour   const char *ModuleStr =
510d20ed66SBardia Mahjour       "target datalayout = \"e-m:e-i64:64-n32:64\"\n"
520d20ed66SBardia Mahjour       "target triple = \"powerpc64le-unknown-linux-gnu\"\n"
530d20ed66SBardia Mahjour       "\n"
540d20ed66SBardia Mahjour       "define dso_local void @foo(i32 signext %n, i32* noalias %A, i32* "
550d20ed66SBardia Mahjour       "noalias %B) {\n"
560d20ed66SBardia Mahjour       "entry:\n"
570d20ed66SBardia Mahjour       "   %cmp1 = icmp sgt i32 %n, 0\n"
580d20ed66SBardia Mahjour       "   br i1 %cmp1, label %for.body.preheader, label %for.end\n"
590d20ed66SBardia Mahjour       "\n"
600d20ed66SBardia Mahjour       "for.body.preheader:\n"
610d20ed66SBardia Mahjour       "   %wide.trip.count = zext i32 %n to i64\n"
620d20ed66SBardia Mahjour       "   br label %for.body\n"
630d20ed66SBardia Mahjour       " \n"
640d20ed66SBardia Mahjour       " for.body:\n"
650d20ed66SBardia Mahjour       "   %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ "
660d20ed66SBardia Mahjour       "%indvars.iv.next, %for.body ]\n"
670d20ed66SBardia Mahjour       "   %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n"
680d20ed66SBardia Mahjour       "  %0 = trunc i64 %indvars.iv to i32\n"
690d20ed66SBardia Mahjour       "  store i32 %0, i32* %arrayidx, align 4\n"
700d20ed66SBardia Mahjour       "  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
710d20ed66SBardia Mahjour       "  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 "
720d20ed66SBardia Mahjour       "%indvars.iv.next\n"
730d20ed66SBardia Mahjour       "  %1 = load i32, i32* %arrayidx2, align 4\n"
740d20ed66SBardia Mahjour       "  %add3 = add nsw i32 %1, 1\n"
750d20ed66SBardia Mahjour       "  %arrayidx5 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv\n"
760d20ed66SBardia Mahjour       "  store i32 %add3, i32* %arrayidx5, align 4\n"
770d20ed66SBardia Mahjour       "  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count\n"
780d20ed66SBardia Mahjour       "  br i1 %exitcond, label %for.body, label %for.end.loopexit\n"
790d20ed66SBardia Mahjour       "\n"
800d20ed66SBardia Mahjour       "for.end.loopexit:\n"
810d20ed66SBardia Mahjour       "  br label %for.end\n"
820d20ed66SBardia Mahjour       "\n"
830d20ed66SBardia Mahjour       "for.end:\n"
840d20ed66SBardia Mahjour       "  ret void\n"
850d20ed66SBardia Mahjour       "}\n";
860d20ed66SBardia Mahjour 
870d20ed66SBardia Mahjour   LLVMContext Context;
880d20ed66SBardia Mahjour   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
890d20ed66SBardia Mahjour 
900d20ed66SBardia Mahjour   runTest(
910d20ed66SBardia Mahjour       *M, "foo",
920d20ed66SBardia Mahjour       [&](Function &F, LoopInfo &LI, DependenceInfo &DI, ScalarEvolution &SE) {
930d20ed66SBardia Mahjour         Loop *L = *LI.begin();
940d20ed66SBardia Mahjour         assert(L && "expected the loop to be identified.");
950d20ed66SBardia Mahjour 
960d20ed66SBardia Mahjour         DataDependenceGraph DDG(*L, LI, DI);
970d20ed66SBardia Mahjour 
980d20ed66SBardia Mahjour         // Collect all the nodes that have an outgoing memory edge
990d20ed66SBardia Mahjour         // while collecting all memory edges as well. There should
1000d20ed66SBardia Mahjour         // only be one node with an outgoing memory edge and there
1010d20ed66SBardia Mahjour         // should only be one memory edge in the entire graph.
1020d20ed66SBardia Mahjour         std::vector<DDGNode *> DependenceSourceNodes;
1030d20ed66SBardia Mahjour         std::vector<DDGEdge *> MemoryEdges;
1040d20ed66SBardia Mahjour         for (DDGNode *N : DDG) {
1050d20ed66SBardia Mahjour           for (DDGEdge *E : *N) {
1060d20ed66SBardia Mahjour             bool SourceAdded = false;
1070d20ed66SBardia Mahjour             if (E->isMemoryDependence()) {
1080d20ed66SBardia Mahjour               MemoryEdges.push_back(E);
1090d20ed66SBardia Mahjour               if (!SourceAdded) {
1100d20ed66SBardia Mahjour                 DependenceSourceNodes.push_back(N);
1110d20ed66SBardia Mahjour                 SourceAdded = true;
1120d20ed66SBardia Mahjour               }
1130d20ed66SBardia Mahjour             }
1140d20ed66SBardia Mahjour           }
1150d20ed66SBardia Mahjour         }
1160d20ed66SBardia Mahjour 
1170d20ed66SBardia Mahjour         EXPECT_EQ(DependenceSourceNodes.size(), 1ull);
1180d20ed66SBardia Mahjour         EXPECT_EQ(MemoryEdges.size(), 1ull);
1190d20ed66SBardia Mahjour 
1200d20ed66SBardia Mahjour         DataDependenceGraph::DependenceList DL;
1210d20ed66SBardia Mahjour         DDG.getDependencies(*DependenceSourceNodes.back(),
1220d20ed66SBardia Mahjour                             MemoryEdges.back()->getTargetNode(), DL);
1230d20ed66SBardia Mahjour 
1240d20ed66SBardia Mahjour         EXPECT_EQ(DL.size(), 1ull);
1250d20ed66SBardia Mahjour         EXPECT_TRUE(DL.back()->isAnti());
1260d20ed66SBardia Mahjour         EXPECT_EQ(DL.back()->getLevels(), 1u);
1270d20ed66SBardia Mahjour         EXPECT_NE(DL.back()->getDistance(1), nullptr);
1280d20ed66SBardia Mahjour         EXPECT_EQ(DL.back()->getDistance(1),
1290d20ed66SBardia Mahjour                   SE.getOne(DL.back()->getDistance(1)->getType()));
1300d20ed66SBardia Mahjour       });
1310d20ed66SBardia Mahjour }
132ebfe4de2SBardia Mahjour 
133ebfe4de2SBardia Mahjour /// Test to make sure that when pi-blocks are formed, multiple edges of the same
134ebfe4de2SBardia Mahjour /// kind and direction are collapsed into a single edge.
135ebfe4de2SBardia Mahjour /// In the test below, %loadASubI belongs to an outside node, which has input
136ebfe4de2SBardia Mahjour /// dependency with multiple load instructions in the pi-block containing
137ebfe4de2SBardia Mahjour /// %loadBSubI. We expect a single memory dependence edge from the outside node
138ebfe4de2SBardia Mahjour /// to this pi-block. The pi-block also contains %add and %add7 both of which
139ebfe4de2SBardia Mahjour /// feed a phi in an outside node. We expect a single def-use edge from the
140ebfe4de2SBardia Mahjour /// pi-block to the node containing that phi.
TEST(DDGTest,avoidDuplicateEdgesToFromPiBlocks)141ebfe4de2SBardia Mahjour TEST(DDGTest, avoidDuplicateEdgesToFromPiBlocks) {
142ebfe4de2SBardia Mahjour   const char *ModuleStr =
143ebfe4de2SBardia Mahjour       "target datalayout = \"e-m:e-i64:64-n32:64-v256:256:256-v512:512:512\"\n"
144ebfe4de2SBardia Mahjour       "\n"
145ebfe4de2SBardia Mahjour       "define void @foo(float* noalias %A, float* noalias %B, float* noalias "
146ebfe4de2SBardia Mahjour       "%C, float* noalias %D, i32 signext %n) {\n"
147ebfe4de2SBardia Mahjour       "entry:\n"
148ebfe4de2SBardia Mahjour       "  %cmp1 = icmp sgt i32 %n, 0\n"
149ebfe4de2SBardia Mahjour       "  br i1 %cmp1, label %for.body.preheader, label %for.end\n"
150ebfe4de2SBardia Mahjour       "\n"
151ebfe4de2SBardia Mahjour       "for.body.preheader:                               ; preds = %entry\n"
152ebfe4de2SBardia Mahjour       "  %wide.trip.count = zext i32 %n to i64\n"
153ebfe4de2SBardia Mahjour       "  br label %for.body\n"
154ebfe4de2SBardia Mahjour       "\n"
155ebfe4de2SBardia Mahjour       "for.body:                                         ; preds = "
156ebfe4de2SBardia Mahjour       "%for.body.preheader, %if.end\n"
157ebfe4de2SBardia Mahjour       "  %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, "
158ebfe4de2SBardia Mahjour       "%if.end ]\n"
159ebfe4de2SBardia Mahjour       "  %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv\n"
160ebfe4de2SBardia Mahjour       "  %loadASubI = load float, float* %arrayidx, align 4\n"
161ebfe4de2SBardia Mahjour       "  %arrayidx2 = getelementptr inbounds float, float* %B, i64 "
162ebfe4de2SBardia Mahjour       "%indvars.iv\n"
163ebfe4de2SBardia Mahjour       "  %loadBSubI = load float, float* %arrayidx2, align 4\n"
164ebfe4de2SBardia Mahjour       "  %add = fadd fast float %loadASubI, %loadBSubI\n"
165ebfe4de2SBardia Mahjour       "  %arrayidx4 = getelementptr inbounds float, float* %A, i64 "
166ebfe4de2SBardia Mahjour       "%indvars.iv\n"
167ebfe4de2SBardia Mahjour       "  store float %add, float* %arrayidx4, align 4\n"
168ebfe4de2SBardia Mahjour       "  %arrayidx6 = getelementptr inbounds float, float* %A, i64 "
169ebfe4de2SBardia Mahjour       "%indvars.iv\n"
170ebfe4de2SBardia Mahjour       "  %0 = load float, float* %arrayidx6, align 4\n"
171ebfe4de2SBardia Mahjour       "  %add7 = fadd fast float %0, 1.000000e+00\n"
172ebfe4de2SBardia Mahjour       "  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
173ebfe4de2SBardia Mahjour       "  %arrayidx10 = getelementptr inbounds float, float* %B, i64 "
174ebfe4de2SBardia Mahjour       "%indvars.iv.next\n"
175ebfe4de2SBardia Mahjour       "  store float %add7, float* %arrayidx10, align 4\n"
176ebfe4de2SBardia Mahjour       "  %arrayidx12 = getelementptr inbounds float, float* %A, i64 "
177ebfe4de2SBardia Mahjour       "%indvars.iv\n"
178ebfe4de2SBardia Mahjour       "  %1 = load float, float* %arrayidx12, align 4\n"
179ebfe4de2SBardia Mahjour       "  %cmp13 = fcmp fast ogt float %1, 1.000000e+02\n"
180ebfe4de2SBardia Mahjour       "  br i1 %cmp13, label %if.then, label %if.else\n"
181ebfe4de2SBardia Mahjour       "\n"
182ebfe4de2SBardia Mahjour       "if.then:                                          ; preds = %for.body\n"
183ebfe4de2SBardia Mahjour       "  br label %if.end\n"
184ebfe4de2SBardia Mahjour       "\n"
185ebfe4de2SBardia Mahjour       "if.else:                                          ; preds = %for.body\n"
186ebfe4de2SBardia Mahjour       "  br label %if.end\n"
187ebfe4de2SBardia Mahjour       "\n"
188ebfe4de2SBardia Mahjour       "if.end:                                           ; preds = %if.else, "
189ebfe4de2SBardia Mahjour       "%if.then\n"
190ebfe4de2SBardia Mahjour       "  %ff.0 = phi float [ %add, %if.then ], [ %add7, %if.else ]\n"
191ebfe4de2SBardia Mahjour       "  store float %ff.0, float* %C, align 4\n"
192ebfe4de2SBardia Mahjour       "  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count\n"
193ebfe4de2SBardia Mahjour       "  br i1 %exitcond, label %for.body, label %for.end.loopexit\n"
194ebfe4de2SBardia Mahjour       "\n"
195ebfe4de2SBardia Mahjour       "for.end.loopexit:                                 ; preds = %if.end\n"
196ebfe4de2SBardia Mahjour       "  br label %for.end\n"
197ebfe4de2SBardia Mahjour       "\n"
198ebfe4de2SBardia Mahjour       "for.end:                                          ; preds = "
199ebfe4de2SBardia Mahjour       "%for.end.loopexit, %entry\n"
200ebfe4de2SBardia Mahjour       "  ret void\n"
201ebfe4de2SBardia Mahjour       "}\n";
202ebfe4de2SBardia Mahjour 
203ebfe4de2SBardia Mahjour   LLVMContext Context;
204ebfe4de2SBardia Mahjour   std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
205ebfe4de2SBardia Mahjour 
206ebfe4de2SBardia Mahjour   runTest(
207ebfe4de2SBardia Mahjour       *M, "foo",
208ebfe4de2SBardia Mahjour       [&](Function &F, LoopInfo &LI, DependenceInfo &DI, ScalarEvolution &SE) {
209ebfe4de2SBardia Mahjour         Loop *L = *LI.begin();
210ebfe4de2SBardia Mahjour         assert(L && "expected the loop to be identified.");
211ebfe4de2SBardia Mahjour 
212ebfe4de2SBardia Mahjour         DataDependenceGraph DDG(*L, LI, DI);
213ebfe4de2SBardia Mahjour 
214ebfe4de2SBardia Mahjour         const DDGNode *LoadASubI = nullptr;
215ebfe4de2SBardia Mahjour         for (DDGNode *N : DDG) {
216ebfe4de2SBardia Mahjour           if (!isa<SimpleDDGNode>(N))
217ebfe4de2SBardia Mahjour             continue;
218ebfe4de2SBardia Mahjour           SmallVector<Instruction *, 8> IList;
219ebfe4de2SBardia Mahjour           N->collectInstructions([](const Instruction *I) { return true; },
220ebfe4de2SBardia Mahjour                                  IList);
221ebfe4de2SBardia Mahjour           if (llvm::any_of(IList, [](Instruction *I) {
222ebfe4de2SBardia Mahjour                 return I->getName() == "loadASubI";
223ebfe4de2SBardia Mahjour               })) {
224ebfe4de2SBardia Mahjour             LoadASubI = N;
225ebfe4de2SBardia Mahjour             break;
226ebfe4de2SBardia Mahjour           }
227ebfe4de2SBardia Mahjour         }
228ebfe4de2SBardia Mahjour         assert(LoadASubI && "Did not find load of A[i]");
229ebfe4de2SBardia Mahjour 
230ebfe4de2SBardia Mahjour         const PiBlockDDGNode *PiBlockWithBSubI = nullptr;
231ebfe4de2SBardia Mahjour         for (DDGNode *N : DDG) {
232ebfe4de2SBardia Mahjour           if (!isa<PiBlockDDGNode>(N))
233ebfe4de2SBardia Mahjour             continue;
234ebfe4de2SBardia Mahjour           for (DDGNode *M : cast<PiBlockDDGNode>(N)->getNodes()) {
235ebfe4de2SBardia Mahjour             SmallVector<Instruction *, 8> IList;
236ebfe4de2SBardia Mahjour             M->collectInstructions([](const Instruction *I) { return true; },
237ebfe4de2SBardia Mahjour                                    IList);
238ebfe4de2SBardia Mahjour             if (llvm::any_of(IList, [](Instruction *I) {
239ebfe4de2SBardia Mahjour                   return I->getName() == "loadBSubI";
240ebfe4de2SBardia Mahjour                 })) {
241ebfe4de2SBardia Mahjour               PiBlockWithBSubI = static_cast<PiBlockDDGNode *>(N);
242ebfe4de2SBardia Mahjour               break;
243ebfe4de2SBardia Mahjour             }
244ebfe4de2SBardia Mahjour           }
245ebfe4de2SBardia Mahjour           if (PiBlockWithBSubI)
246ebfe4de2SBardia Mahjour             break;
247ebfe4de2SBardia Mahjour         }
248ebfe4de2SBardia Mahjour         assert(PiBlockWithBSubI &&
249ebfe4de2SBardia Mahjour                "Did not find pi-block containing load of B[i]");
250ebfe4de2SBardia Mahjour 
251ebfe4de2SBardia Mahjour         const DDGNode *FFPhi = nullptr;
252ebfe4de2SBardia Mahjour         for (DDGNode *N : DDG) {
253ebfe4de2SBardia Mahjour           if (!isa<SimpleDDGNode>(N))
254ebfe4de2SBardia Mahjour             continue;
255ebfe4de2SBardia Mahjour           SmallVector<Instruction *, 8> IList;
256ebfe4de2SBardia Mahjour           N->collectInstructions([](const Instruction *I) { return true; },
257ebfe4de2SBardia Mahjour                                  IList);
258ebfe4de2SBardia Mahjour           if (llvm::any_of(IList, [](Instruction *I) {
259ebfe4de2SBardia Mahjour                 return I->getName() == "ff.0";
260ebfe4de2SBardia Mahjour               })) {
261ebfe4de2SBardia Mahjour             FFPhi = N;
262ebfe4de2SBardia Mahjour             break;
263ebfe4de2SBardia Mahjour           }
264ebfe4de2SBardia Mahjour         }
265ebfe4de2SBardia Mahjour         assert(FFPhi && "Did not find ff.0 phi instruction");
266ebfe4de2SBardia Mahjour 
267ebfe4de2SBardia Mahjour         // Expect a single memory edge from '%0 = A[i]' to the pi-block. This
268ebfe4de2SBardia Mahjour         // means the duplicate incoming memory edges are removed during pi-block
269ebfe4de2SBardia Mahjour         // formation.
270ebfe4de2SBardia Mahjour         SmallVector<DDGEdge *, 4> EL;
271ebfe4de2SBardia Mahjour         LoadASubI->findEdgesTo(*PiBlockWithBSubI, EL);
272ebfe4de2SBardia Mahjour         unsigned NumMemoryEdges = llvm::count_if(
273ebfe4de2SBardia Mahjour             EL, [](DDGEdge *Edge) { return Edge->isMemoryDependence(); });
274ebfe4de2SBardia Mahjour         EXPECT_EQ(NumMemoryEdges, 1ull);
275ebfe4de2SBardia Mahjour 
276ebfe4de2SBardia Mahjour         /// Expect a single def-use edge from the pi-block to '%ff.0 = phi...`.
277ebfe4de2SBardia Mahjour         /// This means the duplicate outgoing def-use edges are removed during
278ebfe4de2SBardia Mahjour         /// pi-block formation.
279ebfe4de2SBardia Mahjour         EL.clear();
280ebfe4de2SBardia Mahjour         PiBlockWithBSubI->findEdgesTo(*FFPhi, EL);
281ebfe4de2SBardia Mahjour         NumMemoryEdges =
282ebfe4de2SBardia Mahjour             llvm::count_if(EL, [](DDGEdge *Edge) { return Edge->isDefUse(); });
283ebfe4de2SBardia Mahjour         EXPECT_EQ(NumMemoryEdges, 1ull);
284ebfe4de2SBardia Mahjour       });
285ebfe4de2SBardia Mahjour }
286