|
| 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