[clang] [lld] [lld][LTO] Respect `-fno-slp-vectorize` for the LTO pipeline (PR #201585)
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 4 06:31:52 PDT 2026
https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/201585
Summary:
This is related to reported regressions in the GROMACS suite when
offloading to AMDGCN devices through the RDC / LTO interface. The
application intentionally passes `-fno-slp-vectorize` to disable that
pass, but there's currently no way to do this through the LTO pipline.
This PR adds a few option to `lld` that suppresses SLP from being added
to the pipeline.
>From 5c50531b5ff8c2809f9becf58cbcf88dca32bae7 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Thu, 4 Jun 2026 08:20:30 -0500
Subject: [PATCH] [lld][LTO] Respect `-fno-slp-vectorize` for the LTO pipeline
Summary:
This is related to reported regressions in the GROMACS suite when
offloading to AMDGCN devices through the RDC / LTO interface. The
application intentionally passes `-fno-slp-vectorize` to disable that
pass, but there's currently no way to do this through the LTO pipline.
This PR adds a few option to `lld` that suppresses SLP from being added
to the pipeline.
---
clang/lib/Driver/ToolChains/Clang.cpp | 4 +++-
clang/lib/Driver/ToolChains/CommonArgs.cpp | 11 +++++++++++
clang/test/Driver/lto.c | 8 ++++++++
lld/ELF/Config.h | 1 +
lld/ELF/Driver.cpp | 2 ++
lld/ELF/LTO.cpp | 2 +-
lld/ELF/Options.td | 7 +++++++
lld/test/ELF/lto/slp-vectorize-pm.ll | 3 +++
8 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 25bf84a2bde33..55519f6e1089e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9601,7 +9601,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
OPT_fsanitize_minimal_runtime,
OPT_fno_sanitize_minimal_runtime,
OPT_fsanitize_trap_EQ,
- OPT_fno_sanitize_trap_EQ};
+ OPT_fno_sanitize_trap_EQ,
+ OPT_fslp_vectorize,
+ OPT_fno_slp_vectorize};
const llvm::DenseSet<unsigned> LinkerOptions{OPT_mllvm, OPT_Zlinker_input};
auto ToolChainHasRT = [&](const ToolChain &TC, StringRef Name) {
return TC.getVFS().exists(
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 47953bc3a23b5..88175762f7d30 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1157,6 +1157,17 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
ParallelismOpt + Parallelism));
+ // Forward SLP vectorization preference to the LTO backend.
+ if (Arg *A = Args.getLastArg(options::OPT_fslp_vectorize,
+ options::OPT_fno_slp_vectorize)) {
+ if (A->getOption().matches(options::OPT_fslp_vectorize))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "slp-vectorize"));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "no-slp-vectorize"));
+ }
+
// Pass down GlobalISel options.
if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel,
options::OPT_fno_global_isel)) {
diff --git a/clang/test/Driver/lto.c b/clang/test/Driver/lto.c
index 81165d3b9e8a3..44514c0cd830e 100644
--- a/clang/test/Driver/lto.c
+++ b/clang/test/Driver/lto.c
@@ -117,6 +117,14 @@
// CHECK-GISEL: "-plugin-opt=-global-isel=1"
// CHECK-DISABLE-GISEL: "-plugin-opt=-global-isel=0"
+// RUN: %clang --target=x86_64-unknown-linux-gnu -### %s -flto -fno-slp-vectorize 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-SLP < %t %s
+// RUN: %clang --target=x86_64-unknown-linux-gnu -### %s -flto -fslp-vectorize 2> %t
+// RUN: FileCheck --check-prefix=CHECK-SLP < %t %s
+//
+// CHECK-NO-SLP: "-plugin-opt=no-slp-vectorize"
+// CHECK-SLP: "-plugin-opt=slp-vectorize"
+
// -flto passes -time-passes when -ftime-report is passed
// RUN: %clang --target=x86_64-unknown-linux-gnu -### %s -flto -ftime-report 2> %t
// RUN: FileCheck --check-prefix=CHECK-TIME-REPORT < %t %s
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 12b16ded61fca..58eb12d87a36e 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -373,6 +373,7 @@ struct Config {
bool ltoPGOWarnMismatch;
bool ltoDebugPassManager;
bool ltoEmitAsm;
+ bool ltoSLPVectorize;
bool ltoUniqueBasicBlockSectionNames;
bool ltoValidateAllVtablesHaveTypeInfos;
bool ltoWholeProgramVisibility;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 7ec7dfcae6bca..9d1981986969f 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1468,6 +1468,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ctx.arg.ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
ctx.arg.ltoEmitAsm = args.hasArg(OPT_lto_emit_asm);
ctx.arg.ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes);
+ ctx.arg.ltoSLPVectorize =
+ args.hasFlag(OPT_lto_slp_vectorize, OPT_no_lto_slp_vectorize, true);
ctx.arg.ltoWholeProgramVisibility =
args.hasFlag(OPT_lto_whole_program_visibility,
OPT_no_lto_whole_program_visibility, false);
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index e40575bffec62..804f6959f87fc 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -116,7 +116,7 @@ static lto::Config createConfig(Ctx &ctx) {
c.CGOptLevel = ctx.arg.ltoCgo;
c.PTO.LoopVectorization = c.OptLevel > 1;
- c.PTO.SLPVectorization = c.OptLevel > 1;
+ c.PTO.SLPVectorization = ctx.arg.ltoSLPVectorize && c.OptLevel > 1;
// Set up a custom pipeline if we've been asked to.
c.OptPipeline = std::string(ctx.arg.ltoNewPmPasses);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 64c42eb49607d..6b9ab89b9d987 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -672,6 +672,9 @@ defm lto_known_safe_vtables : EEq<"lto-known-safe-vtables",
def lto_obj_path_eq: JJ<"lto-obj-path=">;
def lto_sample_profile: JJ<"lto-sample-profile=">,
HelpText<"Sample profile file path">;
+defm lto_slp_vectorize: BB<"lto-slp-vectorize",
+ "Enable SLP vectorization during LTO (default at O2+)",
+ "Disable SLP vectorization during LTO">;
defm lto_validate_all_vtables_have_type_infos: BB<"lto-validate-all-vtables-have-type-infos",
"Validate that all vtables have type infos for LTO link",
"Do not validate that all vtables have type infos for LTO link">;
@@ -776,6 +779,10 @@ def: J<"plugin-opt=opt-remarks-hotness-threshold=">,
def: J<"plugin-opt=sample-profile=">,
Alias<lto_sample_profile>, HelpText<"Alias for --lto-sample-profile">;
def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for --save-temps">;
+def: F<"plugin-opt=slp-vectorize">,
+ Alias<lto_slp_vectorize>, HelpText<"Alias for --lto-slp-vectorize">;
+def: F<"plugin-opt=no-slp-vectorize">,
+ Alias<no_lto_slp_vectorize>, HelpText<"Alias for --no-lto-slp-vectorize">;
def plugin_opt_stats_file: J<"plugin-opt=stats-file=">,
HelpText<"Filename to write LTO statistics to">;
def: J<"plugin-opt=time-trace=">, Alias<time_trace_eq>, HelpText<"Alias for --time-trace=">;
diff --git a/lld/test/ELF/lto/slp-vectorize-pm.ll b/lld/test/ELF/lto/slp-vectorize-pm.ll
index 2171092569536..f0576c98d9f46 100644
--- a/lld/test/ELF/lto/slp-vectorize-pm.ll
+++ b/lld/test/ELF/lto/slp-vectorize-pm.ll
@@ -14,10 +14,13 @@
; RUN: ld.lld --plugin-opt=debug-pass-manager --plugin-opt=O3 --plugin-opt=save-temps -shared -o %t4.o %t.o 2>&1 | FileCheck %s --check-prefix=CHECK-O3-SLP
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-O3-LPV
+; RUN: ld.lld --plugin-opt=debug-pass-manager --plugin-opt=O2 --no-lto-slp-vectorize -shared -o %t5.o %t.o 2>&1 | FileCheck %s --check-prefix=CHECK-O2-NOSLP
+
; CHECK-O0-SLP-NOT: Running pass: SLPVectorizerPass
; CHECK-O1-SLP-NOT: Running pass: SLPVectorizerPass
; CHECK-O2-SLP: Running pass: SLPVectorizerPass
; CHECK-O3-SLP: Running pass: SLPVectorizerPass
+; CHECK-O2-NOSLP-NOT: Running pass: SLPVectorizerPass
; CHECK-O0-LPV-NOT: = !{!"llvm.loop.isvectorized", i32 1}
; CHECK-O1-LPV-NOT: = !{!"llvm.loop.isvectorized", i32 1}
; CHECK-O2-LPV: = !{!"llvm.loop.isvectorized", i32 1}
More information about the cfe-commits
mailing list