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 
TEST(LICMTest,TestSCEVInvalidationOnHoisting)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(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->getFirstNonPHI();
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.getFirstNonPHI();
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