1 //===- LICMTest.cpp - LICM unit tests -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Analysis/ScalarEvolution.h" 10 #include "llvm/AsmParser/Parser.h" 11 #include "llvm/IR/Module.h" 12 #include "llvm/Passes/PassBuilder.h" 13 #include "llvm/Support/SourceMgr.h" 14 #include "llvm/Testing/Support/Error.h" 15 #include "llvm/Transforms/Scalar/LICM.h" 16 #include "gtest/gtest.h" 17 18 namespace llvm { 19 20 TEST(LICMTest, TestSCEVInvalidationOnHoisting) { 21 LLVMContext Ctx; 22 ModulePassManager MPM; 23 PassBuilder PB; 24 LoopAnalysisManager LAM; 25 FunctionAnalysisManager FAM; 26 CGSCCAnalysisManager CGAM; 27 ModuleAnalysisManager MAM; 28 29 PB.registerModuleAnalyses(MAM); 30 PB.registerCGSCCAnalyses(CGAM); 31 PB.registerFunctionAnalyses(FAM); 32 PB.registerLoopAnalyses(LAM); 33 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 34 35 StringRef PipelineStr = "require<opt-remark-emit>,loop-mssa(licm)"; 36 ASSERT_THAT_ERROR(PB.parsePassPipeline(MPM, PipelineStr), Succeeded()); 37 38 SMDiagnostic Error; 39 StringRef Text = R"( 40 define void @foo(i64* %ptr) { 41 entry: 42 br label %loop 43 44 loop: 45 %iv = phi i64 [ 0, %entry ], [ %iv.inc, %loop ] 46 %n = load i64, i64* %ptr, !invariant.load !0 47 %iv.inc = add i64 %iv, 1 48 %cmp = icmp ult i64 %iv.inc, %n 49 br i1 %cmp, label %loop, label %exit 50 51 exit: 52 ret void 53 } 54 55 !0 = !{} 56 )"; 57 58 std::unique_ptr<Module> M = parseAssemblyString(Text, Error, Ctx); 59 ASSERT_TRUE(M); 60 Function *F = M->getFunction("foo"); 61 ScalarEvolution &SE = FAM.getResult<ScalarEvolutionAnalysis>(*F); 62 BasicBlock &EntryBB = F->getEntryBlock(); 63 BasicBlock *LoopBB = EntryBB.getUniqueSuccessor(); 64 65 // Select `load i64, i64* %ptr`. 66 Instruction *IBefore = &*LoopBB->getFirstNonPHIIt(); 67 // Make sure the right instruction was selected. 68 ASSERT_TRUE(isa<LoadInst>(IBefore)); 69 // Upon this query SCEV caches disposition of <load i64, i64* %ptr> SCEV. 70 ASSERT_EQ(SE.getBlockDisposition(SE.getSCEV(IBefore), LoopBB), 71 ScalarEvolution::BlockDisposition::DominatesBlock); 72 73 MPM.run(*M, MAM); 74 75 // Select `load i64, i64* %ptr` after it was hoisted. 76 Instruction *IAfter = &*EntryBB.getFirstNonPHIIt(); 77 // Make sure the right instruction was selected. 78 ASSERT_TRUE(isa<LoadInst>(IAfter)); 79 80 ScalarEvolution::BlockDisposition DispositionBeforeInvalidation = 81 SE.getBlockDisposition(SE.getSCEV(IAfter), LoopBB); 82 SE.forgetValue(IAfter); 83 ScalarEvolution::BlockDisposition DispositionAfterInvalidation = 84 SE.getBlockDisposition(SE.getSCEV(IAfter), LoopBB); 85 86 // If LICM have properly invalidated SCEV, 87 // 1. SCEV of <load i64, i64* %ptr> should properly dominate the "loop" BB, 88 // 2. extra invalidation shouldn't change result of the query. 89 EXPECT_EQ(DispositionBeforeInvalidation, 90 ScalarEvolution::BlockDisposition::ProperlyDominatesBlock); 91 EXPECT_EQ(DispositionBeforeInvalidation, DispositionAfterInvalidation); 92 } 93 } 94