From 7e50f006f7f652b9a5ac5ddd64deba5f1c9388a8 Mon Sep 17 00:00:00 2001 From: paperchalice Date: Wed, 24 Jan 2024 09:27:25 +0800 Subject: [PATCH] [NewPM][CodeGen][llc] Add NPM support (#70922) Add new pass manager support to `llc`. Users can use `--passes=pass1,pass2...` to run mir passes, and use `--enable-new-pm` to run default codegen pipeline. This patch is taken from [D83612](https://reviews.llvm.org/D83612), the original author is @yuanfang-chen. --------- Co-authored-by: Yuanfang Chen <455423+yuanfang-chen@users.noreply.github.com> --- .../include/llvm/CodeGen/CodeGenPassBuilder.h | 21 +- llvm/include/llvm/CodeGen/TargetPassConfig.h | 9 +- .../include/llvm/Target/CGPassBuilderOption.h | 2 +- llvm/lib/CodeGen/TargetPassConfig.cpp | 5 +- llvm/lib/Target/X86/CMakeLists.txt | 3 + llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp | 56 +++++ llvm/lib/Target/X86/X86TargetMachine.h | 6 + llvm/test/tools/llc/new-pm/lit.local.cfg | 2 + llvm/test/tools/llc/new-pm/option-conflict.ll | 3 + llvm/test/tools/llc/new-pm/pipeline.ll | 5 + llvm/test/tools/llc/new-pm/start-stop.ll | 4 + llvm/tools/llc/CMakeLists.txt | 3 + llvm/tools/llc/NewPMDriver.cpp | 236 ++++++++++++++++++ llvm/tools/llc/NewPMDriver.h | 49 ++++ llvm/tools/llc/llc.cpp | 68 ++--- llvm/unittests/CodeGen/CMakeLists.txt | 1 - .../CodeGen/CodeGenPassBuilderTest.cpp | 141 ----------- 17 files changed, 411 insertions(+), 203 deletions(-) create mode 100644 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp create mode 100644 llvm/test/tools/llc/new-pm/lit.local.cfg create mode 100644 llvm/test/tools/llc/new-pm/option-conflict.ll create mode 100644 llvm/test/tools/llc/new-pm/pipeline.ll create mode 100644 llvm/test/tools/llc/new-pm/start-stop.ll create mode 100644 llvm/tools/llc/NewPMDriver.cpp create mode 100644 llvm/tools/llc/NewPMDriver.h delete mode 100644 llvm/unittests/CodeGen/CodeGenPassBuilderTest.cpp diff --git a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h index 12088f6fc35e0..96d6f891af4e2 100644 --- a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h +++ b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h @@ -1113,30 +1113,13 @@ void CodeGenPassBuilder::addTargetRegisterAllocator( template void CodeGenPassBuilder::addRegAllocPass(AddMachinePass &addPass, bool Optimized) const { - if (Opt.RegAlloc == RegAllocType::Default) - // With no -regalloc= override, ask the target for a regalloc pass. - derived().addTargetRegisterAllocator(addPass, Optimized); - else if (Opt.RegAlloc == RegAllocType::Basic) - addPass(RABasicPass()); - else if (Opt.RegAlloc == RegAllocType::Fast) - addPass(RAFastPass()); - else if (Opt.RegAlloc == RegAllocType::Greedy) - addPass(RAGreedyPass()); - else if (Opt.RegAlloc == RegAllocType::PBQP) - addPass(RAPBQPPass()); - else - llvm_unreachable("unknonwn register allocator type"); + // TODO: Parse Opt.RegAlloc to add register allocator. } template Error CodeGenPassBuilder::addRegAssignmentFast( AddMachinePass &addPass) const { - if (Opt.RegAlloc != RegAllocType::Default && - Opt.RegAlloc != RegAllocType::Fast) - return make_error( - "Must use fast (default) register allocator for unoptimized regalloc.", - inconvertibleErrorCode()); - + // TODO: Ensure allocator is default or fast. addRegAllocPass(addPass, false); return Error::success(); } diff --git a/llvm/include/llvm/CodeGen/TargetPassConfig.h b/llvm/include/llvm/CodeGen/TargetPassConfig.h index de6a760c4e4fd..d00e0bed91a45 100644 --- a/llvm/include/llvm/CodeGen/TargetPassConfig.h +++ b/llvm/include/llvm/CodeGen/TargetPassConfig.h @@ -171,11 +171,10 @@ class TargetPassConfig : public ImmutablePass { /// set. static bool willCompleteCodeGenPipeline(); - /// If hasLimitedCodeGenPipeline is true, this method - /// returns a string with the name of the options, separated - /// by \p Separator that caused this pipeline to be limited. - static std::string - getLimitedCodeGenPipelineReason(const char *Separator = "/"); + /// If hasLimitedCodeGenPipeline is true, this method returns + /// a string with the name of the options that caused this + /// pipeline to be limited. + static std::string getLimitedCodeGenPipelineReason(); struct StartStopInfo { bool StartAfter; diff --git a/llvm/include/llvm/Target/CGPassBuilderOption.h b/llvm/include/llvm/Target/CGPassBuilderOption.h index 6b5c023a9b6ad..8ab6d63a00056 100644 --- a/llvm/include/llvm/Target/CGPassBuilderOption.h +++ b/llvm/include/llvm/Target/CGPassBuilderOption.h @@ -52,7 +52,7 @@ struct CGPassBuilderOption { bool RequiresCodeGenSCCOrder = false; RunOutliner EnableMachineOutliner = RunOutliner::TargetDefault; - RegAllocType RegAlloc = RegAllocType::Default; + StringRef RegAlloc = "default"; std::optional EnableGlobalISelAbort; std::string FSProfileFile; std::string FSRemappingFile; diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 46697480db52a..599ca48189048 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -635,8 +635,7 @@ bool TargetPassConfig::hasLimitedCodeGenPipeline() { !willCompleteCodeGenPipeline(); } -std::string -TargetPassConfig::getLimitedCodeGenPipelineReason(const char *Separator) { +std::string TargetPassConfig::getLimitedCodeGenPipelineReason() { if (!hasLimitedCodeGenPipeline()) return std::string(); std::string Res; @@ -648,7 +647,7 @@ TargetPassConfig::getLimitedCodeGenPipelineReason(const char *Separator) { for (int Idx = 0; Idx < 4; ++Idx) if (!PassNames[Idx]->empty()) { if (!IsFirst) - Res += Separator; + Res += " and "; IsFirst = false; Res += OptNames[Idx]; } diff --git a/llvm/lib/Target/X86/CMakeLists.txt b/llvm/lib/Target/X86/CMakeLists.txt index 4d6300cad2a7a..610999f0cc3cf 100644 --- a/llvm/lib/Target/X86/CMakeLists.txt +++ b/llvm/lib/Target/X86/CMakeLists.txt @@ -29,6 +29,7 @@ set(sources X86CallFrameOptimization.cpp X86CallingConv.cpp X86CmovConversion.cpp + X86CodeGenPassBuilder.cpp X86DomainReassignment.cpp X86DiscriminateMemOps.cpp X86LowerTileCopy.cpp @@ -98,9 +99,11 @@ add_llvm_target(X86CodeGen ${sources} CodeGenTypes Core GlobalISel + IRPrinter Instrumentation MC ProfileData + Scalar SelectionDAG Support Target diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp new file mode 100644 index 0000000000000..616f777833e56 --- /dev/null +++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp @@ -0,0 +1,56 @@ +//===-- X86CodeGenPassBuilder.cpp ---------------------------------*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file contains X86 CodeGen pipeline builder. +/// TODO: Port CodeGen passes to new pass manager. +//===----------------------------------------------------------------------===// + +#include "X86TargetMachine.h" + +#include "llvm/CodeGen/CodeGenPassBuilder.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +namespace { + +class X86CodeGenPassBuilder : public CodeGenPassBuilder { +public: + explicit X86CodeGenPassBuilder(LLVMTargetMachine &TM, + CGPassBuilderOption Opts, + PassInstrumentationCallbacks *PIC) + : CodeGenPassBuilder(TM, Opts, PIC) {} + void addPreISel(AddIRPass &addPass) const; + void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const; + Error addInstSelector(AddMachinePass &) const; +}; + +void X86CodeGenPassBuilder::addPreISel(AddIRPass &addPass) const { + // TODO: Add passes pre instruction selection. +} + +void X86CodeGenPassBuilder::addAsmPrinter(AddMachinePass &addPass, + CreateMCStreamer) const { + // TODO: Add AsmPrinter. +} + +Error X86CodeGenPassBuilder::addInstSelector(AddMachinePass &) const { + // TODO: Add instruction selector. + return Error::success(); +} + +} // namespace + +Error X86TargetMachine::buildCodeGenPipeline( + ModulePassManager &MPM, MachineFunctionPassManager &MFPM, + MachineFunctionAnalysisManager &, raw_pwrite_stream &Out, + raw_pwrite_stream *DwoOut, CodeGenFileType FileType, + CGPassBuilderOption Opt, PassInstrumentationCallbacks *PIC) { + auto CGPB = X86CodeGenPassBuilder(*this, Opt, PIC); + return CGPB.buildPipeline(MPM, MFPM, Out, DwoOut, FileType); +} diff --git a/llvm/lib/Target/X86/X86TargetMachine.h b/llvm/lib/Target/X86/X86TargetMachine.h index 4836be4db0e8e..f31c971df9584 100644 --- a/llvm/lib/Target/X86/X86TargetMachine.h +++ b/llvm/lib/Target/X86/X86TargetMachine.h @@ -58,6 +58,12 @@ class X86TargetMachine final : public LLVMTargetMachine { createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F, const TargetSubtargetInfo *STI) const override; + Error buildCodeGenPipeline(ModulePassManager &, MachineFunctionPassManager &, + MachineFunctionAnalysisManager &, + raw_pwrite_stream &, raw_pwrite_stream *, + CodeGenFileType, CGPassBuilderOption, + PassInstrumentationCallbacks *) override; + bool isJIT() const { return IsJIT; } bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override; diff --git a/llvm/test/tools/llc/new-pm/lit.local.cfg b/llvm/test/tools/llc/new-pm/lit.local.cfg new file mode 100644 index 0000000000000..42bf50dcc13c3 --- /dev/null +++ b/llvm/test/tools/llc/new-pm/lit.local.cfg @@ -0,0 +1,2 @@ +if not "X86" in config.root.targets: + config.unsupported = True diff --git a/llvm/test/tools/llc/new-pm/option-conflict.ll b/llvm/test/tools/llc/new-pm/option-conflict.ll new file mode 100644 index 0000000000000..5847a32058756 --- /dev/null +++ b/llvm/test/tools/llc/new-pm/option-conflict.ll @@ -0,0 +1,3 @@ +; RUN: not llc -mtriple=x86_64-pc-linux-gnu -passes=foo -start-before=mergeicmps -stop-after=gc-lowering -filetype=null %s 2>&1 | FileCheck %s + +; CHECK: warning: --passes cannot be used with start-before and stop-after. diff --git a/llvm/test/tools/llc/new-pm/pipeline.ll b/llvm/test/tools/llc/new-pm/pipeline.ll new file mode 100644 index 0000000000000..1ace5963e4ef8 --- /dev/null +++ b/llvm/test/tools/llc/new-pm/pipeline.ll @@ -0,0 +1,5 @@ +; RUN: llc -mtriple=x86_64-pc-linux-gnu -enable-new-pm -print-pipeline-passes -filetype=null %s | FileCheck %s + +; CHECK: require,require +; CHECK: MachineSanitizerBinaryMetadata,FreeMachineFunctionPass + diff --git a/llvm/test/tools/llc/new-pm/start-stop.ll b/llvm/test/tools/llc/new-pm/start-stop.ll new file mode 100644 index 0000000000000..c25e45d1f7ab9 --- /dev/null +++ b/llvm/test/tools/llc/new-pm/start-stop.ll @@ -0,0 +1,4 @@ +; RUN: llc -mtriple=x86_64-pc-linux-gnu -enable-new-pm -print-pipeline-passes -start-before=mergeicmps -stop-after=gc-lowering -filetype=null %s | FileCheck --match-full-lines %s + +; CHECK: IR pipeline: function(mergeicmps,expand-memcmp,gc-lowering) + diff --git a/llvm/tools/llc/CMakeLists.txt b/llvm/tools/llc/CMakeLists.txt index 257d5b519f040..01825c6e4c64c 100644 --- a/llvm/tools/llc/CMakeLists.txt +++ b/llvm/tools/llc/CMakeLists.txt @@ -8,9 +8,11 @@ set(LLVM_LINK_COMPONENTS CodeGen CodeGenTypes Core + IRPrinter IRReader MC MIRParser + Passes Remarks ScalarOpts SelectionDAG @@ -23,6 +25,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llc llc.cpp + NewPMDriver.cpp DEPENDS intrinsics_gen diff --git a/llvm/tools/llc/NewPMDriver.cpp b/llvm/tools/llc/NewPMDriver.cpp new file mode 100644 index 0000000000000..13020f3dd07fe --- /dev/null +++ b/llvm/tools/llc/NewPMDriver.cpp @@ -0,0 +1,236 @@ +//===- NewPMDriver.cpp - Driver for llc using new PM ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file is just a split of the code that logically belongs in llc.cpp but +/// that includes the new pass manager headers. +/// +//===----------------------------------------------------------------------===// + +#include "NewPMDriver.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/CodeGen/CodeGenPassBuilder.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/MIRParser/MIRParser.h" +#include "llvm/CodeGen/MIRPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachinePassManager.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Target/CGPassBuilderOption.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +extern cl::opt PrintPipelinePasses; +} // namespace llvm + +using namespace llvm; + +static cl::opt + RegAlloc("regalloc-npm", + cl::desc("Register allocator to use for new pass manager"), + cl::Hidden, cl::init("default")); + +static cl::opt + DebugPM("debug-pass-manager", cl::Hidden, + cl::desc("Print pass management debugging information")); + +bool LLCDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { + DiagnosticHandler::handleDiagnostics(DI); + if (DI.getKind() == llvm::DK_SrcMgr) { + const auto &DISM = cast(DI); + const SMDiagnostic &SMD = DISM.getSMDiag(); + + SMD.print(nullptr, errs()); + + // For testing purposes, we print the LocCookie here. + if (DISM.isInlineAsmDiag() && DISM.getLocCookie()) + WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n"; + + return true; + } + + if (auto *Remark = dyn_cast(&DI)) + if (!Remark->isEnabled()) + return true; + + DiagnosticPrinterRawOStream DP(errs()); + errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": "; + DI.print(DP); + errs() << "\n"; + return true; +} + +static llvm::ExitOnError ExitOnErr; + +static void RunPasses(bool BOS, ToolOutputFile *Out, Module *M, + LLVMContext &Context, SmallString<0> &Buffer, + ModulePassManager *MPM, ModuleAnalysisManager *MAM, + MachineFunctionPassManager &MFPM, + MachineFunctionAnalysisManager &MFAM) { + assert(M && "invalid input module!"); + + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + + if (MPM) { + assert(MAM && "expect a ModuleAnalysisManager!"); + MPM->run(*M, *MAM); + } + + ExitOnErr(MFPM.run(*M, MFAM)); + + if (Context.getDiagHandlerPtr()->HasErrors) + exit(1); + + if (BOS) + Out->os() << Buffer; +} + +int llvm::compileModuleWithNewPM( + StringRef Arg0, std::unique_ptr M, std::unique_ptr MIR, + std::unique_ptr Target, std::unique_ptr Out, + std::unique_ptr DwoOut, LLVMContext &Context, + const TargetLibraryInfoImpl &TLII, bool NoVerify, StringRef PassPipeline, + CodeGenFileType FileType) { + + if (!PassPipeline.empty() && TargetPassConfig::hasLimitedCodeGenPipeline()) { + WithColor::warning(errs(), Arg0) + << "--passes cannot be used with " + << TargetPassConfig::getLimitedCodeGenPipelineReason() << ".\n"; + return 1; + } + + LLVMTargetMachine &LLVMTM = static_cast(*Target); + + raw_pwrite_stream *OS = &Out->os(); + + // Manually do the buffering rather than using buffer_ostream, + // so we can memcmp the contents in CompileTwice mode in future. + SmallString<0> Buffer; + std::unique_ptr BOS; + if ((codegen::getFileType() != CodeGenFileType::AssemblyFile && + !Out->os().supportsSeeking())) { + BOS = std::make_unique(Buffer); + OS = BOS.get(); + } + + // Fetch options from TargetPassConfig + CGPassBuilderOption Opt = getCGPassBuilderOption(); + Opt.DisableVerify = NoVerify; + Opt.DebugPM = DebugPM; + Opt.RegAlloc = RegAlloc; + + PassInstrumentationCallbacks PIC; + StandardInstrumentations SI(Context, Opt.DebugPM); + SI.registerCallbacks(PIC); + registerCodeGenCallback(PIC, LLVMTM); + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PassBuilder PB(Target.get(), PipelineTuningOptions(), std::nullopt, &PIC); + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); }); + MAM.registerPass([&] { return MachineModuleAnalysis(&LLVMTM); }); + + MachineFunctionAnalysisManager MFAM(FAM, MAM); + + if (!PassPipeline.empty()) { + // Construct a custom pass pipeline that starts after instruction + // selection. + + if (!MIR) { + WithColor::warning(errs(), Arg0) << "-passes is for .mir file only.\n"; + return 1; + } + + MachineFunctionPassManager MFPM; + ExitOnErr(PB.parsePassPipeline(MFPM, PassPipeline)); + MFPM.addPass(PrintMIRPass(*OS)); + MFPM.addPass(FreeMachineFunctionPass()); + + auto &MMI = MFAM.getResult(*M); + if (MIR->parseMachineFunctions(*M, MMI)) + return 1; + + RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, nullptr, nullptr, + MFPM, MFAM); + } else { + ModulePassManager MPM; + MachineFunctionPassManager MFPM; + + ExitOnErr(LLVMTM.buildCodeGenPipeline(MPM, MFPM, MFAM, *OS, + DwoOut ? &DwoOut->os() : nullptr, + FileType, Opt, &PIC)); + + auto StartStopInfo = TargetPassConfig::getStartStopInfo(PIC); + assert(StartStopInfo && "Expect StartStopInfo!"); + // Add IR or MIR printing pass according the pass type. + + if (auto StopPassName = StartStopInfo->StopPass; !StopPassName.empty()) { + MFPM.addPass(PrintMIRPass(*OS)); + MFPM.addPass(FreeMachineFunctionPass()); + } + + if (PrintPipelinePasses) { + std::string IRPipeline; + raw_string_ostream IRSOS(IRPipeline); + MPM.printPipeline(IRSOS, [&PIC](StringRef ClassName) { + auto PassName = PIC.getPassNameForClassName(ClassName); + return PassName.empty() ? ClassName : PassName; + }); + outs() << "IR pipeline: " << IRPipeline << '\n'; + + std::string MIRPipeline; + raw_string_ostream MIRSOS(MIRPipeline); + MFPM.printPipeline(MIRSOS, [&PIC](StringRef ClassName) { + auto PassName = PIC.getPassNameForClassName(ClassName); + return PassName.empty() ? ClassName : PassName; + }); + outs() << "MIR pipeline: " << MIRPipeline << '\n'; + return 0; + } + + RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, &MPM, &MAM, MFPM, + MFAM); + } + + // Declare success. + Out->keep(); + if (DwoOut) + DwoOut->keep(); + + return 0; +} diff --git a/llvm/tools/llc/NewPMDriver.h b/llvm/tools/llc/NewPMDriver.h new file mode 100644 index 0000000000000..b0beeaf596c8f --- /dev/null +++ b/llvm/tools/llc/NewPMDriver.h @@ -0,0 +1,49 @@ +//===- NewPMDriver.h - Function to drive llc with the new PM ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// A single function which is called to drive the llc behavior for the new +/// PassManager. +/// +/// This is only in a separate TU with a header to avoid including all of the +/// old pass manager headers and the new pass manager headers into the same +/// file. Eventually all of the routines here will get folded back into +/// llc.cpp. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_LLC_NEWPMDRIVER_H +#define LLVM_TOOLS_LLC_NEWPMDRIVER_H + +#include "llvm/IR/DiagnosticHandler.h" +#include "llvm/Support/CodeGen.h" +#include +#include + +namespace llvm { +class Module; +class TargetLibraryInfoImpl; +class TargetMachine; +class ToolOutputFile; +class LLVMContext; +class MIRParser; + +struct LLCDiagnosticHandler : public DiagnosticHandler { + bool handleDiagnostics(const DiagnosticInfo &DI) override; +}; + +int compileModuleWithNewPM(StringRef Arg0, std::unique_ptr M, + std::unique_ptr MIR, + std::unique_ptr Target, + std::unique_ptr Out, + std::unique_ptr DwoOut, + LLVMContext &Context, + const TargetLibraryInfoImpl &TLII, bool NoVerify, + StringRef PassPipeline, CodeGenFileType FileType); +} // namespace llvm + +#endif diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index 02187f7048a10..d76d89eae3b18 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "NewPMDriver.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -186,6 +187,21 @@ static cl::opt RemarksFormat( cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); +static cl::opt EnableNewPassManager( + "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false)); + +// This flag specifies a textual description of the optimization pass pipeline +// to run over the module. This flag switches opt to use the new pass manager +// infrastructure, completely disabling all of the flags specific to the old +// pass management. +static cl::opt PassPipeline( + "passes", + cl::desc( + "A textual description of the pass pipeline. To have analysis passes " + "available before a certain pass, add 'require'.")); +static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline), + cl::desc("Alias for -passes")); + static cl::opt TryUseNewDbgInfoFormat( "try-experimental-debuginfo-iterators", cl::desc("Enable debuginfo iterator positions, if they're built in"), @@ -306,34 +322,6 @@ static std::unique_ptr GetOutputStream(const char *TargetName, return FDOut; } -struct LLCDiagnosticHandler : public DiagnosticHandler { - bool handleDiagnostics(const DiagnosticInfo &DI) override { - DiagnosticHandler::handleDiagnostics(DI); - if (DI.getKind() == llvm::DK_SrcMgr) { - const auto &DISM = cast(DI); - const SMDiagnostic &SMD = DISM.getSMDiag(); - - SMD.print(nullptr, errs()); - - // For testing purposes, we print the LocCookie here. - if (DISM.isInlineAsmDiag() && DISM.getLocCookie()) - WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n"; - - return true; - } - - if (auto *Remark = dyn_cast(&DI)) - if (!Remark->isEnabled()) - return true; - - DiagnosticPrinterRawOStream DP(errs()); - errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": "; - DI.print(DP); - errs() << "\n"; - return true; - } -}; - // main - Entry point for the llc compiler. // int main(int argc, char **argv) { @@ -377,6 +365,13 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + if (!PassPipeline.empty() && !getRunPassNames().empty()) { + errs() << "The `llc -run-pass=...` syntax for the new pass manager is " + "not supported, please use `llc -passes=` (or the `-p` " + "alias for a more concise version).\n"; + return 1; + } + // RemoveDIs debug-info transition: tests may request that we /try/ to use the // new debug-info format, if it's built in. #ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS @@ -642,16 +637,12 @@ static int compileModule(char **argv, LLVMContext &Context) { reportError(EC.message(), SplitDwarfOutputFile); } - // Build up all of the passes that we want to do to the module. - legacy::PassManager PM; - // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple())); // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) TLII.disableAllFunctions(); - PM.add(new TargetLibraryInfoWrapperPass(TLII)); // Verify module immediately to catch problems before doInitialization() is // called on any passes. @@ -667,6 +658,17 @@ static int compileModule(char **argv, LLVMContext &Context) { WithColor::warning(errs(), argv[0]) << ": warning: ignoring -mc-relax-all because filetype != obj"; + if (EnableNewPassManager || !PassPipeline.empty()) { + return compileModuleWithNewPM(argv[0], std::move(M), std::move(MIR), + std::move(Target), std::move(Out), + std::move(DwoOut), Context, TLII, NoVerify, + PassPipeline, codegen::getFileType()); + } + + // Build up all of the passes that we want to do to the module. + legacy::PassManager PM; + PM.add(new TargetLibraryInfoWrapperPass(TLII)); + { raw_pwrite_stream *OS = &Out->os(); @@ -700,7 +702,7 @@ static int compileModule(char **argv, LLVMContext &Context) { if (TPC.hasLimitedCodeGenPipeline()) { WithColor::warning(errs(), argv[0]) << "run-pass cannot be used with " - << TPC.getLimitedCodeGenPipelineReason(" and ") << ".\n"; + << TPC.getLimitedCodeGenPipelineReason() << ".\n"; delete PTPC; delete MMIWP; return 1; diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt index c78cbfcc28193..6140e0d6fb370 100644 --- a/llvm/unittests/CodeGen/CMakeLists.txt +++ b/llvm/unittests/CodeGen/CMakeLists.txt @@ -25,7 +25,6 @@ add_llvm_unittest(CodeGenTests AMDGPUMetadataTest.cpp AsmPrinterDwarfTest.cpp CCStateTest.cpp - CodeGenPassBuilderTest.cpp DIEHashTest.cpp DIETest.cpp DwarfStringPoolEntryRefTest.cpp diff --git a/llvm/unittests/CodeGen/CodeGenPassBuilderTest.cpp b/llvm/unittests/CodeGen/CodeGenPassBuilderTest.cpp deleted file mode 100644 index d6ec393155cf0..0000000000000 --- a/llvm/unittests/CodeGen/CodeGenPassBuilderTest.cpp +++ /dev/null @@ -1,141 +0,0 @@ -//===- llvm/unittest/CodeGen/CodeGenPassBuilderTest.cpp -------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/CodeGenPassBuilder.h" -#include "llvm/CodeGen/MachinePassManager.h" -#include "llvm/CodeGen/TargetPassConfig.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Passes/PassBuilder.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TargetParser/Host.h" -#include "gtest/gtest.h" -#include - -using namespace llvm; - -namespace { - -class DummyCodeGenPassBuilder - : public CodeGenPassBuilder { -public: - DummyCodeGenPassBuilder(LLVMTargetMachine &TM, CGPassBuilderOption Opts, - PassInstrumentationCallbacks *PIC) - : CodeGenPassBuilder(TM, Opts, PIC){}; - - void addPreISel(AddIRPass &addPass) const { - addPass(NoOpModulePass()); - addPass(NoOpFunctionPass()); - addPass(NoOpFunctionPass()); - addPass(NoOpFunctionPass()); - addPass(NoOpModulePass()); - addPass(NoOpFunctionPass()); - } - - void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const {} - - Error addInstSelector(AddMachinePass &) const { return Error::success(); } -}; - -class CodeGenPassBuilderTest : public testing::Test { -public: - std::unique_ptr TM; - - static void SetUpTestCase() { - InitializeAllTargets(); - InitializeAllTargetMCs(); - - // TODO: Move this test to normal lit test when llc supports new pm. - static const char *argv[] = { - "test", - "-print-pipeline-passes", - }; - int argc = std::size(argv); - cl::ParseCommandLineOptions(argc, argv); - } - - void SetUp() override { - std::string TripleName = Triple::normalize("x86_64-pc-linux-gnu"); - std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); - if (!TheTarget) - GTEST_SKIP(); - - TargetOptions Options; - TM = std::unique_ptr(static_cast( - TheTarget->createTargetMachine("", "", "", Options, std::nullopt))); - if (!TM) - GTEST_SKIP(); - } -}; - -TEST_F(CodeGenPassBuilderTest, basic) { - LoopAnalysisManager LAM; - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; - - PassInstrumentationCallbacks PIC; - DummyCodeGenPassBuilder CGPB(*TM, getCGPassBuilderOption(), &PIC); - PipelineTuningOptions PTO; - PassBuilder PB(TM.get(), PTO, std::nullopt, &PIC); - - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - ModulePassManager MPM; - MachineFunctionPassManager MFPM; - Error Err = - CGPB.buildPipeline(MPM, MFPM, outs(), nullptr, CodeGenFileType::Null); - EXPECT_FALSE(Err); - - std::string IRPipeline; - raw_string_ostream IROS(IRPipeline); - MPM.printPipeline(IROS, [&PIC](StringRef Name) { - auto PassName = PIC.getPassNameForClassName(Name); - return PassName.empty() ? Name : PassName; - }); - const char ExpectedIRPipeline[] = - "no-op-module,function(no-op-function," - "no-op-function,no-op-function),no-op-module"; - // TODO: Move this test to normal lit test when llc supports new pm. - EXPECT_TRUE(StringRef(IRPipeline).contains(ExpectedIRPipeline)); - - std::string MIRPipeline; - raw_string_ostream MIROS(MIRPipeline); - MFPM.printPipeline(MIROS, [&PIC](StringRef Name) { - auto PassName = PIC.getPassNameForClassName(Name); - return PassName.empty() ? Name : PassName; - }); - const char ExpectedMIRPipeline[] = - "FinalizeISelPass,EarlyTailDuplicatePass,OptimizePHIsPass," - "StackColoringPass,LocalStackSlotPass,DeadMachineInstructionElimPass," - "EarlyMachineLICMPass,MachineCSEPass,MachineSinkingPass," - "PeepholeOptimizerPass,DeadMachineInstructionElimPass," - "DetectDeadLanesPass,ProcessImplicitDefsPass,PHIEliminationPass," - "TwoAddressInstructionPass,RegisterCoalescerPass," - "RenameIndependentSubregsPass,MachineSchedulerPass,RAGreedyPass," - "VirtRegRewriterPass,StackSlotColoringPass," - "RemoveRedundantDebugValuesPass,PostRAMachineSinkingPass,ShrinkWrapPass," - "PrologEpilogInserterPass,BranchFolderPass,TailDuplicatePass," - "MachineLateInstrsCleanupPass,MachineCopyPropagationPass," - "ExpandPostRAPseudosPass,PostRASchedulerPass,MachineBlockPlacementPass," - "FEntryInserterPass,XRayInstrumentationPass,PatchableFunctionPass," - "FuncletLayoutPass,StackMapLivenessPass,LiveDebugValuesPass," - "MachineSanitizerBinaryMetadata,FreeMachineFunctionPass"; - // TODO: Check pipeline string when all pass names are populated. - // TODO: Move this test to normal lit test when llc supports new pm. - EXPECT_EQ(MIRPipeline, ExpectedMIRPipeline); -} - -} // namespace