Add -funique-source-file-identifier option.

This option complements -funique-source-file-names and allows the user
to use a different unique identifier than the source file path.

Reviewers: teresajohnson

Reviewed By: teresajohnson

Pull Request: https://github.com/llvm/llvm-project/pull/142901
This commit is contained in:
Peter Collingbourne 2025-06-05 10:52:01 -07:00 committed by GitHub
parent def37f7e3a
commit d1b0b4bb44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 60 additions and 28 deletions

View File

@ -2300,12 +2300,14 @@ are listed below.
.. 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
path. This is useful for reducing link times when doing ThinLTO
in combination with whole-program devirtualization or CFI.
passed to the linker has a unique identifier. The identifier for
an object file is either the source file path or the value of the
argument `-funique-source-file-identifier` if specified. This is
useful for reducing link times when doing ThinLTO in combination with
whole-program devirtualization or CFI.
The full source path passed to the compiler must be unique. This
means that, for example, the following is a usage error:
The full source path or identifier passed to the compiler must be
unique. This means that, for example, the following is a usage error:
.. code-block:: console
@ -2327,6 +2329,11 @@ are listed below.
A misuse of this flag may result in a duplicate symbol error at
link time.
.. option:: -funique-source-file-identifier=IDENTIFIER
Used with `-funique-source-file-names` to specify a source file
identifier.
.. option:: -fforce-emit-vtables
In order to improve devirtualization, forces emitting of vtables even in

View File

@ -278,8 +278,6 @@ 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.

View File

@ -338,6 +338,10 @@ public:
/// -fsymbol-partition (see https://lld.llvm.org/Partitions.html).
std::string SymbolPartition;
/// If non-empty, allow the compiler to assume that the given source file
/// identifier is unique at link time.
std::string UniqueSourceFileIdentifier;
enum RemarkKind {
RK_Missing, // Remark argument not present on the command line.
RK_Enabled, // Remark enabled via '-Rgroup'.

View File

@ -4204,13 +4204,15 @@ 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 funique_source_file_names: Flag<["-"], "funique-source-file-names">, Group<f_Group>,
HelpText<"Allow the compiler to assume that each translation unit has a unique "
"source file identifier (see -funique-source-file-identifier) at link time">;
def fno_unique_source_file_names: Flag<["-"], "fno-unique-source-file-names">;
def unique_source_file_identifier_EQ: Joined<["-"], "funique-source-file-identifier=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Specify the source file identifier for -funique-source-file-names; "
"uses the source file path if not specified">,
MarshallingInfoString<CodeGenOpts<"UniqueSourceFileIdentifier">>;
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">;

View File

@ -1146,8 +1146,13 @@ void CodeGenModule::Release() {
1);
}
if (CodeGenOpts.UniqueSourceFileNames) {
getModule().addModuleFlag(llvm::Module::Max, "Unique Source File Names", 1);
if (!CodeGenOpts.UniqueSourceFileIdentifier.empty()) {
getModule().addModuleFlag(
llvm::Module::Append, "Unique Source File Identifier",
llvm::MDTuple::get(
TheModule.getContext(),
llvm::MDString::get(TheModule.getContext(),
CodeGenOpts.UniqueSourceFileIdentifier)));
}
if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {

View File

@ -7740,8 +7740,14 @@ 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);
if (Args.hasFlag(options::OPT_funique_source_file_names,
options::OPT_fno_unique_source_file_names, false)) {
if (Arg *A = Args.getLastArg(options::OPT_unique_source_file_identifier_EQ))
A->render(Args, CmdArgs);
else
CmdArgs.push_back(Args.MakeArgString(
Twine("-funique-source-file-identifier=") + Input.getBaseInput()));
}
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);

View File

@ -1,2 +1,3 @@
// 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}
// RUN: %clang_cc1 -funique-source-file-identifier=foo -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
// CHECK: !{i32 5, !"Unique Source File Identifier", ![[MD:[0-9]*]]}
// CHECK: ![[MD]] = !{!"foo"}

View File

@ -1,5 +1,11 @@
// RUN: %clang -funique-source-file-names -### %s 2> %t
// RUN: FileCheck < %t %s
// RUN: FileCheck --check-prefix=SRC < %t %s
// CHECK: "-cc1"
// CHECK: "-funique-source-file-names"
// SRC: "-cc1"
// SRC: "-funique-source-file-identifier={{.*}}unique-source-file-names.c"
// RUN: %clang -funique-source-file-names -funique-source-file-identifier=foo -### %s 2> %t
// RUN: FileCheck --check-prefix=ID < %t %s
// ID: "-cc1"
// ID: "-funique-source-file-identifier=foo"

View File

@ -18,6 +18,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/xxhash.h"
@ -346,10 +347,11 @@ void llvm::filterDeadComdatFunctions(
std::string llvm::getUniqueModuleId(Module *M) {
MD5 Md5;
auto *UniqueSourceFileNames = mdconst::extract_or_null<ConstantInt>(
M->getModuleFlag("Unique Source File Names"));
if (UniqueSourceFileNames && UniqueSourceFileNames->getZExtValue()) {
Md5.update(M->getSourceFileName());
auto *UniqueSourceFileIdentifier = dyn_cast_or_null<MDNode>(
M->getModuleFlag("Unique Source File Identifier"));
if (UniqueSourceFileIdentifier) {
Md5.update(
cast<MDString>(UniqueSourceFileIdentifier->getOperand(0))->getString());
} else {
bool ExportsSymbols = false;
for (auto &GV : M->global_values()) {

View File

@ -19,4 +19,5 @@ define internal void @f() {
!0 = !{i32 0, !"typeid"}
!llvm.module.flags = !{!1}
!1 = !{i32 1, !"Unique Source File Names", i32 1}
!1 = !{i32 5, !"Unique Source File Identifier", !2}
!2 = !{!"unique-source-file-names.c"}