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
18namespace llvm {
19
20TEST(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

source code of llvm/unittests/Transforms/Scalar/LICMTest.cpp