From d3e6ce051a1e6dadf93f89a08d9135bb1366636c Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 3 Jun 2025 22:01:37 +0100 Subject: [PATCH 01/18] [DTLTO][LLD][ELF] Add support for Integrated Distributed ThinLTO This patch introduces support for Integrated Distributed ThinLTO (DTLTO) in ELF LLD. DTLTO enables the distribution of ThinLTO backend compilations via external distribution systems, such as Incredibuild, during the traditional link step: https://llvm.org/docs/DTLTO.html. It is expected that users will invoke DTLTO through the compiler driver (e.g., Clang) rather than calling LLD directly. A Clang-side interface for DTLTO will be added in a follow-up patch. Note: Bitcode members of non-thin archives are not currently supported. This will be addressed in a future change. Testing: - ELF LLD `lit` test coverage has been added, using a mock distributor to avoid requiring Clang. - Cross-project `lit` tests cover integration with Clang. For the design discussion of the DTLTO feature, see: https://github.com/llvm/llvm-project/issues/126654 --- cross-project-tests/CMakeLists.txt | 12 ++- cross-project-tests/dtlto/README.md | 3 + cross-project-tests/dtlto/archive-thin.test | 65 ++++++++++++++++ cross-project-tests/dtlto/dtlto.c | 35 +++++++++ cross-project-tests/dtlto/lit.local.cfg | 2 + cross-project-tests/lit.cfg.py | 4 +- lld/ELF/Config.h | 4 + lld/ELF/Driver.cpp | 5 ++ lld/ELF/InputFiles.cpp | 39 +++++++++- lld/ELF/LTO.cpp | 7 ++ lld/ELF/Options.td | 12 ++- lld/docs/DTLTO.rst | 42 +++++++++++ lld/docs/index.rst | 1 + lld/test/ELF/dtlto/archive-thin.test | 82 +++++++++++++++++++++ lld/test/ELF/dtlto/empty.test | 44 +++++++++++ lld/test/ELF/dtlto/imports.test | 53 +++++++++++++ lld/test/ELF/dtlto/index.test | 44 +++++++++++ lld/test/ELF/dtlto/options.test | 41 +++++++++++ lld/test/ELF/dtlto/partitions.test | 61 +++++++++++++++ lld/test/ELF/dtlto/save-temps.test | 39 ++++++++++ lld/test/lit.cfg.py | 1 + 21 files changed, 588 insertions(+), 8 deletions(-) create mode 100644 cross-project-tests/dtlto/README.md create mode 100644 cross-project-tests/dtlto/archive-thin.test create mode 100644 cross-project-tests/dtlto/dtlto.c create mode 100644 cross-project-tests/dtlto/lit.local.cfg create mode 100644 lld/docs/DTLTO.rst create mode 100644 lld/test/ELF/dtlto/archive-thin.test create mode 100644 lld/test/ELF/dtlto/empty.test create mode 100644 lld/test/ELF/dtlto/imports.test create mode 100644 lld/test/ELF/dtlto/index.test create mode 100644 lld/test/ELF/dtlto/options.test create mode 100644 lld/test/ELF/dtlto/partitions.test create mode 100644 lld/test/ELF/dtlto/save-temps.test diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt index 7f2fee48fda77..192db87043177 100644 --- a/cross-project-tests/CMakeLists.txt +++ b/cross-project-tests/CMakeLists.txt @@ -19,11 +19,12 @@ set(CROSS_PROJECT_TEST_DEPS FileCheck check-gdb-llvm-support count - llvm-dwarfdump + llvm-ar llvm-config + llvm-dwarfdump llvm-objdump - split-file not + split-file ) if ("clang" IN_LIST LLVM_ENABLE_PROJECTS) @@ -94,6 +95,13 @@ add_lit_testsuite(check-cross-amdgpu "Running AMDGPU cross-project tests" DEPENDS clang ) +# DTLTO tests. +add_lit_testsuite(check-cross-dtlto "Running DTLTO cross-project tests" + ${CMAKE_CURRENT_BINARY_DIR}/dtlto + EXCLUDE_FROM_CHECK_ALL + DEPENDS ${CROSS_PROJECT_TEST_DEPS} + ) + # Add check-cross-project-* targets. add_lit_testsuites(CROSS_PROJECT ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CROSS_PROJECT_TEST_DEPS} diff --git a/cross-project-tests/dtlto/README.md b/cross-project-tests/dtlto/README.md new file mode 100644 index 0000000000000..12f9aa19b0d9b --- /dev/null +++ b/cross-project-tests/dtlto/README.md @@ -0,0 +1,3 @@ +Tests for DTLTO (Integrated Distributed ThinLTO) functionality. + +These are integration tests as DTLTO invokes `clang` for code-generation. \ No newline at end of file diff --git a/cross-project-tests/dtlto/archive-thin.test b/cross-project-tests/dtlto/archive-thin.test new file mode 100644 index 0000000000000..2d6b7f1cb7e37 --- /dev/null +++ b/cross-project-tests/dtlto/archive-thin.test @@ -0,0 +1,65 @@ +# REQUIRES: x86-registered-target,ld.lld,llvm-ar + +# Test that a DTLTO link succeeds and outputs the expected set of files +# correctly when thin archives are present. + +RUN: rm -rf %t && split-file %s %t && cd %t +RUN: %clang --target=x86_64-linux-gnu -flto=thin -c \ +RUN: foo.c bar.c dog.c cat.c _start.c + +RUN: llvm-ar rcs foo.a foo.o --thin +# Create this bitcode thin archive in a subdirectory to test the expansion of +# the path to a bitcode file that is referenced using "..", e.g., in this case +# "../bar.o". +RUN: mkdir lib +RUN: llvm-ar rcs lib/bar.a bar.o --thin +# Create this bitcode thin archive with an absolute path entry containing "..". +RUN: llvm-ar rcs dog.a %t/lib/../dog.o --thin +RUN: llvm-ar rcs cat.a cat.o --thin +RUN: llvm-ar rcs _start.a _start.o --thin + +RUN: mkdir %t/out && cd %t/out + +RUN: ld.lld %t/foo.a %t/lib/bar.a ../_start.a %t/cat.a \ +RUN: --whole-archive ../dog.a \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/local.py \ +RUN: --thinlto-remote-compiler=%clang \ +RUN: --save-temps + +# Check that the required output files have been created. +RUN: ls | FileCheck %s --check-prefix=OUTPUTS \ +RUN: --implicit-check-not=cat --implicit-check-not=foo + +# JSON jobs description. +OUTPUTS-DAG: a.[[PID:[a-zA-Z0-9_]+]].dist-file.json + +# Individual summary index files. +OUTPUTS-DAG: dog.1.[[PID]].native.o.thinlto.bc{{$}} +OUTPUTS-DAG: _start.2.[[PID]].native.o.thinlto.bc{{$}} +OUTPUTS-DAG: bar.3.[[PID]].native.o.thinlto.bc{{$}} + +# Native output object files. +OUTPUTS-DAG: dog.1.[[PID]].native.o{{$}} +OUTPUTS-DAG: _start.2.[[PID]].native.o{{$}} +OUTPUTS-DAG: bar.3.[[PID]].native.o{{$}} + +#--- foo.c +__attribute__((retain)) void foo() {} + +#--- bar.c +extern void foo(); +__attribute__((retain)) void bar() { foo(); } + +#--- dog.c +__attribute__((retain)) void dog() {} + +#--- cat.c +__attribute__((retain)) void cat() {} + +#--- _start.c +extern void bar(); +__attribute__((retain)) void _start() { + bar(); +} + diff --git a/cross-project-tests/dtlto/dtlto.c b/cross-project-tests/dtlto/dtlto.c new file mode 100644 index 0000000000000..e967ede35b09b --- /dev/null +++ b/cross-project-tests/dtlto/dtlto.c @@ -0,0 +1,35 @@ +// REQUIRES: x86-registered-target,ld.lld + +/// Simple test that DTLTO works with a single input bitcode file and that +/// --save-temps can be applied to the remote compilation. +// RUN: rm -rf %t && mkdir %t && cd %t + +// RUN: %clang --target=x86_64-linux-gnu -c -flto=thin %s + +// RUN: ld.lld dtlto.o \ +// RUN: --thinlto-distributor=%python \ +// RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/local.py \ +// RUN: --thinlto-remote-compiler=%clang \ +// RUN: --thinlto-remote-compiler-arg=--save-temps + +/// Check that the required output files have been created. +// RUN: ls | count 10 +// RUN: ls | FileCheck %s + +/// Produced by the bitcode compilation. +// CHECK-DAG: {{^}}dtlto.o{{$}} + +/// Linked ELF. +// CHECK-DAG: {{^}}a.out{{$}} + +/// --save-temps output for the backend compilation. +// CHECK-DAG: {{^}}dtlto.s{{$}} +// CHECK-DAG: {{^}}dtlto.s.0.preopt.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.1.promote.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.2.internalize.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.3.import.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.4.opt.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.5.precodegen.bc{{$}} +// CHECK-DAG: {{^}}dtlto.s.resolution.txt{{$}} + +int _start() { return 0; } diff --git a/cross-project-tests/dtlto/lit.local.cfg b/cross-project-tests/dtlto/lit.local.cfg new file mode 100644 index 0000000000000..530f4c01646ff --- /dev/null +++ b/cross-project-tests/dtlto/lit.local.cfg @@ -0,0 +1,2 @@ +if "clang" not in config.available_features: + config.unsupported = True diff --git a/cross-project-tests/lit.cfg.py b/cross-project-tests/lit.cfg.py index b35c643ac898c..ac27753472646 100644 --- a/cross-project-tests/lit.cfg.py +++ b/cross-project-tests/lit.cfg.py @@ -19,7 +19,7 @@ config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. -config.suffixes = [".c", ".cl", ".cpp", ".m"] +config.suffixes = [".c", ".cl", ".cpp", ".m", ".test"] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent @@ -107,6 +107,8 @@ def get_required_attr(config, attr_name): if lldb_path is not None: config.available_features.add("lldb") +if llvm_config.use_llvm_tool("llvm-ar"): + config.available_features.add("llvm-ar") def configure_dexter_substitutions(): """Configure substitutions for host platform and return list of dependencies""" diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 2b72d54ba410d..f40be136a8664 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -275,6 +275,10 @@ struct Config { llvm::SmallVector searchPaths; llvm::SmallVector symbolOrderingFile; llvm::SmallVector thinLTOModulesToCompile; + llvm::StringRef dtltoDistributor; + llvm::SmallVector dtltoDistributorArgs; + llvm::StringRef dtltoCompiler; + llvm::SmallVector dtltoCompilerArgs; llvm::SmallVector undefined; llvm::SmallVector dynamicList; llvm::SmallVector buildIdVector; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 7e132a387a04d..676d984fa2fcf 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1396,6 +1396,11 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); ctx.arg.disableVerify = args.hasArg(OPT_disable_verify); ctx.arg.discard = getDiscard(args); + ctx.arg.dtltoDistributor = args.getLastArgValue(OPT_thinlto_distributor_eq); + ctx.arg.dtltoDistributorArgs = + args::getStrings(args, OPT_thinlto_distributor_arg); + ctx.arg.dtltoCompiler = args.getLastArgValue(OPT_thinlto_compiler_eq); + ctx.arg.dtltoCompilerArgs = args::getStrings(args, OPT_thinlto_compiler_arg); ctx.arg.dwoDir = args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); ctx.arg.dynamicLinker = getDynamicLinker(ctx, args); ctx.arg.ehFrameHdr = diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 71e72e7184b9f..3358e8bc38cbd 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTO.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" @@ -1753,6 +1754,33 @@ static uint8_t getOsAbi(const Triple &t) { } } +// For DTLTO, bitcode member names must be valid paths to files on disk. +// For thin archives, resolve `memberPath` relative to the archive's location. +// Returns true if adjusted; false otherwise. Non-thin archives are unsupported. +static bool dtltoAdjustMemberPathIfThinArchive(Ctx &ctx, StringRef archivePath, + std::string &memberPath) { + assert(!archivePath.empty() && !ctx.arg.dtltoDistributor.empty()); + + // Check if the archive file is a thin archive by reading its header. + auto bufferOrErr = + MemoryBuffer::getFileSlice(archivePath, sizeof(ThinArchiveMagic) - 1, 0); + if (std::error_code ec = bufferOrErr.getError()) { + ErrAlways(ctx) << "cannot open " << archivePath << ": " << ec.message(); + return false; + } + + if (!bufferOrErr->get()->getBuffer().starts_with(ThinArchiveMagic)) + return false; + + SmallString<64> resolvedPath; + if (path::is_relative(memberPath)) { + resolvedPath = path::parent_path(archivePath); + path::append(resolvedPath, memberPath); + memberPath = resolvedPath.str(); + } + return true; +} + BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName, uint64_t offsetInArchive, bool lazy) : InputFile(ctx, BitcodeKind, mb) { @@ -1770,10 +1798,13 @@ BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName, // symbols later in the link stage). So we append file offset to make // filename unique. StringSaver &ss = ctx.saver; - StringRef name = archiveName.empty() - ? ss.save(path) - : ss.save(archiveName + "(" + path::filename(path) + - " at " + utostr(offsetInArchive) + ")"); + StringRef name = + (archiveName.empty() || + (!ctx.arg.dtltoDistributor.empty() && + dtltoAdjustMemberPathIfThinArchive(ctx, archiveName, path))) + ? ss.save(path) + : ss.save(archiveName + "(" + path::filename(path) + " at " + + utostr(offsetInArchive) + ")"); MemoryBufferRef mbref(mb.getBuffer(), name); obj = CHECK2(lto::InputFile::create(mbref), this); diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 82a7463446a94..8d4a6c9e3a81e 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -180,6 +180,13 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) { std::string(ctx.arg.thinLTOPrefixReplaceNew), std::string(ctx.arg.thinLTOPrefixReplaceNativeObject), ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite); + } else if (!ctx.arg.dtltoDistributor.empty()) { + backend = lto::createOutOfProcessThinBackend( + llvm::hardware_concurrency(ctx.arg.thinLTOJobs), onIndexWrite, + ctx.arg.thinLTOEmitIndexFiles, ctx.arg.thinLTOEmitImportsFiles, + ctx.arg.outputFile, ctx.arg.dtltoDistributor, + ctx.arg.dtltoDistributorArgs, ctx.arg.dtltoCompiler, + ctx.arg.dtltoCompilerArgs, !ctx.arg.saveTempsArgs.empty()); } else { backend = lto::createInProcessThinBackend( llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs), diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index c795147eb9662..6599691244fe8 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -710,7 +710,17 @@ def thinlto_object_suffix_replace_eq: JJ<"thinlto-object-suffix-replace=">; def thinlto_prefix_replace_eq: JJ<"thinlto-prefix-replace=">; def thinlto_single_module_eq: JJ<"thinlto-single-module=">, HelpText<"Specify a single module to compile in ThinLTO mode, for debugging only">; - +def thinlto_distributor_eq: JJ<"thinlto-distributor=">, + HelpText<"Distributor to use for ThinLTO backend compilations. If specified, " + "ThinLTO backend compilations will be distributed.">; +defm thinlto_distributor_arg: EEq<"thinlto-distributor-arg", "Arguments to " + "pass to the ThinLTO distributor">; +def thinlto_compiler_eq: JJ<"thinlto-remote-compiler=">, + HelpText<"Compiler for the ThinLTO distributor to invoke for ThinLTO backend " + "compilations">; +defm thinlto_compiler_arg: EEq<"thinlto-remote-compiler-arg", "Compiler " + "arguments for the ThinLTO distributor to pass for ThinLTO backend " + "compilations">; defm fat_lto_objects: BB<"fat-lto-objects", "Use the .llvm.lto section, which contains LLVM bitcode, in fat LTO object files to perform LTO.", "Ignore the .llvm.lto section in relocatable object files (default).">; diff --git a/lld/docs/DTLTO.rst b/lld/docs/DTLTO.rst new file mode 100644 index 0000000000000..985decf6c7db8 --- /dev/null +++ b/lld/docs/DTLTO.rst @@ -0,0 +1,42 @@ +Integrated Distributed ThinLTO (DTLTO) +====================================== + +Integrated Distributed ThinLTO (DTLTO) enables the distribution of backend +ThinLTO compilations via external distribution systems, such as Incredibuild, +during the traditional link step. + +The implementation is documented here: https://llvm.org/docs/DTLTO.html. + +Currently, DTLTO is only supported in ELF LLD. Support will be added to other +LLD flavours in the future. + +ELF LLD +------- + +The command-line interface is as follows: + +- ``--thinlto-distributor=`` + Specifies the file to execute as the distributor process. If specified, + ThinLTO backend compilations will be distributed. + +- ``--thinlto-remote-compiler=`` + Specifies the path to the compiler that the distributor process will use for + backend compilations. The compiler invoked must match the version of LLD. + +- ``--thinlto-distributor-arg=`` + Specifies ```` on the command line when invoking the distributor. + Can be specified multiple times. + +- ``--thinlto-remote-compiler-arg=`` + Appends ```` to the remote compiler's command line. + Can be specified multiple times. + + Options that introduce extra input/output files may cause miscompilation if + the distribution system does not automatically handle pushing/fetching them to + remote nodes. In such cases, configure the distributor - possibly using + ``--thinlto-distributor-arg=`` - to manage these dependencies. See the + distributor documentation for details. + +Some LLD LTO options (e.g., ``--lto-sample-profile=``) are supported. +Currently, other options are silently accepted but do not have the intended +effect. Support for such options will be expanded in the future. diff --git a/lld/docs/index.rst b/lld/docs/index.rst index 8260461c36905..69792e3b575be 100644 --- a/lld/docs/index.rst +++ b/lld/docs/index.rst @@ -147,3 +147,4 @@ document soon. ELF/start-stop-gc ELF/warn_backrefs MachO/index + DTLTO diff --git a/lld/test/ELF/dtlto/archive-thin.test b/lld/test/ELF/dtlto/archive-thin.test new file mode 100644 index 0000000000000..45f841be3fcf6 --- /dev/null +++ b/lld/test/ELF/dtlto/archive-thin.test @@ -0,0 +1,82 @@ +# REQUIRES: x86 + +# Test that a DTLTO link succeeds and outputs the expected set of files +# correctly when thin archives are present. + +RUN: rm -rf %t && split-file %s %t && cd %t + +# Generate ThinLTO bitcode files. +RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 +RUN: opt -thinlto-bc t2.ll -o t2.bc -O2 +RUN: opt -thinlto-bc t3.ll -o t3.bc -O2 + +# Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic +RUN: llc t2.ll --filetype=obj -o t2.o --relocation-model=pic +RUN: llc t3.ll --filetype=obj -o t3.o --relocation-model=pic + +RUN: llvm-ar rcs t1.a t1.bc --thin +# Create this bitcode thin archive in a subdirectory to test the expansion of +# the path to a bitcode file that is referenced using "..", e.g., in this case +# "../t2.bc". +RUN: mkdir lib +RUN: llvm-ar rcs lib/t2.a t2.bc --thin +# Create this bitcode thin archive with an absolute path entry containing "..". +RUN: llvm-ar rcs t3.a %t/lib/../t3.bc --thin +RUN: llvm-ar rcs t4.a t1.bc --thin + +RUN: mkdir %t/out && cd %t/out + +# Note that mock.py does not do any compilation, instead it simply writes the +# contents of the object files supplied on the command line into the output +# object files in job order. +RUN: ld.lld --whole-archive %t/t1.a %t/lib/t2.a ../t3.a \ +RUN: --no-whole-archive %t/t4.a \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=../t1.o \ +RUN: --thinlto-distributor-arg=../t2.o \ +RUN: --thinlto-distributor-arg=../t3.o \ +RUN: --save-temps + +RUN: ls | FileCheck %s --implicit-check-not=4 + +# JSON jobs description. +CHECK-DAG: a.{{[0-9]+}}.dist-file.json + +# Individual summary index files. +CHECK-DAG: t1.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} +CHECK-DAG: t2.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} +CHECK-DAG: t3.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} + +# Native output object files. +CHECK-DAG: t1.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} +CHECK-DAG: t2.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} +CHECK-DAG: t3.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { +entry: + ret void +} + +#--- t2.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t2() { +entry: + ret void +} + +#--- t3.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t3() { +entry: + ret void +} diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test new file mode 100644 index 0000000000000..5f69d90051220 --- /dev/null +++ b/lld/test/ELF/dtlto/empty.test @@ -0,0 +1,44 @@ +# REQUIRES: x86 + +# Test that DTLTO options are a no-op if no thinLTO is performed. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: opt t1.ll -o t1.o -O2 +RUN: opt t2.ll -o t2.o -O2 + +# Common command-line arguments. Note that mock.py does not do any compilation; +# instead, it simply writes the contents of the object files supplied on the +# command line into the output object files in job order. +RUN: echo "t1.o t2.o \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=no-exist1.o \ +RUN: --thinlto-distributor-arg=no-exist2.o" > l.rsp + +# Check linking succeeds when all input files are Full LTO. +RUN: ld.lld @l.rsp + +RUN: llc -filetype=obj t1.ll -o t1.o +RUN: llc -filetype=obj t2.ll -o t2.o + +# Check linking succeeds when all input files are ET_RELs. +RUN: ld.lld @l.rsp + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { +entry: + ret void +} + +#--- t2.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t2() { +entry: + ret void +} diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test new file mode 100644 index 0000000000000..74d5223f04e24 --- /dev/null +++ b/lld/test/ELF/dtlto/imports.test @@ -0,0 +1,53 @@ +# REQUIRES: x86 + +# Check that DTLTO creates imports lists if requested. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 +RUN: opt -thinlto-bc t2.ll -o t2.bc -O2 + +# Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic +RUN: llc t2.ll --filetype=obj -o t2.o --relocation-model=pic + +# Common command-line arguments. Note that mock.py does not do any compilation; +# instead, it simply writes the contents of the object files supplied on the +# command line into the output object files in job order. +RUN: echo "t1.bc t2.bc \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=t1.o \ +RUN: --thinlto-distributor-arg=t2.o" > l.rsp + +# Check that imports files are not created normally. +RUN: ld.lld @l.rsp +RUN: ls | FileCheck %s --check-prefix=NOIMPORTSFILES +NOIMPORTSFILES-NOT: .imports + +# Check that imports files are created with --thinlto-emit-imports-files. +RUN: ld.lld @l.rsp --thinlto-emit-imports-files +RUN: ls | FileCheck %s --check-prefix=IMPORTSFILES +IMPORTSFILES: t1.bc.imports +IMPORTSFILES: t2.bc.imports + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { +entry: + ret void +} + +#--- t2.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @t1(...) + +define void @t2() { +entry: + call void (...) @t1() + ret void +} diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test new file mode 100644 index 0000000000000..4a869c65468fe --- /dev/null +++ b/lld/test/ELF/dtlto/index.test @@ -0,0 +1,44 @@ +# REQUIRES: x86 + +# Check that DTLTO creates individual summary index files if requested. + +RUN: rm -rf %t && split-file %s %t && cd %t + +# Generate ThinLTO bitcode files. +RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 +RUN: opt -thinlto-bc t1.ll -o t2.bc -O2 + +# Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic + +# Use a response file for the common command-line arguments. +# Note that mock.py does not perform any compilation; instead, it copies the +# contents of the specified object files into the output object files, in the +# order the jobs are received. +# The "--start-lib/--end-lib" options are used to exercise the special case +# where unused lazy object inputs result in empty index files. +RUN: echo "t1.bc --start-lib t2.bc --end-lib \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=t1.o \ +RUN: --thinlto-distributor-arg=t2.o" > l.rsp + +# Check that index files are not created normally. +RUN: ld.lld @l.rsp +RUN: ls | FileCheck %s --check-prefix=NOINDEXFILES +NOINDEXFILES-NOT: .thinlto.bc + +# Check that index files are created with --thinlto-emit-index-files. +RUN: ld.lld @l.rsp --thinlto-emit-index-files +RUN: ls | FileCheck %s --check-prefix=INDEXFILES +INDEXFILES: t1.bc.thinlto.bc +INDEXFILES: t2.bc.thinlto.bc + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { +entry: + ret void +} diff --git a/lld/test/ELF/dtlto/options.test b/lld/test/ELF/dtlto/options.test new file mode 100644 index 0000000000000..53f0eb41952d0 --- /dev/null +++ b/lld/test/ELF/dtlto/options.test @@ -0,0 +1,41 @@ +# REQUIRES: x86 + +# Test that DTLTO options are passed correctly to the distributor and +# remote compiler. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: opt -thinlto-bc foo.ll -o foo.o + +# Note: validate.py does not perform any compilation. Instead, it validates the +# received JSON, pretty-prints the JSON and the supplied arguments, and then +# exits with an error. This allows FileCheck directives to verify the +# distributor inputs. +RUN: not ld.lld foo.o \ +RUN: -o my.elf \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \ +RUN: --thinlto-distributor-arg=darg1=10 \ +RUN: --thinlto-distributor-arg=darg2=20 \ +RUN: --thinlto-remote-compiler=my_clang.exe \ +RUN: --thinlto-remote-compiler-arg=carg1=20 \ +RUN: --thinlto-remote-compiler-arg=carg2=30 2>&1 | FileCheck %s + +CHECK: distributor_args=['darg1=10', 'darg2=20'] + +CHECK: "linker_output": "my.elf" + +CHECK: "my_clang.exe" +CHECK: "carg1=20" +CHECK: "carg2=30" + +CHECK: ld.lld: error: DTLTO backend compilation: cannot open native object file: + +#--- foo.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo() { +entry: + ret void +} diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test new file mode 100644 index 0000000000000..306dbedcbb19c --- /dev/null +++ b/lld/test/ELF/dtlto/partitions.test @@ -0,0 +1,61 @@ +# REQUIRES: x86 + +# Test that DTLTO works with more than one LTO partition. + +RUN: rm -rf %t && split-file %s %t && cd %t + +# Compile bitcode. +RUN: llvm-as -o full.bc full.ll +RUN: opt -thinlto-bc thin1.ll -o thin1.bc +RUN: opt -thinlto-bc thin2.ll -o thin2.bc + +# Generate object files for mock.py to return. +RUN: llc thin1.ll --filetype=obj -o thin1.o --relocation-model=pic +RUN: llc thin2.ll --filetype=obj -o thin2.o --relocation-model=pic + +# Link with 3 LTO partitions. +RUN: ld.lld full.bc thin1.bc thin2.bc \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=thin1.o \ +RUN: --thinlto-distributor-arg=thin2.o \ +RUN: --save-temps \ +RUN: --lto-partitions=3 + +# DTLTO temporary object files include the task number and a PID component. The +# task number should incorporate the LTO partition number. +RUN: ls | FileCheck %s +CHECK: thin1.3.[[#]].native.o +CHECK: thin2.4.[[#]].native.o + +#--- full.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo() { + call void @bar() + ret void +} + +define void @bar() { + call void @foo() + ret void +} + +#--- thin1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @baz() { +entry: + ret void +} + +#--- thin2.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @_start() { +entry: + ret void +} diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test new file mode 100644 index 0000000000000..07e5b0f4d8e7d --- /dev/null +++ b/lld/test/ELF/dtlto/save-temps.test @@ -0,0 +1,39 @@ +# REQUIRES: x86 + +# Check that DTLTO responds to --save-temps. + +RUN: rm -rf %t && split-file %s %t && cd %t + +# Generate ThinLTO bitcode files. +RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 + +# Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic + +# Use a response file for common command-line arguments. +# Note that mock.py does not perform any compilation; instead, it simply writes +# the contents of the object files supplied on the command line into the output +# object files in job order. +RUN: echo "t1.bc -o my.elf \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=t1.o" > l.rsp + +# Check that DTLTO temporary files are removed by default. +RUN: ld.lld @l.rsp +RUN: ls | FileCheck %s --check-prefix=REMOVED +REMOVED-NOT: .json + +# Check that DTLTO temporary files are retained with --save-temps. +RUN: ld.lld @l.rsp --save-temps +RUN: ls | FileCheck %s --check-prefix=RETAINED +RETAINED: my.[[#]].dist-file.json + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { +entry: + ret void +} diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py index 9e6b0e839d9a8..10f556567cdc8 100644 --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -36,6 +36,7 @@ llvm_config.use_default_substitutions() llvm_config.use_lld() +config.substitutions.append(("%llvm_src_root", config.llvm_src_root)) tool_patterns = [ "llc", From da4539384a19ec98d246b4bf0e247311c6c9396b Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Wed, 18 Jun 2025 19:14:52 +0100 Subject: [PATCH 02/18] Remove thin-archive bitcode member support This change removes the DTLTO support for thin-archive bitcode members from this patch. This makes the patch simpler and more amenable to review. We are also exploring how to support bitcode members in non-thin archives. That work is progressing and may require a different approach for thin-archive support than was originally implemented. If that is the case, reviewing the current implementation would waste reviewers' time. Note that with this support removed, this patch is no longer sufficient to allow for self-hosting an LLVM build with DTLTO. Theoretically, --start-lib/--end-lib could be used instead. However, unlike thin-archives, it's unclear how --start-lib/--end-lib can be easily used with the LLVM build system. --- cross-project-tests/CMakeLists.txt | 5 +- cross-project-tests/dtlto/archive-thin.test | 65 ---------------- cross-project-tests/lit.cfg.py | 4 +- lld/ELF/InputFiles.cpp | 38 +--------- lld/test/ELF/dtlto/archive-thin.test | 82 --------------------- 5 files changed, 7 insertions(+), 187 deletions(-) delete mode 100644 cross-project-tests/dtlto/archive-thin.test delete mode 100644 lld/test/ELF/dtlto/archive-thin.test diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt index 192db87043177..b4b1f47626073 100644 --- a/cross-project-tests/CMakeLists.txt +++ b/cross-project-tests/CMakeLists.txt @@ -19,12 +19,11 @@ set(CROSS_PROJECT_TEST_DEPS FileCheck check-gdb-llvm-support count - llvm-ar - llvm-config llvm-dwarfdump + llvm-config llvm-objdump - not split-file + not ) if ("clang" IN_LIST LLVM_ENABLE_PROJECTS) diff --git a/cross-project-tests/dtlto/archive-thin.test b/cross-project-tests/dtlto/archive-thin.test deleted file mode 100644 index 2d6b7f1cb7e37..0000000000000 --- a/cross-project-tests/dtlto/archive-thin.test +++ /dev/null @@ -1,65 +0,0 @@ -# REQUIRES: x86-registered-target,ld.lld,llvm-ar - -# Test that a DTLTO link succeeds and outputs the expected set of files -# correctly when thin archives are present. - -RUN: rm -rf %t && split-file %s %t && cd %t -RUN: %clang --target=x86_64-linux-gnu -flto=thin -c \ -RUN: foo.c bar.c dog.c cat.c _start.c - -RUN: llvm-ar rcs foo.a foo.o --thin -# Create this bitcode thin archive in a subdirectory to test the expansion of -# the path to a bitcode file that is referenced using "..", e.g., in this case -# "../bar.o". -RUN: mkdir lib -RUN: llvm-ar rcs lib/bar.a bar.o --thin -# Create this bitcode thin archive with an absolute path entry containing "..". -RUN: llvm-ar rcs dog.a %t/lib/../dog.o --thin -RUN: llvm-ar rcs cat.a cat.o --thin -RUN: llvm-ar rcs _start.a _start.o --thin - -RUN: mkdir %t/out && cd %t/out - -RUN: ld.lld %t/foo.a %t/lib/bar.a ../_start.a %t/cat.a \ -RUN: --whole-archive ../dog.a \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/local.py \ -RUN: --thinlto-remote-compiler=%clang \ -RUN: --save-temps - -# Check that the required output files have been created. -RUN: ls | FileCheck %s --check-prefix=OUTPUTS \ -RUN: --implicit-check-not=cat --implicit-check-not=foo - -# JSON jobs description. -OUTPUTS-DAG: a.[[PID:[a-zA-Z0-9_]+]].dist-file.json - -# Individual summary index files. -OUTPUTS-DAG: dog.1.[[PID]].native.o.thinlto.bc{{$}} -OUTPUTS-DAG: _start.2.[[PID]].native.o.thinlto.bc{{$}} -OUTPUTS-DAG: bar.3.[[PID]].native.o.thinlto.bc{{$}} - -# Native output object files. -OUTPUTS-DAG: dog.1.[[PID]].native.o{{$}} -OUTPUTS-DAG: _start.2.[[PID]].native.o{{$}} -OUTPUTS-DAG: bar.3.[[PID]].native.o{{$}} - -#--- foo.c -__attribute__((retain)) void foo() {} - -#--- bar.c -extern void foo(); -__attribute__((retain)) void bar() { foo(); } - -#--- dog.c -__attribute__((retain)) void dog() {} - -#--- cat.c -__attribute__((retain)) void cat() {} - -#--- _start.c -extern void bar(); -__attribute__((retain)) void _start() { - bar(); -} - diff --git a/cross-project-tests/lit.cfg.py b/cross-project-tests/lit.cfg.py index ac27753472646..b35c643ac898c 100644 --- a/cross-project-tests/lit.cfg.py +++ b/cross-project-tests/lit.cfg.py @@ -19,7 +19,7 @@ config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. -config.suffixes = [".c", ".cl", ".cpp", ".m", ".test"] +config.suffixes = [".c", ".cl", ".cpp", ".m"] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent @@ -107,8 +107,6 @@ def get_required_attr(config, attr_name): if lldb_path is not None: config.available_features.add("lldb") -if llvm_config.use_llvm_tool("llvm-ar"): - config.available_features.add("llvm-ar") def configure_dexter_substitutions(): """Configure substitutions for host platform and return list of dependencies""" diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 3358e8bc38cbd..46508443e2863 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1754,33 +1754,6 @@ static uint8_t getOsAbi(const Triple &t) { } } -// For DTLTO, bitcode member names must be valid paths to files on disk. -// For thin archives, resolve `memberPath` relative to the archive's location. -// Returns true if adjusted; false otherwise. Non-thin archives are unsupported. -static bool dtltoAdjustMemberPathIfThinArchive(Ctx &ctx, StringRef archivePath, - std::string &memberPath) { - assert(!archivePath.empty() && !ctx.arg.dtltoDistributor.empty()); - - // Check if the archive file is a thin archive by reading its header. - auto bufferOrErr = - MemoryBuffer::getFileSlice(archivePath, sizeof(ThinArchiveMagic) - 1, 0); - if (std::error_code ec = bufferOrErr.getError()) { - ErrAlways(ctx) << "cannot open " << archivePath << ": " << ec.message(); - return false; - } - - if (!bufferOrErr->get()->getBuffer().starts_with(ThinArchiveMagic)) - return false; - - SmallString<64> resolvedPath; - if (path::is_relative(memberPath)) { - resolvedPath = path::parent_path(archivePath); - path::append(resolvedPath, memberPath); - memberPath = resolvedPath.str(); - } - return true; -} - BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName, uint64_t offsetInArchive, bool lazy) : InputFile(ctx, BitcodeKind, mb) { @@ -1798,13 +1771,10 @@ BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName, // symbols later in the link stage). So we append file offset to make // filename unique. StringSaver &ss = ctx.saver; - StringRef name = - (archiveName.empty() || - (!ctx.arg.dtltoDistributor.empty() && - dtltoAdjustMemberPathIfThinArchive(ctx, archiveName, path))) - ? ss.save(path) - : ss.save(archiveName + "(" + path::filename(path) + " at " + - utostr(offsetInArchive) + ")"); + StringRef name = archiveName.empty() + ? ss.save(path) + : ss.save(archiveName + "(" + path::filename(path) + + " at " + utostr(offsetInArchive) + ")"); MemoryBufferRef mbref(mb.getBuffer(), name); obj = CHECK2(lto::InputFile::create(mbref), this); diff --git a/lld/test/ELF/dtlto/archive-thin.test b/lld/test/ELF/dtlto/archive-thin.test deleted file mode 100644 index 45f841be3fcf6..0000000000000 --- a/lld/test/ELF/dtlto/archive-thin.test +++ /dev/null @@ -1,82 +0,0 @@ -# REQUIRES: x86 - -# Test that a DTLTO link succeeds and outputs the expected set of files -# correctly when thin archives are present. - -RUN: rm -rf %t && split-file %s %t && cd %t - -# Generate ThinLTO bitcode files. -RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 -RUN: opt -thinlto-bc t2.ll -o t2.bc -O2 -RUN: opt -thinlto-bc t3.ll -o t3.bc -O2 - -# Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic -RUN: llc t2.ll --filetype=obj -o t2.o --relocation-model=pic -RUN: llc t3.ll --filetype=obj -o t3.o --relocation-model=pic - -RUN: llvm-ar rcs t1.a t1.bc --thin -# Create this bitcode thin archive in a subdirectory to test the expansion of -# the path to a bitcode file that is referenced using "..", e.g., in this case -# "../t2.bc". -RUN: mkdir lib -RUN: llvm-ar rcs lib/t2.a t2.bc --thin -# Create this bitcode thin archive with an absolute path entry containing "..". -RUN: llvm-ar rcs t3.a %t/lib/../t3.bc --thin -RUN: llvm-ar rcs t4.a t1.bc --thin - -RUN: mkdir %t/out && cd %t/out - -# Note that mock.py does not do any compilation, instead it simply writes the -# contents of the object files supplied on the command line into the output -# object files in job order. -RUN: ld.lld --whole-archive %t/t1.a %t/lib/t2.a ../t3.a \ -RUN: --no-whole-archive %t/t4.a \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ -RUN: --thinlto-distributor-arg=../t1.o \ -RUN: --thinlto-distributor-arg=../t2.o \ -RUN: --thinlto-distributor-arg=../t3.o \ -RUN: --save-temps - -RUN: ls | FileCheck %s --implicit-check-not=4 - -# JSON jobs description. -CHECK-DAG: a.{{[0-9]+}}.dist-file.json - -# Individual summary index files. -CHECK-DAG: t1.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} -CHECK-DAG: t2.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} -CHECK-DAG: t3.{{[0-9]+}}.{{[0-9]+}}.native.o.thinlto.bc{{$}} - -# Native output object files. -CHECK-DAG: t1.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} -CHECK-DAG: t2.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} -CHECK-DAG: t3.{{[0-9]+}}.{{[0-9]+}}.native.o{{$}} - -#--- t1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t1() { -entry: - ret void -} - -#--- t2.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t2() { -entry: - ret void -} - -#--- t3.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t3() { -entry: - ret void -} From f1ca7ded5f6a924b8dc9fd33acc3af21c73e4e64 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 10:00:53 +0100 Subject: [PATCH 03/18] Remove trailing full stop from new help text. --- lld/ELF/Options.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 6599691244fe8..fdd766c1a3826 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -712,7 +712,7 @@ def thinlto_single_module_eq: JJ<"thinlto-single-module=">, HelpText<"Specify a single module to compile in ThinLTO mode, for debugging only">; def thinlto_distributor_eq: JJ<"thinlto-distributor=">, HelpText<"Distributor to use for ThinLTO backend compilations. If specified, " - "ThinLTO backend compilations will be distributed.">; + "ThinLTO backend compilations will be distributed">; defm thinlto_distributor_arg: EEq<"thinlto-distributor-arg", "Arguments to " "pass to the ThinLTO distributor">; def thinlto_compiler_eq: JJ<"thinlto-remote-compiler=">, From d256457bada53bbd9ef0cb26836470d2194b4ce7 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 11:46:56 +0100 Subject: [PATCH 04/18] Use "relocatable file" in test comment rather than "ET_REL" --- lld/test/ELF/dtlto/empty.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test index 5f69d90051220..4c5036743f189 100644 --- a/lld/test/ELF/dtlto/empty.test +++ b/lld/test/ELF/dtlto/empty.test @@ -22,7 +22,7 @@ RUN: ld.lld @l.rsp RUN: llc -filetype=obj t1.ll -o t1.o RUN: llc -filetype=obj t2.ll -o t2.o -# Check linking succeeds when all input files are ET_RELs. +# Check linking succeeds when all input files are relocatable files. RUN: ld.lld @l.rsp #--- t1.ll From aa04affe1ce67309023662ef76b079a6231a61d3 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 15:22:57 +0100 Subject: [PATCH 05/18] Improve ls usage/checks in tests. --- cross-project-tests/dtlto/dtlto.c | 31 +++++++++++++++++------------- lld/test/ELF/dtlto/imports.test | 6 +++--- lld/test/ELF/dtlto/index.test | 6 +++--- lld/test/ELF/dtlto/partitions.test | 6 +++--- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/cross-project-tests/dtlto/dtlto.c b/cross-project-tests/dtlto/dtlto.c index e967ede35b09b..0ebdc6b59da50 100644 --- a/cross-project-tests/dtlto/dtlto.c +++ b/cross-project-tests/dtlto/dtlto.c @@ -13,23 +13,28 @@ // RUN: --thinlto-remote-compiler-arg=--save-temps /// Check that the required output files have been created. -// RUN: ls | count 10 -// RUN: ls | FileCheck %s +// RUN: ls | sort | FileCheck %s -/// Produced by the bitcode compilation. -// CHECK-DAG: {{^}}dtlto.o{{$}} +/// No files are expected before. +// CHECK-NOT: {{.}} /// Linked ELF. -// CHECK-DAG: {{^}}a.out{{$}} +// CHECK: {{^}}a.out{{$}} + +/// Produced by the bitcode compilation. +// CHECK-NEXT: {{^}}dtlto.o{{$}} /// --save-temps output for the backend compilation. -// CHECK-DAG: {{^}}dtlto.s{{$}} -// CHECK-DAG: {{^}}dtlto.s.0.preopt.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.1.promote.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.2.internalize.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.3.import.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.4.opt.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.5.precodegen.bc{{$}} -// CHECK-DAG: {{^}}dtlto.s.resolution.txt{{$}} +// CHECK-NEXT: {{^}}dtlto.s{{$}} +// CHECK-NEXT: {{^}}dtlto.s.0.preopt.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.1.promote.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.2.internalize.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.3.import.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.4.opt.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.5.precodegen.bc{{$}} +// CHECK-NEXT: {{^}}dtlto.s.resolution.txt{{$}} + +/// No files are expected after. +// CHECK-NOT: {{.}} int _start() { return 0; } diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test index 74d5223f04e24..1969b4888e0e0 100644 --- a/lld/test/ELF/dtlto/imports.test +++ b/lld/test/ELF/dtlto/imports.test @@ -27,9 +27,9 @@ NOIMPORTSFILES-NOT: .imports # Check that imports files are created with --thinlto-emit-imports-files. RUN: ld.lld @l.rsp --thinlto-emit-imports-files -RUN: ls | FileCheck %s --check-prefix=IMPORTSFILES -IMPORTSFILES: t1.bc.imports -IMPORTSFILES: t2.bc.imports +RUN: ls | sort | FileCheck %s --check-prefix=IMPORTSFILES +IMPORTSFILES: {{^}}t1.bc.imports{{$}} +IMPORTSFILES: {{^}}t2.bc.imports{{$}} #--- t1.ll target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test index 4a869c65468fe..5a17f5e65612b 100644 --- a/lld/test/ELF/dtlto/index.test +++ b/lld/test/ELF/dtlto/index.test @@ -30,9 +30,9 @@ NOINDEXFILES-NOT: .thinlto.bc # Check that index files are created with --thinlto-emit-index-files. RUN: ld.lld @l.rsp --thinlto-emit-index-files -RUN: ls | FileCheck %s --check-prefix=INDEXFILES -INDEXFILES: t1.bc.thinlto.bc -INDEXFILES: t2.bc.thinlto.bc +RUN: ls | sort | FileCheck %s --check-prefix=INDEXFILES +INDEXFILES: {{^}}t1.bc.thinlto.bc{{$}} +INDEXFILES: {{^}}t2.bc.thinlto.bc{{$}} #--- t1.ll target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test index 306dbedcbb19c..6e6a76ae5d042 100644 --- a/lld/test/ELF/dtlto/partitions.test +++ b/lld/test/ELF/dtlto/partitions.test @@ -24,9 +24,9 @@ RUN: --lto-partitions=3 # DTLTO temporary object files include the task number and a PID component. The # task number should incorporate the LTO partition number. -RUN: ls | FileCheck %s -CHECK: thin1.3.[[#]].native.o -CHECK: thin2.4.[[#]].native.o +RUN: ls | sort | FileCheck %s +CHECK: {{^}}thin1.3.[[PID:[a-zA-Z0-9_]+]].native.o{{$}} +CHECK: {{^}}thin2.4.[[PID]].native.o{{$}} #--- full.ll target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" From 2006a77a4e7d1b2bed27ec66052d00f78a4a7823 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 15:26:34 +0100 Subject: [PATCH 06/18] "#" -> "##" to make comments stand out more. --- lld/test/ELF/dtlto/empty.test | 12 ++++++------ lld/test/ELF/dtlto/imports.test | 14 +++++++------- lld/test/ELF/dtlto/index.test | 22 +++++++++++----------- lld/test/ELF/dtlto/options.test | 12 ++++++------ lld/test/ELF/dtlto/partitions.test | 12 ++++++------ lld/test/ELF/dtlto/save-temps.test | 18 +++++++++--------- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test index 4c5036743f189..711035399d193 100644 --- a/lld/test/ELF/dtlto/empty.test +++ b/lld/test/ELF/dtlto/empty.test @@ -1,28 +1,28 @@ # REQUIRES: x86 -# Test that DTLTO options are a no-op if no thinLTO is performed. +## Check that DTLTO options are a no-op if no thinLTO is performed. RUN: rm -rf %t && split-file %s %t && cd %t RUN: opt t1.ll -o t1.o -O2 RUN: opt t2.ll -o t2.o -O2 -# Common command-line arguments. Note that mock.py does not do any compilation; -# instead, it simply writes the contents of the object files supplied on the -# command line into the output object files in job order. +## Common command-line arguments. Note that mock.py does not do any compilation; +## instead, it simply writes the contents of the object files supplied on the +## command line into the output object files in job order. RUN: echo "t1.o t2.o \ RUN: --thinlto-distributor=%python \ RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ RUN: --thinlto-distributor-arg=no-exist1.o \ RUN: --thinlto-distributor-arg=no-exist2.o" > l.rsp -# Check linking succeeds when all input files are Full LTO. +## Check linking succeeds when all input files are Full LTO. RUN: ld.lld @l.rsp RUN: llc -filetype=obj t1.ll -o t1.o RUN: llc -filetype=obj t2.ll -o t2.o -# Check linking succeeds when all input files are relocatable files. +## Check linking succeeds when all input files are relocatable files. RUN: ld.lld @l.rsp #--- t1.ll diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test index 1969b4888e0e0..3472f32640dce 100644 --- a/lld/test/ELF/dtlto/imports.test +++ b/lld/test/ELF/dtlto/imports.test @@ -1,31 +1,31 @@ # REQUIRES: x86 -# Check that DTLTO creates imports lists if requested. +## Check that DTLTO creates imports lists if requested. RUN: rm -rf %t && split-file %s %t && cd %t RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 RUN: opt -thinlto-bc t2.ll -o t2.bc -O2 -# Generate object files for mock.py to return. +## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic RUN: llc t2.ll --filetype=obj -o t2.o --relocation-model=pic -# Common command-line arguments. Note that mock.py does not do any compilation; -# instead, it simply writes the contents of the object files supplied on the -# command line into the output object files in job order. +## Common command-line arguments. Note that mock.py does not do any compilation; +## instead, it simply writes the contents of the object files supplied on the +## command line into the output object files in job order. RUN: echo "t1.bc t2.bc \ RUN: --thinlto-distributor=%python \ RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ RUN: --thinlto-distributor-arg=t1.o \ RUN: --thinlto-distributor-arg=t2.o" > l.rsp -# Check that imports files are not created normally. +## Check that imports files are not created normally. RUN: ld.lld @l.rsp RUN: ls | FileCheck %s --check-prefix=NOIMPORTSFILES NOIMPORTSFILES-NOT: .imports -# Check that imports files are created with --thinlto-emit-imports-files. +## Check that imports files are created with --thinlto-emit-imports-files. RUN: ld.lld @l.rsp --thinlto-emit-imports-files RUN: ls | sort | FileCheck %s --check-prefix=IMPORTSFILES IMPORTSFILES: {{^}}t1.bc.imports{{$}} diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test index 5a17f5e65612b..a7522233380fd 100644 --- a/lld/test/ELF/dtlto/index.test +++ b/lld/test/ELF/dtlto/index.test @@ -1,34 +1,34 @@ # REQUIRES: x86 -# Check that DTLTO creates individual summary index files if requested. +## Check that DTLTO creates individual summary index files if requested. RUN: rm -rf %t && split-file %s %t && cd %t -# Generate ThinLTO bitcode files. +## Generate ThinLTO bitcode files. RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 RUN: opt -thinlto-bc t1.ll -o t2.bc -O2 -# Generate object files for mock.py to return. +## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic -# Use a response file for the common command-line arguments. -# Note that mock.py does not perform any compilation; instead, it copies the -# contents of the specified object files into the output object files, in the -# order the jobs are received. -# The "--start-lib/--end-lib" options are used to exercise the special case -# where unused lazy object inputs result in empty index files. +## Use a response file for the common command-line arguments. +## Note that mock.py does not perform any compilation; instead, it copies the +## contents of the specified object files into the output object files, in the +## order the jobs are received. +## The "--start-lib/--end-lib" options are used to exercise the special case +## where unused lazy object inputs result in empty index files. RUN: echo "t1.bc --start-lib t2.bc --end-lib \ RUN: --thinlto-distributor=%python \ RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ RUN: --thinlto-distributor-arg=t1.o \ RUN: --thinlto-distributor-arg=t2.o" > l.rsp -# Check that index files are not created normally. +## Check that index files are not created normally. RUN: ld.lld @l.rsp RUN: ls | FileCheck %s --check-prefix=NOINDEXFILES NOINDEXFILES-NOT: .thinlto.bc -# Check that index files are created with --thinlto-emit-index-files. +## Check that index files are created with --thinlto-emit-index-files. RUN: ld.lld @l.rsp --thinlto-emit-index-files RUN: ls | sort | FileCheck %s --check-prefix=INDEXFILES INDEXFILES: {{^}}t1.bc.thinlto.bc{{$}} diff --git a/lld/test/ELF/dtlto/options.test b/lld/test/ELF/dtlto/options.test index 53f0eb41952d0..7a3585d029f8a 100644 --- a/lld/test/ELF/dtlto/options.test +++ b/lld/test/ELF/dtlto/options.test @@ -1,16 +1,16 @@ # REQUIRES: x86 -# Test that DTLTO options are passed correctly to the distributor and -# remote compiler. +## Test that DTLTO options are passed correctly to the distributor and +## remote compiler. RUN: rm -rf %t && split-file %s %t && cd %t RUN: opt -thinlto-bc foo.ll -o foo.o -# Note: validate.py does not perform any compilation. Instead, it validates the -# received JSON, pretty-prints the JSON and the supplied arguments, and then -# exits with an error. This allows FileCheck directives to verify the -# distributor inputs. +## Note: validate.py does not perform any compilation. Instead, it validates the +## received JSON, pretty-prints the JSON and the supplied arguments, and then +## exits with an error. This allows FileCheck directives to verify the +## distributor inputs. RUN: not ld.lld foo.o \ RUN: -o my.elf \ RUN: --thinlto-distributor=%python \ diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test index 6e6a76ae5d042..07136ad70ef55 100644 --- a/lld/test/ELF/dtlto/partitions.test +++ b/lld/test/ELF/dtlto/partitions.test @@ -1,19 +1,19 @@ # REQUIRES: x86 -# Test that DTLTO works with more than one LTO partition. +## Test that DTLTO works with more than one LTO partition. RUN: rm -rf %t && split-file %s %t && cd %t -# Compile bitcode. +## Compile bitcode. RUN: llvm-as -o full.bc full.ll RUN: opt -thinlto-bc thin1.ll -o thin1.bc RUN: opt -thinlto-bc thin2.ll -o thin2.bc -# Generate object files for mock.py to return. +## Generate object files for mock.py to return. RUN: llc thin1.ll --filetype=obj -o thin1.o --relocation-model=pic RUN: llc thin2.ll --filetype=obj -o thin2.o --relocation-model=pic -# Link with 3 LTO partitions. +## Link with 3 LTO partitions. RUN: ld.lld full.bc thin1.bc thin2.bc \ RUN: --thinlto-distributor=%python \ RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ @@ -22,8 +22,8 @@ RUN: --thinlto-distributor-arg=thin2.o \ RUN: --save-temps \ RUN: --lto-partitions=3 -# DTLTO temporary object files include the task number and a PID component. The -# task number should incorporate the LTO partition number. +## DTLTO temporary object files include the task number and a PID component. The +## task number should incorporate the LTO partition number. RUN: ls | sort | FileCheck %s CHECK: {{^}}thin1.3.[[PID:[a-zA-Z0-9_]+]].native.o{{$}} CHECK: {{^}}thin2.4.[[PID]].native.o{{$}} diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test index 07e5b0f4d8e7d..7e5deba834514 100644 --- a/lld/test/ELF/dtlto/save-temps.test +++ b/lld/test/ELF/dtlto/save-temps.test @@ -1,30 +1,30 @@ # REQUIRES: x86 -# Check that DTLTO responds to --save-temps. +## Check that DTLTO responds to --save-temps. RUN: rm -rf %t && split-file %s %t && cd %t -# Generate ThinLTO bitcode files. +## Generate ThinLTO bitcode. RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 -# Generate object files for mock.py to return. +## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic -# Use a response file for common command-line arguments. -# Note that mock.py does not perform any compilation; instead, it simply writes -# the contents of the object files supplied on the command line into the output -# object files in job order. +## Use a response file for common command-line arguments. +## Note that mock.py does not perform any compilation; instead, it simply writes +## the contents of the object files supplied on the command line into the output +## object files in job order. RUN: echo "t1.bc -o my.elf \ RUN: --thinlto-distributor=%python \ RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ RUN: --thinlto-distributor-arg=t1.o" > l.rsp -# Check that DTLTO temporary files are removed by default. +## Check that DTLTO temporary files are removed by default. RUN: ld.lld @l.rsp RUN: ls | FileCheck %s --check-prefix=REMOVED REMOVED-NOT: .json -# Check that DTLTO temporary files are retained with --save-temps. +## Check that DTLTO temporary files are retained with --save-temps. RUN: ld.lld @l.rsp --save-temps RUN: ls | FileCheck %s --check-prefix=RETAINED RETAINED: my.[[#]].dist-file.json From 8716e1cdc7e5ef7024221b391d4e5dd3d246e1eb Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 16:58:55 +0100 Subject: [PATCH 07/18] Remove unneeded "-O2" use. --- lld/test/ELF/dtlto/empty.test | 4 ++-- lld/test/ELF/dtlto/imports.test | 4 ++-- lld/test/ELF/dtlto/index.test | 4 ++-- lld/test/ELF/dtlto/save-temps.test | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test index 711035399d193..c1398af8c1c06 100644 --- a/lld/test/ELF/dtlto/empty.test +++ b/lld/test/ELF/dtlto/empty.test @@ -4,8 +4,8 @@ RUN: rm -rf %t && split-file %s %t && cd %t -RUN: opt t1.ll -o t1.o -O2 -RUN: opt t2.ll -o t2.o -O2 +RUN: opt t1.ll -o t1.o +RUN: opt t2.ll -o t2.o ## Common command-line arguments. Note that mock.py does not do any compilation; ## instead, it simply writes the contents of the object files supplied on the diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test index 3472f32640dce..426bd145660fd 100644 --- a/lld/test/ELF/dtlto/imports.test +++ b/lld/test/ELF/dtlto/imports.test @@ -4,8 +4,8 @@ RUN: rm -rf %t && split-file %s %t && cd %t -RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 -RUN: opt -thinlto-bc t2.ll -o t2.bc -O2 +RUN: opt -thinlto-bc t1.ll -o t1.bc +RUN: opt -thinlto-bc t2.ll -o t2.bc ## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test index a7522233380fd..81d438a7a0a62 100644 --- a/lld/test/ELF/dtlto/index.test +++ b/lld/test/ELF/dtlto/index.test @@ -5,8 +5,8 @@ RUN: rm -rf %t && split-file %s %t && cd %t ## Generate ThinLTO bitcode files. -RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 -RUN: opt -thinlto-bc t1.ll -o t2.bc -O2 +RUN: opt -thinlto-bc t1.ll -o t1.bc +RUN: opt -thinlto-bc t1.ll -o t2.bc ## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test index 7e5deba834514..2bc068bcd52db 100644 --- a/lld/test/ELF/dtlto/save-temps.test +++ b/lld/test/ELF/dtlto/save-temps.test @@ -5,7 +5,7 @@ RUN: rm -rf %t && split-file %s %t && cd %t ## Generate ThinLTO bitcode. -RUN: opt -thinlto-bc t1.ll -o t1.bc -O2 +RUN: opt -thinlto-bc t1.ll -o t1.bc ## Generate object files for mock.py to return. RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic From cb5e2663f08a895606d9f6cd58d7ae3e7203d24c Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 17:01:34 +0100 Subject: [PATCH 08/18] Remove unneeded "--relocation-model=pic" use. --- lld/test/ELF/dtlto/imports.test | 4 ++-- lld/test/ELF/dtlto/index.test | 2 +- lld/test/ELF/dtlto/partitions.test | 4 ++-- lld/test/ELF/dtlto/save-temps.test | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test index 426bd145660fd..7ebd0fdec1349 100644 --- a/lld/test/ELF/dtlto/imports.test +++ b/lld/test/ELF/dtlto/imports.test @@ -8,8 +8,8 @@ RUN: opt -thinlto-bc t1.ll -o t1.bc RUN: opt -thinlto-bc t2.ll -o t2.bc ## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic -RUN: llc t2.ll --filetype=obj -o t2.o --relocation-model=pic +RUN: llc t1.ll --filetype=obj -o t1.o +RUN: llc t2.ll --filetype=obj -o t2.o ## Common command-line arguments. Note that mock.py does not do any compilation; ## instead, it simply writes the contents of the object files supplied on the diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test index 81d438a7a0a62..39633484bc94d 100644 --- a/lld/test/ELF/dtlto/index.test +++ b/lld/test/ELF/dtlto/index.test @@ -9,7 +9,7 @@ RUN: opt -thinlto-bc t1.ll -o t1.bc RUN: opt -thinlto-bc t1.ll -o t2.bc ## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic +RUN: llc t1.ll --filetype=obj -o t1.o ## Use a response file for the common command-line arguments. ## Note that mock.py does not perform any compilation; instead, it copies the diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test index 07136ad70ef55..4a9955a400e4d 100644 --- a/lld/test/ELF/dtlto/partitions.test +++ b/lld/test/ELF/dtlto/partitions.test @@ -10,8 +10,8 @@ RUN: opt -thinlto-bc thin1.ll -o thin1.bc RUN: opt -thinlto-bc thin2.ll -o thin2.bc ## Generate object files for mock.py to return. -RUN: llc thin1.ll --filetype=obj -o thin1.o --relocation-model=pic -RUN: llc thin2.ll --filetype=obj -o thin2.o --relocation-model=pic +RUN: llc thin1.ll --filetype=obj -o thin1.o +RUN: llc thin2.ll --filetype=obj -o thin2.o ## Link with 3 LTO partitions. RUN: ld.lld full.bc thin1.bc thin2.bc \ diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test index 2bc068bcd52db..e0a2becc4b8ee 100644 --- a/lld/test/ELF/dtlto/save-temps.test +++ b/lld/test/ELF/dtlto/save-temps.test @@ -8,7 +8,7 @@ RUN: rm -rf %t && split-file %s %t && cd %t RUN: opt -thinlto-bc t1.ll -o t1.bc ## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o --relocation-model=pic +RUN: llc t1.ll --filetype=obj -o t1.o ## Use a response file for common command-line arguments. ## Note that mock.py does not perform any compilation; instead, it simply writes From 96fa2cb7f54bad64f7e9bf44910f42ca4584fe79 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 17:02:51 +0100 Subject: [PATCH 09/18] Remove unneeded "entry:" lines from textual IR in tests. --- lld/test/ELF/dtlto/empty.test | 2 -- lld/test/ELF/dtlto/imports.test | 2 -- lld/test/ELF/dtlto/index.test | 1 - lld/test/ELF/dtlto/options.test | 1 - lld/test/ELF/dtlto/partitions.test | 2 -- lld/test/ELF/dtlto/save-temps.test | 1 - 6 files changed, 9 deletions(-) diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test index c1398af8c1c06..c79a80f854c71 100644 --- a/lld/test/ELF/dtlto/empty.test +++ b/lld/test/ELF/dtlto/empty.test @@ -30,7 +30,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @t1() { -entry: ret void } @@ -39,6 +38,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @t2() { -entry: ret void } diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test index 7ebd0fdec1349..b31f802a85450 100644 --- a/lld/test/ELF/dtlto/imports.test +++ b/lld/test/ELF/dtlto/imports.test @@ -36,7 +36,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @t1() { -entry: ret void } @@ -47,7 +46,6 @@ target triple = "x86_64-unknown-linux-gnu" declare void @t1(...) define void @t2() { -entry: call void (...) @t1() ret void } diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test index 39633484bc94d..e53ceb5d2d568 100644 --- a/lld/test/ELF/dtlto/index.test +++ b/lld/test/ELF/dtlto/index.test @@ -39,6 +39,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @t1() { -entry: ret void } diff --git a/lld/test/ELF/dtlto/options.test b/lld/test/ELF/dtlto/options.test index 7a3585d029f8a..c67fa70a631a8 100644 --- a/lld/test/ELF/dtlto/options.test +++ b/lld/test/ELF/dtlto/options.test @@ -36,6 +36,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @foo() { -entry: ret void } diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test index 4a9955a400e4d..30c02aafe9153 100644 --- a/lld/test/ELF/dtlto/partitions.test +++ b/lld/test/ELF/dtlto/partitions.test @@ -47,7 +47,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @baz() { -entry: ret void } @@ -56,6 +55,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @_start() { -entry: ret void } diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test index e0a2becc4b8ee..d9cbe5d53a14c 100644 --- a/lld/test/ELF/dtlto/save-temps.test +++ b/lld/test/ELF/dtlto/save-temps.test @@ -34,6 +34,5 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @t1() { -entry: ret void } From 54b91cc4c8b36444fa6716d8c0421bafa84ffb2c Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 17:19:25 +0100 Subject: [PATCH 10/18] Improve comment in test to explain the presence of the PID in a the file name. --- lld/test/ELF/dtlto/save-temps.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test index d9cbe5d53a14c..e56b3c4489536 100644 --- a/lld/test/ELF/dtlto/save-temps.test +++ b/lld/test/ELF/dtlto/save-temps.test @@ -24,7 +24,8 @@ RUN: ld.lld @l.rsp RUN: ls | FileCheck %s --check-prefix=REMOVED REMOVED-NOT: .json -## Check that DTLTO temporary files are retained with --save-temps. +## Check that DTLTO temporary files are retained with --save-temps. Note that +## DTLTO temporary object files include a PID component. RUN: ld.lld @l.rsp --save-temps RUN: ls | FileCheck %s --check-prefix=RETAINED RETAINED: my.[[#]].dist-file.json From 04fa090f52fe1581e092b23e08a6e6020fcabd5a Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Thu, 26 Jun 2025 17:20:30 +0100 Subject: [PATCH 11/18] Remove unneeded linker name from error message check. --- lld/test/ELF/dtlto/options.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/test/ELF/dtlto/options.test b/lld/test/ELF/dtlto/options.test index c67fa70a631a8..1a10d18140f27 100644 --- a/lld/test/ELF/dtlto/options.test +++ b/lld/test/ELF/dtlto/options.test @@ -29,7 +29,7 @@ CHECK: "my_clang.exe" CHECK: "carg1=20" CHECK: "carg2=30" -CHECK: ld.lld: error: DTLTO backend compilation: cannot open native object file: +CHECK: error: DTLTO backend compilation: cannot open native object file: #--- foo.ll target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" From d2a704a15fa870c6b1fbad62ff78c02884b221a5 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 10:53:38 +0100 Subject: [PATCH 12/18] Removed unnecessary line left over from now removed code. --- lld/ELF/InputFiles.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 46508443e2863..71e72e7184b9f 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTO.h" -#include "llvm/Object/Archive.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" From 6f9889ef12ec27c1624fb5edc10bab645c1837b2 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 13:54:26 +0100 Subject: [PATCH 13/18] Amalgamate imports.test, index.test, and save-temps.test into files.test --- lld/test/ELF/dtlto/files.test | 99 ++++++++++++++++++++++++++++++ lld/test/ELF/dtlto/imports.test | 51 --------------- lld/test/ELF/dtlto/index.test | 43 ------------- lld/test/ELF/dtlto/save-temps.test | 39 ------------ 4 files changed, 99 insertions(+), 133 deletions(-) create mode 100644 lld/test/ELF/dtlto/files.test delete mode 100644 lld/test/ELF/dtlto/imports.test delete mode 100644 lld/test/ELF/dtlto/index.test delete mode 100644 lld/test/ELF/dtlto/save-temps.test diff --git a/lld/test/ELF/dtlto/files.test b/lld/test/ELF/dtlto/files.test new file mode 100644 index 0000000000000..9a8af17ebcc26 --- /dev/null +++ b/lld/test/ELF/dtlto/files.test @@ -0,0 +1,99 @@ +# REQUIRES: x86 + +## Check that the LLD options --save-temps, --thinlto-emit-index-files, +## and --thinlto-emit-imports-files for DTLTO. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: sed 's/@t1/@t2/g' t1.ll > t2.ll + +## Generate ThinLTO bitcode files. Note that t3.bc will not be used by the +## linker. +RUN: opt -thinlto-bc t1.ll -o t1.bc +RUN: opt -thinlto-bc t2.ll -o t2.bc +RUN: cp t1.bc t3.bc + +## Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.o +RUN: llc t2.ll --filetype=obj -o t2.o + +## Create response file containing shared ThinLTO linker arguments. +## --start-lib/--end-lib is used to test the special case where unused lazy +## bitcode inputs result in empty index/imports files. +## Note that mock.py does not do any compilation; instead, it simply writes +## the contents of the object files supplied on the command line into the +## output object files in job order. +RUN: echo "t1.bc t2.bc --start-lib t3.bc --end-lib -o my.elf \ +RUN: --thinlto-distributor=%python \ +RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ +RUN: --thinlto-distributor-arg=t1.o \ +RUN: --thinlto-distributor-arg=t2.o" > l.rsp + +## Check that without extra flags, no index/imports files are produced and +## backend temp files are removed. +RUN: ld.lld @l.rsp +RUN: ls | FileCheck %s \ +RUN: --check-prefixes=NOBACKEND,NOINDEXFILES,NOIMPORTSFILES,NOEMPTYIMPORTS + +## Check that index files are created with --thinlto-emit-index-files. +RUN: rm -f *.imports *.thinlto.bc +RUN: ld.lld @l.rsp --thinlto-emit-index-files +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=NOBACKEND,INDEXFILES,NOIMPORTSFILES,NOEMPTYIMPORTS + +## Check that imports files are created with --thinlto-emit-imports-files. +RUN: rm -f *.imports *.thinlto.bc +RUN: ld.lld @l.rsp --thinlto-emit-imports-files +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=NOBACKEND,NOINDEXFILES,IMPORTSFILES,NOEMPTYIMPORTS + +## Check that both index and imports files are emitted with both flags. +RUN: rm -f *.imports *.thinlto.bc +RUN: ld.lld @l.rsp --thinlto-emit-index-files \ +RUN: --thinlto-emit-imports-files +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=NOBACKEND,INDEXFILES,IMPORTSFILES,EMPTYIMPORTS + +## Check that backend temp files are retained with --save-temps. +RUN: rm -f *.imports *.thinlto.bc +RUN: ld.lld @l.rsp --save-temps +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=BACKEND,NOINDEXFILES,NOIMPORTSFILES,NOEMPTYIMPORTS + +## Check that all files are emitted when all options are enabled. +RUN: rm -f *.imports *.thinlto.bc +RUN: ld.lld @l.rsp --save-temps --thinlto-emit-index-files \ +RUN: --thinlto-emit-imports-files +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=BACKEND,INDEXFILES,IMPORTSFILES,EMPTYIMPORTS + +## JSON jobs description, retained with --save-temps. +## Note that DTLTO temporary files include a PID component. +NOBACKEND-NOT: {{^}}my.[[#]].dist-file.json{{$}} +BACKEND: {{^}}my.[[#]].dist-file.json{{$}} + +## Index/imports files for t1.bc. +NOIMPORTSFILES-NOT: {{^}}t1.bc.imports{{$}} +IMPORTSFILES: {{^}}t1.bc.imports{{$}} +NOINDEXFILES-NOT: {{^}}t1.bc.thinlto.bc{{$}} +INDEXFILES: {{^}}t1.bc.thinlto.bc{{$}} + +## Index/imports files for t2.bc. +NOIMPORTSFILES-NOT: {{^}}t2.bc.imports{{$}} +IMPORTSFILES: {{^}}t2.bc.imports{{$}} +NOINDEXFILES-NOT: {{^}}t2.bc.thinlto.bc{{$}} +INDEXFILES: {{^}}t2.bc.thinlto.bc{{$}} + +## Empty index/imports files for unused t3.bc. +NOEMPTYIMPORTS-NOT: {{^}}t3.bc.imports{{$}} +EMPTYIMPORTS: {{^}}t3.bc.imports{{$}} +NOINDEXFILES-NOT: {{^}}t3.bc.thinlto.bc{{$}} +INDEXFILES: {{^}}t3.bc.thinlto.bc{{$}} + +#--- t1.ll +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @t1() { + ret void +} diff --git a/lld/test/ELF/dtlto/imports.test b/lld/test/ELF/dtlto/imports.test deleted file mode 100644 index b31f802a85450..0000000000000 --- a/lld/test/ELF/dtlto/imports.test +++ /dev/null @@ -1,51 +0,0 @@ -# REQUIRES: x86 - -## Check that DTLTO creates imports lists if requested. - -RUN: rm -rf %t && split-file %s %t && cd %t - -RUN: opt -thinlto-bc t1.ll -o t1.bc -RUN: opt -thinlto-bc t2.ll -o t2.bc - -## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o -RUN: llc t2.ll --filetype=obj -o t2.o - -## Common command-line arguments. Note that mock.py does not do any compilation; -## instead, it simply writes the contents of the object files supplied on the -## command line into the output object files in job order. -RUN: echo "t1.bc t2.bc \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ -RUN: --thinlto-distributor-arg=t1.o \ -RUN: --thinlto-distributor-arg=t2.o" > l.rsp - -## Check that imports files are not created normally. -RUN: ld.lld @l.rsp -RUN: ls | FileCheck %s --check-prefix=NOIMPORTSFILES -NOIMPORTSFILES-NOT: .imports - -## Check that imports files are created with --thinlto-emit-imports-files. -RUN: ld.lld @l.rsp --thinlto-emit-imports-files -RUN: ls | sort | FileCheck %s --check-prefix=IMPORTSFILES -IMPORTSFILES: {{^}}t1.bc.imports{{$}} -IMPORTSFILES: {{^}}t2.bc.imports{{$}} - -#--- t1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t1() { - ret void -} - -#--- t2.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -declare void @t1(...) - -define void @t2() { - call void (...) @t1() - ret void -} diff --git a/lld/test/ELF/dtlto/index.test b/lld/test/ELF/dtlto/index.test deleted file mode 100644 index e53ceb5d2d568..0000000000000 --- a/lld/test/ELF/dtlto/index.test +++ /dev/null @@ -1,43 +0,0 @@ -# REQUIRES: x86 - -## Check that DTLTO creates individual summary index files if requested. - -RUN: rm -rf %t && split-file %s %t && cd %t - -## Generate ThinLTO bitcode files. -RUN: opt -thinlto-bc t1.ll -o t1.bc -RUN: opt -thinlto-bc t1.ll -o t2.bc - -## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o - -## Use a response file for the common command-line arguments. -## Note that mock.py does not perform any compilation; instead, it copies the -## contents of the specified object files into the output object files, in the -## order the jobs are received. -## The "--start-lib/--end-lib" options are used to exercise the special case -## where unused lazy object inputs result in empty index files. -RUN: echo "t1.bc --start-lib t2.bc --end-lib \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ -RUN: --thinlto-distributor-arg=t1.o \ -RUN: --thinlto-distributor-arg=t2.o" > l.rsp - -## Check that index files are not created normally. -RUN: ld.lld @l.rsp -RUN: ls | FileCheck %s --check-prefix=NOINDEXFILES -NOINDEXFILES-NOT: .thinlto.bc - -## Check that index files are created with --thinlto-emit-index-files. -RUN: ld.lld @l.rsp --thinlto-emit-index-files -RUN: ls | sort | FileCheck %s --check-prefix=INDEXFILES -INDEXFILES: {{^}}t1.bc.thinlto.bc{{$}} -INDEXFILES: {{^}}t2.bc.thinlto.bc{{$}} - -#--- t1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t1() { - ret void -} diff --git a/lld/test/ELF/dtlto/save-temps.test b/lld/test/ELF/dtlto/save-temps.test deleted file mode 100644 index e56b3c4489536..0000000000000 --- a/lld/test/ELF/dtlto/save-temps.test +++ /dev/null @@ -1,39 +0,0 @@ -# REQUIRES: x86 - -## Check that DTLTO responds to --save-temps. - -RUN: rm -rf %t && split-file %s %t && cd %t - -## Generate ThinLTO bitcode. -RUN: opt -thinlto-bc t1.ll -o t1.bc - -## Generate object files for mock.py to return. -RUN: llc t1.ll --filetype=obj -o t1.o - -## Use a response file for common command-line arguments. -## Note that mock.py does not perform any compilation; instead, it simply writes -## the contents of the object files supplied on the command line into the output -## object files in job order. -RUN: echo "t1.bc -o my.elf \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ -RUN: --thinlto-distributor-arg=t1.o" > l.rsp - -## Check that DTLTO temporary files are removed by default. -RUN: ld.lld @l.rsp -RUN: ls | FileCheck %s --check-prefix=REMOVED -REMOVED-NOT: .json - -## Check that DTLTO temporary files are retained with --save-temps. Note that -## DTLTO temporary object files include a PID component. -RUN: ld.lld @l.rsp --save-temps -RUN: ls | FileCheck %s --check-prefix=RETAINED -RETAINED: my.[[#]].dist-file.json - -#--- t1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t1() { - ret void -} From af40a1e73fa8482fbfe5b7cbc315ff65490e76a9 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 16:43:15 +0100 Subject: [PATCH 14/18] Remove empty.test --- lld/test/ELF/dtlto/empty.test | 42 ----------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 lld/test/ELF/dtlto/empty.test diff --git a/lld/test/ELF/dtlto/empty.test b/lld/test/ELF/dtlto/empty.test deleted file mode 100644 index c79a80f854c71..0000000000000 --- a/lld/test/ELF/dtlto/empty.test +++ /dev/null @@ -1,42 +0,0 @@ -# REQUIRES: x86 - -## Check that DTLTO options are a no-op if no thinLTO is performed. - -RUN: rm -rf %t && split-file %s %t && cd %t - -RUN: opt t1.ll -o t1.o -RUN: opt t2.ll -o t2.o - -## Common command-line arguments. Note that mock.py does not do any compilation; -## instead, it simply writes the contents of the object files supplied on the -## command line into the output object files in job order. -RUN: echo "t1.o t2.o \ -RUN: --thinlto-distributor=%python \ -RUN: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py \ -RUN: --thinlto-distributor-arg=no-exist1.o \ -RUN: --thinlto-distributor-arg=no-exist2.o" > l.rsp - -## Check linking succeeds when all input files are Full LTO. -RUN: ld.lld @l.rsp - -RUN: llc -filetype=obj t1.ll -o t1.o -RUN: llc -filetype=obj t2.ll -o t2.o - -## Check linking succeeds when all input files are relocatable files. -RUN: ld.lld @l.rsp - -#--- t1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t1() { - ret void -} - -#--- t2.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @t2() { - ret void -} From 47cd97ed8ec01a1f3868592fd066dd1bbd211a10 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 16:45:56 +0100 Subject: [PATCH 15/18] Simplify lld/test/ELF/dtlto/partitions.test --- lld/test/ELF/dtlto/partitions.test | 41 ++++++++---------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/lld/test/ELF/dtlto/partitions.test b/lld/test/ELF/dtlto/partitions.test index 30c02aafe9153..fbcbc0713ce23 100644 --- a/lld/test/ELF/dtlto/partitions.test +++ b/lld/test/ELF/dtlto/partitions.test @@ -4,14 +4,17 @@ RUN: rm -rf %t && split-file %s %t && cd %t -## Compile bitcode. -RUN: llvm-as -o full.bc full.ll -RUN: opt -thinlto-bc thin1.ll -o thin1.bc -RUN: opt -thinlto-bc thin2.ll -o thin2.bc +RUN: sed 's/@f/@t1/g' f.ll > t1.ll +RUN: sed 's/@f/@t2/g' f.ll > t2.ll + +## Generate bitcode. +RUN: opt f.ll -o full.bc +RUN: opt -thinlto-bc t1.ll -o thin1.bc +RUN: opt -thinlto-bc t2.ll -o thin2.bc ## Generate object files for mock.py to return. -RUN: llc thin1.ll --filetype=obj -o thin1.o -RUN: llc thin2.ll --filetype=obj -o thin2.o +RUN: llc t1.ll --filetype=obj -o thin1.o +RUN: llc t2.ll --filetype=obj -o thin2.o ## Link with 3 LTO partitions. RUN: ld.lld full.bc thin1.bc thin2.bc \ @@ -28,32 +31,10 @@ RUN: ls | sort | FileCheck %s CHECK: {{^}}thin1.3.[[PID:[a-zA-Z0-9_]+]].native.o{{$}} CHECK: {{^}}thin2.4.[[PID]].native.o{{$}} -#--- full.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @foo() { - call void @bar() - ret void -} - -define void @bar() { - call void @foo() - ret void -} - -#--- thin1.ll -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @baz() { - ret void -} - -#--- thin2.ll +#--- f.ll target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -define void @_start() { +define void @f() { ret void } From ef5f7f6f092aad3c08e067701be60a5a7b0856d6 Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 17:11:15 +0100 Subject: [PATCH 16/18] Move x86 requirement cross-project-test into lit.local.cfg All cross-project DTLTO tests will use x86 for now. --- cross-project-tests/dtlto/dtlto.c | 3 ++- cross-project-tests/dtlto/lit.local.cfg | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cross-project-tests/dtlto/dtlto.c b/cross-project-tests/dtlto/dtlto.c index 0ebdc6b59da50..6c43d3ed32828 100644 --- a/cross-project-tests/dtlto/dtlto.c +++ b/cross-project-tests/dtlto/dtlto.c @@ -1,7 +1,8 @@ -// REQUIRES: x86-registered-target,ld.lld +// REQUIRES: ld.lld /// Simple test that DTLTO works with a single input bitcode file and that /// --save-temps can be applied to the remote compilation. + // RUN: rm -rf %t && mkdir %t && cd %t // RUN: %clang --target=x86_64-linux-gnu -c -flto=thin %s diff --git a/cross-project-tests/dtlto/lit.local.cfg b/cross-project-tests/dtlto/lit.local.cfg index 530f4c01646ff..38eed282704c6 100644 --- a/cross-project-tests/dtlto/lit.local.cfg +++ b/cross-project-tests/dtlto/lit.local.cfg @@ -1,2 +1,5 @@ -if "clang" not in config.available_features: +if any( + f not in config.available_features + for f in ("clang", "x86-registered-target") +): config.unsupported = True From a9449ee571c264c2abd6714824642ae51c77682f Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Tue, 1 Jul 2025 17:24:58 +0100 Subject: [PATCH 17/18] Rename the dtlto.c test to ld-dtlto.c since it specifically tests ld.lld This prepares the test suite for future additions that may cover other linkers such as lld-link.exe. --- cross-project-tests/dtlto/{dtlto.c => ld-dtlto.c} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename cross-project-tests/dtlto/{dtlto.c => ld-dtlto.c} (94%) diff --git a/cross-project-tests/dtlto/dtlto.c b/cross-project-tests/dtlto/ld-dtlto.c similarity index 94% rename from cross-project-tests/dtlto/dtlto.c rename to cross-project-tests/dtlto/ld-dtlto.c index 6c43d3ed32828..3ee962346bd4a 100644 --- a/cross-project-tests/dtlto/dtlto.c +++ b/cross-project-tests/dtlto/ld-dtlto.c @@ -5,7 +5,7 @@ // RUN: rm -rf %t && mkdir %t && cd %t -// RUN: %clang --target=x86_64-linux-gnu -c -flto=thin %s +// RUN: %clang --target=x86_64-linux-gnu -c -flto=thin %s -o dtlto.o // RUN: ld.lld dtlto.o \ // RUN: --thinlto-distributor=%python \ From b28d34ecfa20d7caa7befa788c498aecd1217f0c Mon Sep 17 00:00:00 2001 From: Dunbobbin Date: Wed, 2 Jul 2025 00:56:35 +0100 Subject: [PATCH 18/18] Fix missing word in comment sentence --- lld/test/ELF/dtlto/files.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lld/test/ELF/dtlto/files.test b/lld/test/ELF/dtlto/files.test index 9a8af17ebcc26..727ef53c7f5b5 100644 --- a/lld/test/ELF/dtlto/files.test +++ b/lld/test/ELF/dtlto/files.test @@ -1,7 +1,7 @@ # REQUIRES: x86 -## Check that the LLD options --save-temps, --thinlto-emit-index-files, -## and --thinlto-emit-imports-files for DTLTO. +## Test that the LLD options --save-temps, --thinlto-emit-index-files, +## and --thinlto-emit-imports-files function correctly with DTLTO. RUN: rm -rf %t && split-file %s %t && cd %t