Skip to content

Conversation

lenary
Copy link
Member

@lenary lenary commented Oct 16, 2025

Before this change, -mno-outline and -moutline only controlled the
pass pipelines for the invoked compiler/linker.

The drawback of this implementation is that, when using LTO, only the
flag provided to the linker invocation is honoured (and any files which
individually use -mno-outline will have that flag ignored).

This change serialises the -mno-outline flag into each function's
IR/Bitcode, so that we can correctly disable outlining from functions in
files which disabled outlining, without affecting outlining choices for
functions from other files. This matches how other optimisation flags
are handled so the IR/Bitcode can be correctly merged during LTO.

Copy link
Member Author

lenary commented Oct 16, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@lenary lenary marked this pull request as ready for review October 16, 2025 04:04
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Oct 16, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2025

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Sam Elliott (lenary)

Changes

Before this change, -mno-outline and -moutline only controlled the
pass pipelines for the invoked compiler/linker.

The drawback of this implementation is that, when using LTO, only the
flag provided to the linker invocation is honoured (and any files which
individually use -mno-outline will have that flag ignored).

This change serialises the -mno-outline flag into each function's
IR/Bitcode, so that we can correctly disable outlining from functions in
files which disabled outlining, without affecting outlining choices for
functions from other files. This matches how other optimisation flags
are handled so the IR/Bitcode can be correctly merged during LTO.


Full diff: https://github.com/llvm/llvm-project/pull/163692.diff

9 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.def (+3)
  • (modified) clang/include/clang/Driver/Options.td (+7-10)
  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+3-1)
  • (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+7-4)
  • (modified) clang/test/CodeGen/attr-nooutline.c (+7-3)
  • (modified) clang/test/Driver/aarch64-outliner.c (+1-1)
  • (modified) clang/test/Driver/arm-machine-outliner.c (+1-1)
  • (modified) clang/test/Driver/riscv-outliner.c (+1-1)
  • (modified) clang/test/Driver/x86-outliner.c (+1-1)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 90e1f8d1eb5e9..4ccb75ebf904b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -489,6 +489,9 @@ CODEGENOPT(ResMayAlias, 1, 0, Benign)
 ENUM_CODEGENOPT(WinX64EHUnwindV2, WinX64EHUnwindV2Mode,
                 2, WinX64EHUnwindV2Mode::Disabled, Benign)
 
+/// Adds attributes that prevent outlining (`-mno-outline`)
+CODEGENOPT(DisableOutlining, 1, 0, Benign)
+
 /// FIXME: Make DebugOptions its own top-level .def file.
 #include "DebugOptions.def"
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d62b771f463ea..729be4f09c034 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5127,16 +5127,13 @@ def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">,
   MarshallingInfoFlag<LangOpts<"MSBitfields">>;
-def moutline
-    : Flag<["-"], "moutline">,
-      Group<f_clang_Group>,
-      Visibility<[ClangOption, CC1Option]>,
-      HelpText<"Enable function outlining (AArch64,Arm,RISC-V,X86 only)">;
-def mno_outline
-    : Flag<["-"], "mno-outline">,
-      Group<f_clang_Group>,
-      Visibility<[ClangOption, CC1Option]>,
-      HelpText<"Disable function outlining (AArch64,Arm,RISC-V,X86 only)">;
+defm outline
+    : BoolMOption<
+          "outline", CodeGenOpts<"DisableOutlining">, DefaultFalse,
+          NegFlag<SetTrue, [], [ClangOption, CC1Option],
+                  "Disable function outlining (AArch64,Arm,RISC-V,X86 only)">,
+          PosFlag<SetFalse, [], [ClangOption],
+                  "Enable function outlining (AArch64,Arm,RISC-V,X86 only)">>;
 def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
   HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">;
 def mskip_rax_setup : Flag<["-"], "mskip-rax-setup">, Group<m_Group>,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index ab267236ed579..ca3ef780d2853 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2820,7 +2820,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
       B.addAttribute(llvm::Attribute::MinSize);
   }
 
-  if (D->hasAttr<NoOutlineAttr>())
+  // Add `nooutline` if Outlining is disabled with a command-line flag or a
+  // function attribute.
+  if (CodeGenOpts.DisableOutlining || D->hasAttr<NoOutlineAttr>())
     B.addAttribute(llvm::Attribute::NoOutline);
 
   F->addFnAttrs(B);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 24b12fbf88f6f..a03b34ffb5d50 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -2923,13 +2923,16 @@ void tools::addMachineOutlinerArgs(const Driver &D,
             Triple.isRISCV() || Triple.isX86())) {
         D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName();
       } else {
-        // FIXME: This should probably use the `nooutline` attribute rather than
-        // tweaking Pipeline Pass flags, so `-mno-outline` and `-moutline`
-        // objects can be combined correctly during LTO.
+        // Enable Pass in pipeline
         addArg(Twine("-enable-machine-outliner"));
       }
     } else {
-      // Disable all outlining behaviour.
+      if (!IsLTO)
+        // Disable all outlining behaviour using `nooutline` option, in case
+        // Linker Invocation lacks `-mno-outline`.
+        CmdArgs.push_back("-mno-outline");
+
+      // Disable Pass in Pipeline
       addArg(Twine("-enable-machine-outliner=never"));
     }
   }
diff --git a/clang/test/CodeGen/attr-nooutline.c b/clang/test/CodeGen/attr-nooutline.c
index b9f175da24cb5..ed3565b7f1166 100644
--- a/clang/test/CodeGen/attr-nooutline.c
+++ b/clang/test/CodeGen/attr-nooutline.c
@@ -1,6 +1,7 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --version 6
-// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-unknown-linux-gnu -disable-O0-optnone -o - | FileCheck %s
-
+// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-unknown-linux-gnu -disable-O0-optnone -DATTR -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-unknown-linux-gnu -disable-O0-optnone -mno-outline -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-unknown-linux-gnu -disable-O0-optnone -mno-outline -DATTR -o - | FileCheck %s
 
 // CHECK: Function Attrs: noinline nooutline nounwind
 // CHECK-LABEL: define dso_local i32 @t1(
@@ -11,6 +12,9 @@
 // CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
 // CHECK-NEXT:    ret i32 [[TMP0]]
 //
-[[clang::nooutline]] int t1(int x) {
+#ifdef ATTR
+[[clang::nooutline]]
+#endif
+int t1(int x) {
   return x;
 }
diff --git a/clang/test/Driver/aarch64-outliner.c b/clang/test/Driver/aarch64-outliner.c
index 5ed822f122fc4..4d5b7321e330f 100644
--- a/clang/test/Driver/aarch64-outliner.c
+++ b/clang/test/Driver/aarch64-outliner.c
@@ -3,4 +3,4 @@
 // ON: "-mllvm" "-enable-machine-outliner"
 // RUN: %clang --target=aarch64 -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
 // RUN: %clang --target=aarch64_be -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
-// OFF: "-mllvm" "-enable-machine-outliner=never"
+// OFF: "-mno-outline" "-mllvm" "-enable-machine-outliner=never"
diff --git a/clang/test/Driver/arm-machine-outliner.c b/clang/test/Driver/arm-machine-outliner.c
index a1e705cb60a1b..efa29d2ab8450 100644
--- a/clang/test/Driver/arm-machine-outliner.c
+++ b/clang/test/Driver/arm-machine-outliner.c
@@ -3,6 +3,6 @@
 // RUN: %clang -target armv7-linux-gnueabihf -flto -moutline %s -### 2>&1 | FileCheck %s -check-prefix=ON-LTO
 // ON-LTO: "-plugin-opt=-enable-machine-outliner"
 // RUN: %clang -target armv7-linux-gnueabihf -moutline -mno-outline -c %s -### 2>&1 | FileCheck %s -check-prefix=OFF
-// OFF: "-mllvm" "-enable-machine-outliner=never"
+// OFF: "-mno-outline" "-mllvm" "-enable-machine-outliner=never"
 // RUN: %clang -target armv7-linux-gnueabihf -flto -moutline -mno-outline %s -### 2>&1 | FileCheck %s -check-prefix=OFF-LTO
 // OFF-LTO: "-plugin-opt=-enable-machine-outliner=never"
diff --git a/clang/test/Driver/riscv-outliner.c b/clang/test/Driver/riscv-outliner.c
index 9e9905ab4fd8a..fa69977331e13 100644
--- a/clang/test/Driver/riscv-outliner.c
+++ b/clang/test/Driver/riscv-outliner.c
@@ -4,4 +4,4 @@
 
 // RUN: %clang --target=riscv32 -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
 // RUN: %clang --target=riscv64 -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
-// OFF: "-mllvm" "-enable-machine-outliner=never"
+// OFF: "-mno-outline" "-mllvm" "-enable-machine-outliner=never"
diff --git a/clang/test/Driver/x86-outliner.c b/clang/test/Driver/x86-outliner.c
index e2af85d3d16ab..7da56ac93fa5e 100644
--- a/clang/test/Driver/x86-outliner.c
+++ b/clang/test/Driver/x86-outliner.c
@@ -4,4 +4,4 @@
 
 // RUN: %clang --target=i386 -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
 // RUN: %clang --target=x86_64 -moutline -mno-outline -S %s -### 2>&1 | FileCheck %s -check-prefix=OFF
-// OFF: "-mllvm" "-enable-machine-outliner=never"
+// OFF: "-mno-outline" "-mllvm" "-enable-machine-outliner=never"

@lenary lenary force-pushed the users/lenary/clangensure-mno-outlineaddsattributes branch from 6a3c5d9 to be8091b Compare October 16, 2025 20:43
Before this change, `-mno-outline` and `-moutline` only controlled the
pass pipelines for the invoked compiler/linker.

The drawback of this implementation is that, when using LTO, only the
flag provided to the linker invocation is honoured (and any files which
individually use `-mno-outline` will have that flag ignored).

This change serialises the `-mno-outline` flag into each function's
IR/Bitcode, so that we can correctly disable outlining from functions in
files which disabled outlining, without affecting outlining choices for
functions from other files. This matches how other optimisation flags
are handled so the IR/Bitcode can be correctly merged during LTO.
@lenary lenary force-pushed the users/lenary/clang-add-nooutline-attr branch from 358b089 to a729b26 Compare October 16, 2025 20:51
@lenary lenary force-pushed the users/lenary/clangensure-mno-outlineaddsattributes branch from be8091b to 446d63f Compare October 16, 2025 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants