[clang] a5aa0c4 - Introduce -funique-source-file-names flag.
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 15 11:12:08 PDT 2025
Author: Peter Collingbourne
Date: 2025-04-15T11:12:05-07:00
New Revision: a5aa0c46c3274eaf25dde4d792a1abd6191cccf9
URL: https://github.com/llvm/llvm-project/commit/a5aa0c46c3274eaf25dde4d792a1abd6191cccf9
DIFF: https://github.com/llvm/llvm-project/commit/a5aa0c46c3274eaf25dde4d792a1abd6191cccf9.diff
LOG: Introduce -funique-source-file-names flag.
The purpose of this flag is to allow the compiler to assume that each
object file passed to the linker has been compiled using a unique
source file name. This is useful for reducing link times when doing
ThinLTO in combination with whole-program devirtualization or CFI,
as it allows modules without exported symbols to be built with ThinLTO.
Reviewers: vitalybuka, teresajohnson
Reviewed By: teresajohnson
Pull Request: https://github.com/llvm/llvm-project/pull/135728
Added:
clang/test/CodeGen/unique-source-file-names.c
clang/test/Driver/unique-source-file-names.c
llvm/test/Transforms/ThinLTOBitcodeWriter/unique-source-file-names.ll
Modified:
clang/docs/ControlFlowIntegrity.rst
clang/docs/UsersManual.rst
clang/include/clang/Basic/CodeGenOptions.def
clang/include/clang/Driver/Options.td
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/Driver/ToolChains/Clang.cpp
llvm/lib/Transforms/Utils/ModuleUtils.cpp
Removed:
################################################################################
diff --git a/clang/docs/ControlFlowIntegrity.rst b/clang/docs/ControlFlowIntegrity.rst
index 2f2f8ccf4481b..baff9ab54ff26 100644
--- a/clang/docs/ControlFlowIntegrity.rst
+++ b/clang/docs/ControlFlowIntegrity.rst
@@ -42,6 +42,11 @@ default visibility setting is ``-fvisibility=default``, which would disable
CFI checks for classes without visibility attributes. Most users will want
to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
+When using ``-fsanitize=cfi*`` with ``-flto=thin``, it is recommended
+to reduce link times by passing `-funique-source-file-names
+<UsersManual.html#cmdoption-f-no-unique-source-file-names>`_, provided
+that your program is compatible with it.
+
Experimental support for :ref:`cross-DSO control flow integrity
<cfi-cross-dso>` exists that does not require classes to have hidden LTO
visibility. This cross-DSO support has unstable ABI at this time.
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 2a93c2552d7dc..d4656a7e63c99 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2297,6 +2297,16 @@ are listed below.
pure ThinLTO, as all split regular LTO modules are merged and LTO linked
with regular LTO.
+.. option:: -f[no-]unique-source-file-names
+
+ When enabled, allows the compiler to assume that each object file
+ passed to the linker has been compiled using a unique source file
+ name. This is useful for reducing link times when doing ThinLTO
+ in combination with whole-program devirtualization or CFI.
+
+ A misuse of this flag will generally result in a duplicate symbol
+ error at link time.
+
.. option:: -fforce-emit-vtables
In order to improve devirtualization, forces emitting of vtables even in
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a436c0ec98d5b..c5990fb248689 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -278,6 +278,8 @@ CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types
///< CFI icall function signatures
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
///< instead of creating a local jump table.
+CODEGENOPT(UniqueSourceFileNames, 1, 0) ///< Allow the compiler to assume that TUs
+ ///< have unique source file names at link time
CODEGENOPT(SanitizeKcfiArity, 1, 0) ///< Embed arity in KCFI patchable function prefix
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
///< instrumentation.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index c9d2bc5e81976..e9acb20348654 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4140,6 +4140,13 @@ def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,
HelpText<"Do not process trigraph sequences">,
Visibility<[ClangOption, CC1Option]>;
+defm unique_source_file_names: BoolOption<"f", "unique-source-file-names",
+ CodeGenOpts<"UniqueSourceFileNames">, DefaultFalse,
+ PosFlag<SetTrue, [], [CC1Option], "Allow">,
+ NegFlag<SetFalse, [], [], "Do not allow">,
+ BothFlags<[], [ClangOption], " the compiler to assume that each translation unit has a unique "
+ "source file name at link time">>,
+ Group<f_clang_Group>;
def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 4a48c2f35ff23..26e09fe239242 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1144,6 +1144,10 @@ void CodeGenModule::Release() {
1);
}
+ if (CodeGenOpts.UniqueSourceFileNames) {
+ getModule().addModuleFlag(llvm::Module::Max, "Unique Source File Names", 1);
+ }
+
if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
// KCFI assumes patchable-function-prefix is the same for all indirectly
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 65910e7fdaaa6..8506a5c00e7bc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7744,6 +7744,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.addOptInFlag(CmdArgs, options::OPT_fexperimental_late_parse_attributes,
options::OPT_fno_experimental_late_parse_attributes);
+ Args.addOptInFlag(CmdArgs, options::OPT_funique_source_file_names,
+ options::OPT_fno_unique_source_file_names);
+
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty()) {
diff --git a/clang/test/CodeGen/unique-source-file-names.c b/clang/test/CodeGen/unique-source-file-names.c
new file mode 100644
index 0000000000000..1d5a4a5e8e4c5
--- /dev/null
+++ b/clang/test/CodeGen/unique-source-file-names.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -funique-source-file-names -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// CHECK: !{i32 7, !"Unique Source File Names", i32 1}
diff --git a/clang/test/Driver/unique-source-file-names.c b/clang/test/Driver/unique-source-file-names.c
new file mode 100644
index 0000000000000..8322f0e37b0c7
--- /dev/null
+++ b/clang/test/Driver/unique-source-file-names.c
@@ -0,0 +1,5 @@
+// RUN: %clang -funique-source-file-names -### %s 2> %t
+// RUN: FileCheck < %t %s
+
+// CHECK: "-cc1"
+// CHECK: "-funique-source-file-names"
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index 1c31e851ef4b2..10efdd61d4553 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -345,27 +345,25 @@ void llvm::filterDeadComdatFunctions(
std::string llvm::getUniqueModuleId(Module *M) {
MD5 Md5;
- bool ExportsSymbols = false;
- auto AddGlobal = [&](GlobalValue &GV) {
- if (GV.isDeclaration() || GV.getName().starts_with("llvm.") ||
- !GV.hasExternalLinkage() || GV.hasComdat())
- return;
- ExportsSymbols = true;
- Md5.update(GV.getName());
- Md5.update(ArrayRef<uint8_t>{0});
- };
-
- for (auto &F : *M)
- AddGlobal(F);
- for (auto &GV : M->globals())
- AddGlobal(GV);
- for (auto &GA : M->aliases())
- AddGlobal(GA);
- for (auto &IF : M->ifuncs())
- AddGlobal(IF);
-
- if (!ExportsSymbols)
- return "";
+
+ auto *UniqueSourceFileNames = mdconst::extract_or_null<ConstantInt>(
+ M->getModuleFlag("Unique Source File Names"));
+ if (UniqueSourceFileNames && UniqueSourceFileNames->getZExtValue()) {
+ Md5.update(M->getSourceFileName());
+ } else {
+ bool ExportsSymbols = false;
+ for (auto &GV : M->global_values()) {
+ if (GV.isDeclaration() || GV.getName().starts_with("llvm.") ||
+ !GV.hasExternalLinkage() || GV.hasComdat())
+ continue;
+ ExportsSymbols = true;
+ Md5.update(GV.getName());
+ Md5.update(ArrayRef<uint8_t>{0});
+ }
+
+ if (!ExportsSymbols)
+ return "";
+ }
MD5::MD5Result R;
Md5.final(R);
diff --git a/llvm/test/Transforms/ThinLTOBitcodeWriter/unique-source-file-names.ll b/llvm/test/Transforms/ThinLTOBitcodeWriter/unique-source-file-names.ll
new file mode 100644
index 0000000000000..0f3fd566f9b1c
--- /dev/null
+++ b/llvm/test/Transforms/ThinLTOBitcodeWriter/unique-source-file-names.ll
@@ -0,0 +1,22 @@
+; RUN: opt -thinlto-bc -thin-link-bitcode-file=%t2 -thinlto-split-lto-unit -o %t %s
+; RUN: llvm-modextract -b -n 1 -o %t1 %t
+; RUN: llvm-dis -o - %t1 | FileCheck %s
+
+source_filename = "unique-source-file-names.c"
+
+ at llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @f, ptr null }]
+
+; CHECK: @g.45934e8a5251fb7adbecfff71a4e70ed =
+ at g = internal global i8 42, !type !0
+
+declare void @sink(ptr)
+
+define internal void @f() {
+ call void @sink(ptr @g)
+ ret void
+}
+
+!0 = !{i32 0, !"typeid"}
+
+!llvm.module.flags = !{!1}
+!1 = !{i32 1, !"Unique Source File Names", i32 1}
More information about the cfe-commits
mailing list