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