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 <[email protected]>
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}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to