xref: /llvm-project/llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp (revision edf46f365cf4e7caccd7459ac1a6912de5096857)
19883d7edSWhitney Tsang //===- LoopUtilsTest.cpp - Unit tests for LoopUtils -----------------------===//
29883d7edSWhitney Tsang //
39883d7edSWhitney Tsang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49883d7edSWhitney Tsang // See https://llvm.org/LICENSE.txt for license information.
59883d7edSWhitney Tsang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69883d7edSWhitney Tsang //
79883d7edSWhitney Tsang //===----------------------------------------------------------------------===//
89883d7edSWhitney Tsang 
99883d7edSWhitney Tsang #include "llvm/Transforms/Utils/LoopUtils.h"
10a7aaadc1SFlorian Hahn #include "llvm/Analysis/AssumptionCache.h"
11a5f1f9c9SSimon Pilgrim #include "llvm/Analysis/LoopInfo.h"
12a7aaadc1SFlorian Hahn #include "llvm/Analysis/ScalarEvolution.h"
13c18b7536SSimon Pilgrim #include "llvm/Analysis/TargetLibraryInfo.h"
149883d7edSWhitney Tsang #include "llvm/AsmParser/Parser.h"
15a7aaadc1SFlorian Hahn #include "llvm/IR/Dominators.h"
164169338eSNikita Popov #include "llvm/IR/Module.h"
179883d7edSWhitney Tsang #include "llvm/Support/SourceMgr.h"
189883d7edSWhitney Tsang #include "gtest/gtest.h"
199883d7edSWhitney Tsang 
209883d7edSWhitney Tsang using namespace llvm;
219883d7edSWhitney Tsang 
229883d7edSWhitney Tsang static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
239883d7edSWhitney Tsang   SMDiagnostic Err;
249883d7edSWhitney Tsang   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
259883d7edSWhitney Tsang   if (!Mod)
269883d7edSWhitney Tsang     Err.print("LoopUtilsTests", errs());
279883d7edSWhitney Tsang   return Mod;
289883d7edSWhitney Tsang }
299883d7edSWhitney Tsang 
309883d7edSWhitney Tsang static void run(Module &M, StringRef FuncName,
319883d7edSWhitney Tsang                 function_ref<void(Function &F, DominatorTree &DT,
329883d7edSWhitney Tsang                                   ScalarEvolution &SE, LoopInfo &LI)>
339883d7edSWhitney Tsang                     Test) {
349883d7edSWhitney Tsang   Function *F = M.getFunction(FuncName);
359883d7edSWhitney Tsang   DominatorTree DT(*F);
369883d7edSWhitney Tsang   TargetLibraryInfoImpl TLII;
379883d7edSWhitney Tsang   TargetLibraryInfo TLI(TLII);
389883d7edSWhitney Tsang   AssumptionCache AC(*F);
399883d7edSWhitney Tsang   LoopInfo LI(DT);
409883d7edSWhitney Tsang   ScalarEvolution SE(*F, TLI, AC, DT, LI);
419883d7edSWhitney Tsang   Test(*F, DT, SE, LI);
429883d7edSWhitney Tsang }
439883d7edSWhitney Tsang 
449883d7edSWhitney Tsang TEST(LoopUtils, DeleteDeadLoopNest) {
459883d7edSWhitney Tsang   LLVMContext C;
469883d7edSWhitney Tsang   std::unique_ptr<Module> M =
479883d7edSWhitney Tsang       parseIR(C, "define void @foo() {\n"
489883d7edSWhitney Tsang                  "entry:\n"
499883d7edSWhitney Tsang                  "  br label %for.i\n"
509883d7edSWhitney Tsang                  "for.i:\n"
519883d7edSWhitney Tsang                  "  %i = phi i64 [ 0, %entry ], [ %inc.i, %for.i.latch ]\n"
529883d7edSWhitney Tsang                  "  br label %for.j\n"
539883d7edSWhitney Tsang                  "for.j:\n"
549883d7edSWhitney Tsang                  "  %j = phi i64 [ 0, %for.i ], [ %inc.j, %for.j ]\n"
559883d7edSWhitney Tsang                  "  %inc.j = add nsw i64 %j, 1\n"
569883d7edSWhitney Tsang                  "  %cmp.j = icmp slt i64 %inc.j, 100\n"
579883d7edSWhitney Tsang                  "  br i1 %cmp.j, label %for.j, label %for.k.preheader\n"
589883d7edSWhitney Tsang                  "for.k.preheader:\n"
599883d7edSWhitney Tsang                  "  br label %for.k\n"
609883d7edSWhitney Tsang                  "for.k:\n"
619883d7edSWhitney Tsang                  "  %k = phi i64 [ %inc.k, %for.k ], [ 0, %for.k.preheader ]\n"
629883d7edSWhitney Tsang                  "  %inc.k = add nsw i64 %k, 1\n"
639883d7edSWhitney Tsang                  "  %cmp.k = icmp slt i64 %inc.k, 100\n"
649883d7edSWhitney Tsang                  "  br i1 %cmp.k, label %for.k, label %for.i.latch\n"
659883d7edSWhitney Tsang                  "for.i.latch:\n"
669883d7edSWhitney Tsang                  "  %inc.i = add nsw i64 %i, 1\n"
679883d7edSWhitney Tsang                  "  %cmp.i = icmp slt i64 %inc.i, 100\n"
689883d7edSWhitney Tsang                  "  br i1 %cmp.i, label %for.i, label %for.end\n"
699883d7edSWhitney Tsang                  "for.end:\n"
709883d7edSWhitney Tsang                  "  ret void\n"
719883d7edSWhitney Tsang                  "}\n");
729883d7edSWhitney Tsang 
739883d7edSWhitney Tsang   run(*M, "foo",
749883d7edSWhitney Tsang       [&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) {
759883d7edSWhitney Tsang         assert(LI.begin() != LI.end() && "Expecting loops in function F");
769883d7edSWhitney Tsang         Loop *L = *LI.begin();
779883d7edSWhitney Tsang         assert(L && L->getName() == "for.i" && "Expecting loop for.i");
789883d7edSWhitney Tsang 
799883d7edSWhitney Tsang         deleteDeadLoop(L, &DT, &SE, &LI);
809883d7edSWhitney Tsang 
819883d7edSWhitney Tsang         assert(DT.verify(DominatorTree::VerificationLevel::Fast) &&
829883d7edSWhitney Tsang                "Expecting valid dominator tree");
839883d7edSWhitney Tsang         LI.verify(DT);
849883d7edSWhitney Tsang         assert(LI.begin() == LI.end() &&
859883d7edSWhitney Tsang                "Expecting no loops left in function F");
869883d7edSWhitney Tsang         SE.verify();
879883d7edSWhitney Tsang 
889883d7edSWhitney Tsang         Function::iterator FI = F.begin();
899883d7edSWhitney Tsang         BasicBlock *Entry = &*(FI++);
909883d7edSWhitney Tsang         assert(Entry->getName() == "entry" && "Expecting BasicBlock entry");
919883d7edSWhitney Tsang         const BranchInst *BI = dyn_cast<BranchInst>(Entry->getTerminator());
929883d7edSWhitney Tsang         assert(BI && "Expecting valid branch instruction");
939883d7edSWhitney Tsang         EXPECT_EQ(BI->getNumSuccessors(), (unsigned)1);
949883d7edSWhitney Tsang         EXPECT_EQ(BI->getSuccessor(0)->getName(), "for.end");
959883d7edSWhitney Tsang       });
969883d7edSWhitney Tsang }
97797da79aSDmitry Makogon 
98797da79aSDmitry Makogon TEST(LoopUtils, IsKnownPositiveInLoopTest) {
99797da79aSDmitry Makogon   LLVMContext C;
100797da79aSDmitry Makogon   std::unique_ptr<Module> M =
101797da79aSDmitry Makogon       parseIR(C, "define void @foo(i32 %n, i1 %c) {\n"
102797da79aSDmitry Makogon                  "entry:\n"
103797da79aSDmitry Makogon                  "  %is.positive = icmp sgt i32 %n, 0\n"
104797da79aSDmitry Makogon                  "  br i1 %is.positive, label %loop, label %exit\n"
105797da79aSDmitry Makogon                  "loop:\n"
106797da79aSDmitry Makogon                  "  br i1 %c, label %loop, label %exit\n"
107797da79aSDmitry Makogon                  "exit:\n"
108797da79aSDmitry Makogon                  "  ret void\n"
109797da79aSDmitry Makogon                  "}\n");
110797da79aSDmitry Makogon 
111797da79aSDmitry Makogon   run(*M, "foo",
112797da79aSDmitry Makogon       [&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) {
113797da79aSDmitry Makogon         assert(LI.begin() != LI.end() && "Expecting loops in function F");
114797da79aSDmitry Makogon         Loop *L = *LI.begin();
115797da79aSDmitry Makogon         assert(L && L->getName() == "loop" && "Expecting loop 'loop'");
116797da79aSDmitry Makogon         auto *Arg = F.getArg(0);
117*edf46f36SFlorian Hahn         const SCEV *ArgSCEV = SE.getSCEV(Arg);
118797da79aSDmitry Makogon         EXPECT_EQ(isKnownPositiveInLoop(ArgSCEV, L, SE), true);
119797da79aSDmitry Makogon       });
120797da79aSDmitry Makogon }
121797da79aSDmitry Makogon 
122797da79aSDmitry Makogon TEST(LoopUtils, IsKnownNonPositiveInLoopTest) {
123797da79aSDmitry Makogon   LLVMContext C;
124797da79aSDmitry Makogon   std::unique_ptr<Module> M =
125797da79aSDmitry Makogon       parseIR(C, "define void @foo(i32 %n, i1 %c) {\n"
126797da79aSDmitry Makogon                  "entry:\n"
127797da79aSDmitry Makogon                  "  %is.non.positive = icmp sle i32 %n, 0\n"
128797da79aSDmitry Makogon                  "  br i1 %is.non.positive, label %loop, label %exit\n"
129797da79aSDmitry Makogon                  "loop:\n"
130797da79aSDmitry Makogon                  "  br i1 %c, label %loop, label %exit\n"
131797da79aSDmitry Makogon                  "exit:\n"
132797da79aSDmitry Makogon                  "  ret void\n"
133797da79aSDmitry Makogon                  "}\n");
134797da79aSDmitry Makogon 
135797da79aSDmitry Makogon   run(*M, "foo",
136797da79aSDmitry Makogon       [&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) {
137797da79aSDmitry Makogon         assert(LI.begin() != LI.end() && "Expecting loops in function F");
138797da79aSDmitry Makogon         Loop *L = *LI.begin();
139797da79aSDmitry Makogon         assert(L && L->getName() == "loop" && "Expecting loop 'loop'");
140797da79aSDmitry Makogon         auto *Arg = F.getArg(0);
141*edf46f36SFlorian Hahn         const SCEV *ArgSCEV = SE.getSCEV(Arg);
142797da79aSDmitry Makogon         EXPECT_EQ(isKnownNonPositiveInLoop(ArgSCEV, L, SE), true);
143797da79aSDmitry Makogon       });
144797da79aSDmitry Makogon }
145