[llvm-branch-commits] [clang] [llvm] [LTO] Add support for NewPM CodeGen (PR #210249)
Vikram Hegde via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Sep 27 23:31:47 PDT 2026
https://github.com/vikramRH updated https://github.com/llvm/llvm-project/pull/210249
>From 1d61a4122d5d74d38f427a3d712f6f206455f8d8 Mon Sep 17 00:00:00 2001
From: vikhegde <vikram.hegde at amd.com>
Date: Thu, 16 Jul 2026 16:23:49 +0530
Subject: [PATCH] [CodeGen][LTO] Switch to runCodeGenPipeline abstraction
---
clang/lib/CodeGen/BackendUtil.cpp | 10 ++--
llvm/include/llvm/Passes/RunCodeGen.h | 30 ++++++++---
llvm/lib/LTO/LTOBackend.cpp | 53 ++++++++----------
llvm/lib/Passes/RunCodeGen.cpp | 54 +++++++++++--------
.../CodeGen/AMDGPU/lto-lower-module-lds.ll | 49 +++++++++++++++++
5 files changed, 134 insertions(+), 62 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 5a01779613c8c..b71dfbdd133ca 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1215,10 +1215,12 @@ void EmitAssemblyHelper::RunCodegenPipeline(
}
TimeCodegenPasses([&]() {
- Error CodeGenError = runCodeGenPipeline(
- *TM, *TheModule, *OS, DwoOS, CGFT, PrintPipelinePasses.has_value(),
- !CodeGenOpts.VerifyModule, /*DisableSimplifyLibCalls=*/false,
- CI.getVirtualFileSystemPtr());
+ CodeGenPipelineConfig Config;
+ Config.PrintPipelinePasses = PrintPipelinePasses.has_value();
+ Config.DisableVerify = !CodeGenOpts.VerifyModule;
+ Config.VFS = CI.getVirtualFileSystemPtr();
+ Error CodeGenError =
+ runCodeGenPipeline(*TM, *TheModule, *OS, DwoOS, CGFT, Config);
if (CodeGenError)
Diags.Report(diag::err_fe_unable_to_interface_with_target);
});
diff --git a/llvm/include/llvm/Passes/RunCodeGen.h b/llvm/include/llvm/Passes/RunCodeGen.h
index b61e171363b7d..15aa926300aeb 100644
--- a/llvm/include/llvm/Passes/RunCodeGen.h
+++ b/llvm/include/llvm/Passes/RunCodeGen.h
@@ -16,12 +16,30 @@
namespace llvm {
-LLVM_ABI Error runCodeGenPipeline(
- TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
- std::unique_ptr<ToolOutputFile> &DwoOS, CodeGenFileType CGFT,
- bool PrintPipelinePasses = false, bool DisableVerify = true,
- bool DisableSimplifyLibCalls = false,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem());
+class ModuleSummaryIndex;
+
+/// Options for runCodeGenPipeline().
+struct CodeGenPipelineConfig {
+ /// FIXME: Need to be implemented in runCodeGenPipeline().
+ bool PrintPipelinePasses = false;
+
+ bool DisableVerify = true;
+ bool DisableSimplifyLibCalls = false;
+ /// Log each pass as it runs. New pass manager only.
+ bool DebugPassManager = false;
+ /// Verify the IR between passes. New pass manager only.
+ bool VerifyEach = false;
+ /// LTO uses this to expose the combined summary index to summary-consuming
+ /// codegen passes.
+ const ModuleSummaryIndex *SummaryIndex = nullptr;
+ /// For passes needing file access.
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr;
+};
+
+Error runCodeGenPipeline(TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
+ std::unique_ptr<ToolOutputFile> &DwoOS,
+ CodeGenFileType CGFT,
+ const CodeGenPipelineConfig &Config = {});
} // namespace llvm
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index d9a6551139d37..2b1d57d81f5ef 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -30,6 +30,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ModuleSymbolTable.h"
#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/RunCodeGen.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Plugins/PassPlugin.h"
#include "llvm/Support/Error.h"
@@ -479,36 +480,28 @@ static void codegen(const Config &Conf, TargetMachine *TM,
std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName;
- // Create the codegen pipeline in its own scope so it gets deleted before
- // Stream->commit() is called. The commit function of CacheStream deletes
- // the raw stream, which is too early as streamers (e.g. MCAsmStreamer)
- // keep the pointer and may use it until their destruction. See #138194.
- {
- legacy::PassManager CodeGenPasses;
- TargetLibraryInfoImpl TLII(Mod.getTargetTriple(), TM->Options.VecLib);
- CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
- CodeGenPasses.add(new RuntimeLibraryInfoWrapper(
- TM->Options.MCOptions.ABIName, TM->Options.VecLib));
-
- // No need to make index available if the module is empty.
- // In theory these passes should not use the index for an empty
- // module, however, this guards against doing any unnecessary summary-based
- // analysis in the case of a ThinLTO build where this might be an empty
- // regular LTO combined module, with a large combined index from ThinLTO.
- if (!isEmptyModule(Mod))
- CodeGenPasses.add(
- createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex));
- if (Conf.PreCodeGenPassesHook)
- Conf.PreCodeGenPassesHook(CodeGenPasses);
- if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
- DwoOut ? &DwoOut->os() : nullptr,
- Conf.CGFileType))
- report_fatal_error("Failed to setup codegen");
- CodeGenPasses.run(Mod);
-
- if (DwoOut)
- DwoOut->keep();
- }
+ CodeGenPipelineConfig CGConfig;
+ CGConfig.DebugPassManager = Conf.DebugPassManager;
+ CGConfig.VerifyEach = Conf.VerifyEach;
+ // No need to make index available if the module is empty.
+ // In theory these passes should not use the index for an empty
+ // module, however, this guards against doing any unnecessary summary-based
+ // analysis in the case of a ThinLTO build where this might be an empty
+ // regular LTO combined module, with a large combined index from ThinLTO.
+ if (!isEmptyModule(Mod))
+ CGConfig.SummaryIndex = &CombinedIndex;
+
+ // runCodeGenPipeline() keeps the pipeline local to itself so that it gets
+ // deleted before Stream->commit() is called below. The commit function of
+ // CacheStream deletes the raw stream, which is too early as streamers (e.g.
+ // MCAsmStreamer) keep the pointer and may use it until their destruction.
+ // See #138194.
+ if (Error Err = runCodeGenPipeline(*TM, Mod, *Stream->OS, DwoOut,
+ Conf.CGFileType, CGConfig))
+ report_fatal_error(std::move(Err));
+
+ if (DwoOut)
+ DwoOut->keep();
if (Error Err = Stream->commit())
report_fatal_error(std::move(Err));
diff --git a/llvm/lib/Passes/RunCodeGen.cpp b/llvm/lib/Passes/RunCodeGen.cpp
index fee9b8f4e00de..9112ad1df73df 100644
--- a/llvm/lib/Passes/RunCodeGen.cpp
+++ b/llvm/lib/Passes/RunCodeGen.cpp
@@ -9,6 +9,7 @@
#include "llvm/Passes/RunCodeGen.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LoopAnalysisManager.h"
+#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/Analysis/RuntimeLibcallInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
@@ -32,17 +33,17 @@ static cl::opt<cl::boolOrDefault>
"option will default to what the target prefers."),
cl::init(cl::boolOrDefault::BOU_UNSET));
-static Error
-runCodeGenPipelineLegacy(TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
- std::unique_ptr<ToolOutputFile> &DwoOS,
- CodeGenFileType CGFT, bool PrintPipelinePasses,
- bool DisableVerify, bool DisableSimplifyLibCalls) {
+static Error runCodeGenPipelineLegacy(TargetMachine &TM, Module &M,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<ToolOutputFile> &DwoOS,
+ CodeGenFileType CGFT,
+ const CodeGenPipelineConfig &Config) {
legacy::PassManager CodeGenPasses;
CodeGenPasses.add(
createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
// Add LibraryInfo.
TargetLibraryInfoImpl TLII(TM.getTargetTriple(), TM.Options.VecLib);
- if (DisableSimplifyLibCalls)
+ if (Config.DisableSimplifyLibCalls)
TLII.disableAllFunctions();
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
@@ -50,8 +51,12 @@ runCodeGenPipelineLegacy(TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
CodeGenPasses.add(
new RuntimeLibraryInfoWrapper(Options.MCOptions.ABIName, Options.VecLib));
+ if (Config.SummaryIndex)
+ CodeGenPasses.add(
+ createImmutableModuleSummaryIndexWrapperPass(Config.SummaryIndex));
+
if (TM.addPassesToEmitFile(CodeGenPasses, OS, DwoOS ? &DwoOS->os() : nullptr,
- CGFT, DisableVerify))
+ CGFT, Config.DisableVerify))
return createStringError("Failed to construct CodeGen pipeline");
CodeGenPasses.run(M);
@@ -61,8 +66,8 @@ runCodeGenPipelineLegacy(TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
static Error runCodeGenPipelineNewPM(TargetMachine &TM, Module &M,
raw_pwrite_stream &OS,
std::unique_ptr<ToolOutputFile> &DwoOS,
- CodeGenFileType CGFT, bool DisableVerify,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+ CodeGenFileType CGFT,
+ const CodeGenPipelineConfig &Config) {
ModulePassManager MPM;
MachineFunctionAnalysisManager MFAM;
LoopAnalysisManager LAM;
@@ -70,17 +75,21 @@ static Error runCodeGenPipelineNewPM(TargetMachine &TM, Module &M,
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
CGPassBuilderOption Opt = getCGPassBuilderOption();
- Opt.DisableVerify = DisableVerify;
+ Opt.DisableVerify = Config.DisableVerify;
MachineModuleInfo MMI(&TM);
PassInstrumentationCallbacks PIC;
PipelineTuningOptions PTOptions;
TargetMachine *TMPointer = &TM;
- PassBuilder PB(TMPointer, PTOptions, std::nullopt, &PIC, VFS);
+ // Only resolve the fallback once we know we need one: under clang's IO
+ // sandbox, calling vfs::getRealFileSystem() at all is fatal.
+ PassBuilder PB(TMPointer, PTOptions, std::nullopt, &PIC,
+ Config.VFS ? Config.VFS : vfs::getRealFileSystem());
- StandardInstrumentations SI(M.getContext(), /*DebugLogging=*/false);
+ StandardInstrumentations SI(M.getContext(), Config.DebugPassManager,
+ Config.VerifyEach);
SI.registerCallbacks(PIC, &MAM);
- TargetLibraryInfoImpl TLII(M.getTargetTriple());
+ TargetLibraryInfoImpl TLII(M.getTargetTriple(), TM.Options.VecLib);
FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
MAM.registerPass([&] { return MachineModuleAnalysis(MMI); });
MAM.registerPass([&] {
@@ -88,6 +97,11 @@ static Error runCodeGenPipelineNewPM(TargetMachine &TM, Module &M,
return RuntimeLibraryAnalysis(Options.MCOptions.ABIName, Options.VecLib);
});
+ if (Config.SummaryIndex)
+ MAM.registerPass([&] {
+ return ImmutableModuleSummaryIndexAnalysis(Config.SummaryIndex);
+ });
+
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
@@ -108,15 +122,11 @@ static Error runCodeGenPipelineNewPM(TargetMachine &TM, Module &M,
Error llvm::runCodeGenPipeline(TargetMachine &TM, Module &M,
raw_pwrite_stream &OS,
std::unique_ptr<ToolOutputFile> &DwoOS,
- CodeGenFileType CGFT, bool PrintPipelinePasses,
- bool DisableVerify, bool DisableSimplifyLibCalls,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+ CodeGenFileType CGFT,
+ const CodeGenPipelineConfig &Config) {
if (ForceNewPM == cl::boolOrDefault::BOU_TRUE ||
- (TM.shouldDefaultToNewPM() &&
- ForceNewPM != cl::boolOrDefault::BOU_FALSE)) {
- return runCodeGenPipelineNewPM(TM, M, OS, DwoOS, CGFT, DisableVerify, VFS);
- }
+ (TM.shouldDefaultToNewPM() && ForceNewPM != cl::boolOrDefault::BOU_FALSE))
+ return runCodeGenPipelineNewPM(TM, M, OS, DwoOS, CGFT, Config);
- return runCodeGenPipelineLegacy(TM, M, OS, DwoOS, CGFT, PrintPipelinePasses,
- DisableVerify, DisableSimplifyLibCalls);
+ return runCodeGenPipelineLegacy(TM, M, OS, DwoOS, CGFT, Config);
}
diff --git a/llvm/test/CodeGen/AMDGPU/lto-lower-module-lds.ll b/llvm/test/CodeGen/AMDGPU/lto-lower-module-lds.ll
index a846a7cc12e49..b81cc4ef3c9c0 100644
--- a/llvm/test/CodeGen/AMDGPU/lto-lower-module-lds.ll
+++ b/llvm/test/CodeGen/AMDGPU/lto-lower-module-lds.ll
@@ -27,11 +27,60 @@
; First print will be from the New PM during the full LTO pipeline.
; Second print will be from the legacy PM during the CG pipeline.
+; These will be updated when NPM becomes default for AMDGPU CG pipeline.
; CHECK: Running pass: AMDGPULowerModuleLDSPass on [module]
; CHECK: ModulePass Manager
; CHECK: Lower uses of LDS variables from non-kernel functions
+; Test -force-new-pm-codegen=true.
+
+; ENABLE-NPM Default O0
+; RUN: opt -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -O0 -cg-opt-level 0 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=true -debug-pass-manager 2>&1 | FileCheck --check-prefix=ENABLE-NPM %s
+
+; ENABLE-NPM Unified O0
+; RUN: opt -unified-lto -thinlto-split-lto-unit -thinlto-bc -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -unified-lto=full -O0 -cg-opt-level 0 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=true -debug-pass-manager 2>&1 | FileCheck --check-prefix=ENABLE-NPM %s
+
+; ENABLE-NPM Default O2
+; RUN: opt -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -O2 -cg-opt-level 2 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=true -debug-pass-manager 2>&1 | FileCheck --check-prefix=ENABLE-NPM %s
+
+; ENABLE-NPM Unified O2
+; RUN: opt -unified-lto -thinlto-split-lto-unit -thinlto-bc -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -unified-lto=full -O2 -cg-opt-level 2 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=true -debug-pass-manager 2>&1 | FileCheck --check-prefix=ENABLE-NPM %s
+
+; ENABLE-NPM-NOT: ModulePass Manager
+; ENABLE-NPM: Running pass: AMDGPULowerModuleLDSPass on [module]
+; ENABLE-NPM: Running pass: SelectionDAGISelPass on test
+; ENABLE-NPM: Running pass: PrologEpilogInserterPass on test
+; ENABLE-NPM: Running pass: AMDGPUAsmPrinterPass on test
+
+; Test -force-new-pm-codegen=false drives the CodeGen pipeline
+; with the legacy PM, regardless of the target default.
+
+; DISABLE-NPM Default O0
+; RUN: opt -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -O0 -cg-opt-level 0 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=false -debug-pass-manager -debug-pass=Structure 2>&1 | FileCheck --check-prefix=DISABLE-NPM %s
+
+; DISABLE-NPM Unified O0
+; RUN: opt -unified-lto -thinlto-split-lto-unit -thinlto-bc -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -unified-lto=full -O0 -cg-opt-level 0 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=false -debug-pass-manager -debug-pass=Structure 2>&1 | FileCheck --check-prefix=DISABLE-NPM %s
+
+; DISABLE-NPM Default O2
+; RUN: opt -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -O2 -cg-opt-level 2 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=false -debug-pass-manager -debug-pass=Structure 2>&1 | FileCheck --check-prefix=DISABLE-NPM %s
+
+; DISABLE-NPM Unified O2
+; RUN: opt -unified-lto -thinlto-split-lto-unit -thinlto-bc -mtriple=amdgpu10.30-- %s -o %t.bc
+; RUN: llvm-lto2 run -unified-lto=full -O2 -cg-opt-level 2 %t.bc -o %t.s -r %t.bc,test,px -force-new-pm-codegen=false -debug-pass-manager -debug-pass=Structure 2>&1 | FileCheck --check-prefix=DISABLE-NPM %s
+
+; DISABLE-NPM: Running pass: AMDGPULowerModuleLDSPass on [module]
+; DISABLE-NPM: ModulePass Manager
+; DISABLE-NPM: Lower uses of LDS variables from non-kernel functions
+; DISABLE-NPM-NOT: Running pass: SelectionDAGISelPass
+
@lds = internal unnamed_addr addrspace(3) global i32 poison, align 4
define amdgpu_kernel void @test() {
More information about the llvm-branch-commits
mailing list