Skip to content

Commit b32bae6

Browse files
author
Serguei Katkov
committed
[Test] Add a unit test exposing lack of SCEV invalidation in LICM during code hoisting. NFC.
This unit test exposes a bug in LICM: when it hoists instructions it doesn't invalidate SCEV accordingly. Similar test exposing lack of SCEV invalidation during code sinking will be submitted as a follow-up change. Patch Author: Daniil Suchkov Reviewers: mkazantsev, asbirlea, reames Reviewed By: asbirlea Subscribers: mgorny, javed.absar, llvm-commits Differential Revision: https://reviews.llvm.org/D69369
1 parent e46c664 commit b32bae6

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

llvm/unittests/Transforms/Scalar/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@ set(LLVM_LINK_COMPONENTS
22
Analysis
33
AsmParser
44
Core
5+
Passes
56
Support
67
ScalarOpts
78
TransformUtils
89
)
910

1011
add_llvm_unittest(ScalarTests
12+
LICMTest.cpp
1113
LoopPassManagerTest.cpp
1214
)
1315

16+
target_link_libraries(ScalarTests PRIVATE LLVMTestingSupport)
17+
1418
# Workaround for the gcc 6.1 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80916.
1519
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
1620
set_source_files_properties(LoopPassManagerTest.cpp PROPERTIES COMPILE_FLAGS -Wno-unused-function)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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(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+
// FIXME: these values should be equal!
90+
EXPECT_NE(DispositionBeforeInvalidation,
91+
ScalarEvolution::BlockDisposition::ProperlyDominatesBlock);
92+
// FIXME: these values should be equal!
93+
EXPECT_NE(DispositionBeforeInvalidation, DispositionAfterInvalidation);
94+
}
95+
}

0 commit comments

Comments
 (0)