//===- 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; }