Skip to content

Commit b26b0a5

Browse files
committed
[CodeGen] Allow CodeGenPassBuilder to add module pass after function pass
In fact, there are several backends, e.g. AArch64, AMDGPU etc. add module pass after function pass, this patch removes this constraint. This patch also adds a simple unit test for `CodeGenPassBuilder`
1 parent 76482b7 commit b26b0a5

File tree

3 files changed

+183
-35
lines changed

3 files changed

+183
-35
lines changed

llvm/include/llvm/CodeGen/CodeGenPassBuilder.h

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -175,45 +175,34 @@ template <typename DerivedT> class CodeGenPassBuilder {
175175
// Function object to maintain state while adding codegen IR passes.
176176
class AddIRPass {
177177
public:
178-
AddIRPass(ModulePassManager &MPM, bool DebugPM, bool Check = true)
179-
: MPM(MPM) {
180-
if (Check)
181-
AddingFunctionPasses = false;
182-
}
178+
AddIRPass(ModulePassManager &MPM, bool DebugPM) : MPM(MPM) {}
183179
~AddIRPass() {
184-
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
185-
}
186-
187-
// Add Function Pass
188-
template <typename PassT>
189-
std::enable_if_t<is_detected<is_function_pass_t, PassT>::value>
190-
operator()(PassT &&Pass) {
191-
if (AddingFunctionPasses && !*AddingFunctionPasses)
192-
AddingFunctionPasses = true;
193-
FPM.addPass(std::forward<PassT>(Pass));
180+
if (!FPM.isEmpty())
181+
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
194182
}
195183

196-
// Add Module Pass
197-
template <typename PassT>
198-
std::enable_if_t<is_detected<is_module_pass_t, PassT>::value &&
199-
!is_detected<is_function_pass_t, PassT>::value>
200-
operator()(PassT &&Pass) {
201-
assert((!AddingFunctionPasses || !*AddingFunctionPasses) &&
202-
"could not add module pass after adding function pass");
184+
template <typename PassT> void operator()(PassT &&Pass) {
185+
static_assert((is_detected<is_function_pass_t, PassT>::value ||
186+
is_detected<is_module_pass_t, PassT>::value) &&
187+
"Only module pass and function pass are supported.");
188+
189+
// Add Function Pass
190+
if constexpr (is_detected<is_function_pass_t, PassT>::value) {
191+
FPM.addPass(std::forward<PassT>(Pass));
192+
return;
193+
}
194+
195+
// Add Module Pass
196+
if (!FPM.isEmpty()) {
197+
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
198+
FPM = FunctionPassManager();
199+
}
203200
MPM.addPass(std::forward<PassT>(Pass));
204201
}
205202

206203
private:
207204
ModulePassManager &MPM;
208205
FunctionPassManager FPM;
209-
// The codegen IR pipeline are mostly function passes with the exceptions of
210-
// a few loop and module passes. `AddingFunctionPasses` make sures that
211-
// we could only add module passes at the beginning of the pipeline. Once
212-
// we begin adding function passes, we could no longer add module passes.
213-
// This special-casing introduces less adaptor passes. If we have the need
214-
// of adding module passes after function passes, we could change the
215-
// implementation to accommodate that.
216-
std::optional<bool> AddingFunctionPasses;
217206
};
218207

219208
// Function object to maintain state while adding codegen machine passes.
@@ -627,8 +616,8 @@ void CodeGenPassBuilder<Derived>::addIRPasses(AddIRPass &addPass) const {
627616

628617
// Run loop strength reduction before anything else.
629618
if (getOptLevel() != CodeGenOptLevel::None && !Opt.DisableLSR) {
630-
addPass(createFunctionToLoopPassAdaptor(
631-
LoopStrengthReducePass(), /*UseMemorySSA*/ true, Opt.DebugPM));
619+
addPass(createFunctionToLoopPassAdaptor(LoopStrengthReducePass(),
620+
/*UseMemorySSA=*/true));
632621
// FIXME: use -stop-after so we could remove PrintLSR
633622
if (Opt.PrintLSR)
634623
addPass(PrintFunctionPass(dbgs(), "\n\n*** Code after LSR ***\n"));
@@ -647,9 +636,6 @@ void CodeGenPassBuilder<Derived>::addIRPasses(AddIRPass &addPass) const {
647636
// Run GC lowering passes for builtin collectors
648637
// TODO: add a pass insertion point here
649638
addPass(GCLoweringPass());
650-
// FIXME: `ShadowStackGCLoweringPass` now is a
651-
// module pass, so it will trigger assertion.
652-
// See comment of `AddingFunctionPasses`
653639
addPass(ShadowStackGCLoweringPass());
654640
addPass(LowerConstantIntrinsicsPass());
655641

llvm/unittests/CodeGen/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ set(LLVM_LINK_COMPONENTS
77
CodeGenTypes
88
Core
99
FileCheck
10+
IRPrinter
1011
MC
1112
MIRParser
1213
Passes
14+
ScalarOpts
1315
SelectionDAG
1416
Support
1517
Target
1618
TargetParser
19+
TransformUtils
1720
)
1821

1922
add_llvm_unittest(CodeGenTests
@@ -22,6 +25,7 @@ add_llvm_unittest(CodeGenTests
2225
AMDGPUMetadataTest.cpp
2326
AsmPrinterDwarfTest.cpp
2427
CCStateTest.cpp
28+
CodeGenPassBuilderTest.cpp
2529
DIEHashTest.cpp
2630
DIETest.cpp
2731
DwarfStringPoolEntryRefTest.cpp
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===- llvm/unittest/CodeGen/CodeGenPassBuilderTest.cpp -------------------===//
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/CodeGen/CodeGenPassBuilder.h"
10+
#include "llvm/CodeGen/MachinePassManager.h"
11+
#include "llvm/CodeGen/TargetPassConfig.h"
12+
#include "llvm/MC/MCStreamer.h"
13+
#include "llvm/MC/TargetRegistry.h"
14+
#include "llvm/Passes/PassBuilder.h"
15+
#include "llvm/Support/CommandLine.h"
16+
#include "llvm/Support/TargetSelect.h"
17+
#include "llvm/Support/raw_ostream.h"
18+
#include "llvm/TargetParser/Host.h"
19+
#include "gtest/gtest.h"
20+
#include <string>
21+
22+
using namespace llvm;
23+
24+
namespace {
25+
26+
struct NoOpModulePass : PassInfoMixin<NoOpModulePass> {
27+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
28+
return PreservedAnalyses::all();
29+
}
30+
31+
static StringRef name() { return "NoOpModulePass"; }
32+
};
33+
34+
struct NoOpFunctionPass : PassInfoMixin<NoOpFunctionPass> {
35+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
36+
return PreservedAnalyses::all();
37+
}
38+
static StringRef name() { return "NoOpFunctionPass"; }
39+
};
40+
41+
class DummyCodeGenPassBuilder
42+
: public CodeGenPassBuilder<DummyCodeGenPassBuilder> {
43+
public:
44+
DummyCodeGenPassBuilder(LLVMTargetMachine &TM, CGPassBuilderOption Opts,
45+
PassInstrumentationCallbacks *PIC)
46+
: CodeGenPassBuilder(TM, Opts, PIC){};
47+
48+
void addPreISel(AddIRPass &addPass) const {
49+
addPass(NoOpModulePass());
50+
addPass(NoOpFunctionPass());
51+
addPass(NoOpFunctionPass());
52+
addPass(NoOpFunctionPass());
53+
addPass(NoOpModulePass());
54+
addPass(NoOpFunctionPass());
55+
}
56+
57+
void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const {}
58+
59+
Error addInstSelector(AddMachinePass &) const { return Error::success(); }
60+
};
61+
62+
class CodeGenPassBuilderTest : public testing::Test {
63+
public:
64+
LLVMTargetMachine *TM;
65+
66+
static void SetUpTestCase() {
67+
InitializeAllTargets();
68+
InitializeAllTargetMCs();
69+
70+
static const char *argv[] = {
71+
"test",
72+
"-print-pipeline-passes",
73+
};
74+
int argc = std::size(argv);
75+
cl::ParseCommandLineOptions(argc, argv);
76+
}
77+
78+
void SetUp() override {
79+
std::string TripleName = Triple::normalize(sys::getDefaultTargetTriple());
80+
std::string Error;
81+
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
82+
if (!TheTarget)
83+
GTEST_SKIP();
84+
85+
TargetOptions Options;
86+
TM = static_cast<LLVMTargetMachine *>(
87+
TheTarget->createTargetMachine("", "", "", Options, std::nullopt));
88+
}
89+
};
90+
91+
TEST_F(CodeGenPassBuilderTest, basic) {
92+
LoopAnalysisManager LAM;
93+
FunctionAnalysisManager FAM;
94+
CGSCCAnalysisManager CGAM;
95+
ModuleAnalysisManager MAM;
96+
97+
PassInstrumentationCallbacks PIC;
98+
DummyCodeGenPassBuilder CGPB(*TM, getCGPassBuilderOption(), &PIC);
99+
PipelineTuningOptions PTO;
100+
PassBuilder PB(TM, PTO, std::nullopt, &PIC);
101+
102+
PB.registerModuleAnalyses(MAM);
103+
PB.registerCGSCCAnalyses(CGAM);
104+
PB.registerFunctionAnalyses(FAM);
105+
PB.registerLoopAnalyses(LAM);
106+
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
107+
108+
ModulePassManager MPM;
109+
MachineFunctionPassManager MFPM;
110+
Error Err =
111+
CGPB.buildPipeline(MPM, MFPM, outs(), nullptr, CodeGenFileType::Null);
112+
EXPECT_FALSE(Err);
113+
114+
std::string IRPipeline;
115+
raw_string_ostream IROS(IRPipeline);
116+
MPM.printPipeline(IROS, [&PIC](StringRef Name) {
117+
auto PassName = PIC.getPassNameForClassName(Name);
118+
return PassName.empty() ? Name : PassName;
119+
});
120+
const char ExpectedIRPipeline[] =
121+
"require<profile-summary>,require<collector-metadata>,"
122+
"PreISelIntrinsicLoweringPass,function(verify,loop-mssa(loop-reduce),"
123+
"mergeicmps,expand-memcmp,gc-lowering),shadow-stack-gc-lowering,function("
124+
"lower-constant-intrinsics,UnreachableBlockElimPass,consthoist,"
125+
"ReplaceWithVeclib,partially-inline-libcalls,ee-instrument<post-inline>,"
126+
"scalarize-masked-mem-intrin,ExpandReductionsPass,codegenprepare,"
127+
"dwarf-eh-prepare),no-op-module,function(no-op-function,no-op-function,"
128+
"no-op-function),no-op-module,function(no-op-function,callbrprepare,"
129+
"safe-stack,stack-protector,verify)";
130+
EXPECT_EQ(IRPipeline, ExpectedIRPipeline);
131+
132+
std::string MIRPipeline;
133+
raw_string_ostream MIROS(MIRPipeline);
134+
MFPM.printPipeline(MIROS, [&PIC](StringRef Name) {
135+
auto PassName = PIC.getPassNameForClassName(Name);
136+
return PassName.empty() ? Name : PassName;
137+
});
138+
const char ExpectedMIRPipeline[] =
139+
"FinalizeISelPass,EarlyTailDuplicatePass,OptimizePHIsPass,"
140+
"StackColoringPass,LocalStackSlotPass,DeadMachineInstructionElimPass,"
141+
"EarlyMachineLICMPass,MachineCSEPass,MachineSinkingPass,"
142+
"PeepholeOptimizerPass,DeadMachineInstructionElimPass,"
143+
"DetectDeadLanesPass,ProcessImplicitDefsPass,PHIEliminationPass,"
144+
"TwoAddressInstructionPass,RegisterCoalescerPass,"
145+
"RenameIndependentSubregsPass,MachineSchedulerPass,RAGreedyPass,"
146+
"VirtRegRewriterPass,StackSlotColoringPass,"
147+
"RemoveRedundantDebugValuesPass,PostRAMachineSinkingPass,ShrinkWrapPass,"
148+
"PrologEpilogInserterPass,BranchFolderPass,TailDuplicatePass,"
149+
"MachineLateInstrsCleanupPass,MachineCopyPropagationPass,"
150+
"ExpandPostRAPseudosPass,PostRASchedulerPass,MachineBlockPlacementPass,"
151+
"FEntryInserterPass,XRayInstrumentationPass,PatchableFunctionPass,"
152+
"FuncletLayoutPass,StackMapLivenessPass,LiveDebugValuesPass,"
153+
"MachineSanitizerBinaryMetadata,FreeMachineFunctionPass";
154+
EXPECT_EQ(MIRPipeline, ExpectedMIRPipeline);
155+
// TODO: Check pipeline string when all pass names are populated.
156+
}
157+
158+
} // namespace

0 commit comments

Comments
 (0)