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(AsmString: Text, Err&: Error, Context&: Ctx); |
59 | ASSERT_TRUE(M); |
60 | Function *F = M->getFunction(Name: "foo" ); |
61 | ScalarEvolution &SE = FAM.getResult<ScalarEvolutionAnalysis>(IR&: *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(IR&: *M, AM&: 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(S: SE.getSCEV(V: IAfter), BB: LoopBB); |
82 | SE.forgetValue(V: IAfter); |
83 | ScalarEvolution::BlockDisposition DispositionAfterInvalidation = |
84 | SE.getBlockDisposition(S: SE.getSCEV(V: IAfter), BB: 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 | |