[llvm] [DTLTO] Add remote compiler option forwarding coverage (PR #208589)
Ben Dunbobbin via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 00:07:25 PDT 2026
https://github.com/bd1976bris updated https://github.com/llvm/llvm-project/pull/208589
>From 4c0041399f0a14af60f32526ac069cffce3c3b71 Mon Sep 17 00:00:00 2001
From: Ben <ben.dunbobbin at sony.com>
Date: Fri, 10 Jul 2026 00:58:30 +0100
Subject: [PATCH 1/3] Add DTLTO remote option forwarding coverage
Add a cross-project DTLTO test that checks the existing LTO configuration
state serialized into the remote Clang command line. The test uses the
validate.py distributor to inspect the generated DTLTO JSON.
Cover all the existing forwarded options.
Add paired negative checks for optional flags so the test also verifies they
are not emitted when the corresponding configuration state is not set.
---
cross-project-tests/CMakeLists.txt | 1 +
cross-project-tests/dtlto/remote-options.test | 95 +++++++++++++++++++
2 files changed, 96 insertions(+)
create mode 100644 cross-project-tests/dtlto/remote-options.test
diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt
index 4dab5d3d51fd6..85102065e79e6 100644
--- a/cross-project-tests/CMakeLists.txt
+++ b/cross-project-tests/CMakeLists.txt
@@ -26,6 +26,7 @@ set(CROSS_PROJECT_TEST_DEPS
llvm-config
llvm-dis
llvm-dwarfdump
+ llvm-lto2
llvm-modextract
llvm-objdump
not
diff --git a/cross-project-tests/dtlto/remote-options.test b/cross-project-tests/dtlto/remote-options.test
new file mode 100644
index 0000000000000..f1e8b57564a01
--- /dev/null
+++ b/cross-project-tests/dtlto/remote-options.test
@@ -0,0 +1,95 @@
+REQUIRES: ld.lld
+
+## Check that DTLTO serializes LTO configuration state into the remote Clang
+## command line.
+
+RUN: rm -rf %t && split-file %s %t && cd %t
+
+RUN: %clang --target=x86_64-unknown-linux-gnu -flto=thin -c test.c -o test.o
+RUN: %clang --target=x86_64-pc-windows-msvc -flto=thin -c test.c -o coff.o
+RUN: touch profile.prof
+
+DEFINE: %{base} = not llvm-lto2 run \
+DEFINE: -dtlto-distributor=%python \
+DEFINE: -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
+DEFINE: -dtlto-compiler=%clang \
+DEFINE: -o test.out
+
+DEFINE: %{command} = %{base} \
+DEFINE: test.o \
+DEFINE: -r=test.o,foo,px
+
+DEFINE: %{command-coff} = %{base} \
+DEFINE: coff.o \
+DEFINE: -r=coff.o,foo,px
+
+DEFINE: %{lld} = not ld.lld test.o \
+DEFINE: -o test.elf \
+DEFINE: --thinlto-distributor=%python \
+DEFINE: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
+DEFINE: --thinlto-remote-compiler=%clang
+
+ARGS: "args": [
+
+## Optimization level.
+RUN: %{command} -O0 2>&1 | FileCheck %s --check-prefixes=ARGS,O0,ERR
+RUN: %{command} -O3 2>&1 | FileCheck %s --check-prefixes=ARGS,O3,ERR
+O0: "-O0"
+O3: "-O3"
+
+## Address-significance table, function sections, and data sections.
+RUN: %{command} -addrsig -function-sections -data-sections 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,SECTIONS,ERR
+SECTIONS: "-faddrsig"
+SECTIONS: "-ffunction-sections"
+SECTIONS: "-fdata-sections"
+
+RUN: %{command} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SECTIONS,ERR
+NO-SECTIONS-NOT: "-faddrsig"
+NO-SECTIONS-NOT: "-ffunction-sections"
+NO-SECTIONS-NOT: "-fdata-sections"
+
+## PIC is forwarded as -fpic for ELF targets but not for COFF targets because
+## Clang does not accept -fpic for every target.
+RUN: %{command} -relocation-model=pic 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,PIC,ERR
+PIC: "-fpic"
+
+RUN: %{command} -relocation-model=static 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,NO-PIC,ERR
+NO-PIC-NOT: "-fpic"
+
+RUN: %{command-coff} -relocation-model=pic -O3 2>&1 | \
+RUN: FileCheck %s --check-prefixes=COFF-PIC,ERR
+COFF-PIC-NOT: "-fpic"
+
+## Sample profile forwarding and common-input serialization.
+RUN: %{command} -lto-sample-profile-file=profile.prof 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,SAMPLE,ERR
+SAMPLE: "-fprofile-sample-use=profile.prof"
+SAMPLE: "inputs": [
+SAMPLE: "profile.prof"
+
+RUN: %{command} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SAMPLE,ERR
+NO-SAMPLE-NOT: "-fprofile-sample-use=profile.prof"
+NO-SAMPLE-NOT: "profile.prof"
+
+## PGO warning mismatch control is an LLD-driver option rather than an
+## llvm-lto2 option, so check it through the ELF linker.
+RUN: %{lld} --no-lto-pgo-warn-mismatch 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,PGO-WARN,ERR
+PGO-WARN: "-mllvm"
+PGO-WARN-NEXT: "-no-pgo-warn-mismatch"
+
+RUN: %{lld} 2>&1 | \
+RUN: FileCheck %s --check-prefixes=ARGS,NO-PGO-WARN,ERR
+NO-PGO-WARN-NOT: "-no-pgo-warn-mismatch"
+
+## The validate.py distributor prints the DTLTO JSON and then exits without
+## producing native objects, so each llvm-lto2 command is expected to fail after
+## the JSON has been emitted. We check that we saw the expected failure mode
+## and not some other failure.
+ERR: DTLTO backend compilation: cannot open native object file:
+
+#--- test.c
+void foo(void) {}
>From 1a98600040cc4686a387ecaad3c257387eeaa5b4 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Fri, 10 Jul 2026 10:45:51 +0100
Subject: [PATCH 2/3] Update remote-options.test
Minor improvements
---
cross-project-tests/dtlto/remote-options.test | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/cross-project-tests/dtlto/remote-options.test b/cross-project-tests/dtlto/remote-options.test
index f1e8b57564a01..7c28087bdf0d0 100644
--- a/cross-project-tests/dtlto/remote-options.test
+++ b/cross-project-tests/dtlto/remote-options.test
@@ -15,19 +15,14 @@ DEFINE: -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
DEFINE: -dtlto-compiler=%clang \
DEFINE: -o test.out
-DEFINE: %{command} = %{base} \
-DEFINE: test.o \
-DEFINE: -r=test.o,foo,px
-
-DEFINE: %{command-coff} = %{base} \
-DEFINE: coff.o \
-DEFINE: -r=coff.o,foo,px
-
DEFINE: %{lld} = not ld.lld test.o \
-DEFINE: -o test.elf \
DEFINE: --thinlto-distributor=%python \
DEFINE: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
-DEFINE: --thinlto-remote-compiler=%clang
+DEFINE: --thinlto-remote-compiler=%clang \
+DEFINE: -o test.elf
+
+DEFINE: %{command} = %{base} test.o -r=test.o,foo,px
+DEFINE: %{command-coff} = %{base} coff.o -r=coff.o,foo,px
ARGS: "args": [
@@ -59,7 +54,7 @@ RUN: %{command} -relocation-model=static 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,NO-PIC,ERR
NO-PIC-NOT: "-fpic"
-RUN: %{command-coff} -relocation-model=pic -O3 2>&1 | \
+RUN: %{command-coff} -relocation-model=pic 2>&1 | \
RUN: FileCheck %s --check-prefixes=COFF-PIC,ERR
COFF-PIC-NOT: "-fpic"
>From 0ace628195604f28fcd383a3e727fc4ffe46ddf0 Mon Sep 17 00:00:00 2001
From: Ben <ben.dunbobbin at sony.com>
Date: Wed, 15 Jul 2026 07:55:39 +0100
Subject: [PATCH 3/3] Address review comments
---
cross-project-tests/dtlto/remote-options.test | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/cross-project-tests/dtlto/remote-options.test b/cross-project-tests/dtlto/remote-options.test
index 7c28087bdf0d0..e808adf9cf9e1 100644
--- a/cross-project-tests/dtlto/remote-options.test
+++ b/cross-project-tests/dtlto/remote-options.test
@@ -1,71 +1,74 @@
REQUIRES: ld.lld
-## Check that DTLTO serializes LTO configuration state into the remote Clang
+## Check that DTLTO passes LTO configuration to the remote Clang via the
## command line.
RUN: rm -rf %t && split-file %s %t && cd %t
-RUN: %clang --target=x86_64-unknown-linux-gnu -flto=thin -c test.c -o test.o
+RUN: %clang --target=x86_64-unknown-linux-gnu -flto=thin -c test.c -o elf.o
RUN: %clang --target=x86_64-pc-windows-msvc -flto=thin -c test.c -o coff.o
RUN: touch profile.prof
+## The validate.py distributor prints the DTLTO JSON and then exits without
+## producing native objects, so each llvm-lto2 command is expected to fail after
+## the JSON has been emitted.
DEFINE: %{base} = not llvm-lto2 run \
DEFINE: -dtlto-distributor=%python \
DEFINE: -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
DEFINE: -dtlto-compiler=%clang \
DEFINE: -o test.out
-DEFINE: %{lld} = not ld.lld test.o \
+DEFINE: %{lld} = not ld.lld elf.o \
DEFINE: --thinlto-distributor=%python \
DEFINE: --thinlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
DEFINE: --thinlto-remote-compiler=%clang \
DEFINE: -o test.elf
-DEFINE: %{command} = %{base} test.o -r=test.o,foo,px
-DEFINE: %{command-coff} = %{base} coff.o -r=coff.o,foo,px
+DEFINE: %{lto2-elf} = %{base} elf.o -r=elf.o,foo,px
+DEFINE: %{lto2-coff} = %{base} coff.o -r=coff.o,foo,px
ARGS: "args": [
## Optimization level.
-RUN: %{command} -O0 2>&1 | FileCheck %s --check-prefixes=ARGS,O0,ERR
-RUN: %{command} -O3 2>&1 | FileCheck %s --check-prefixes=ARGS,O3,ERR
+RUN: %{lto2-elf} -O0 2>&1 | FileCheck %s --check-prefixes=ARGS,O0,ERR
+RUN: %{lto2-elf} -O3 2>&1 | FileCheck %s --check-prefixes=ARGS,O3,ERR
O0: "-O0"
O3: "-O3"
## Address-significance table, function sections, and data sections.
-RUN: %{command} -addrsig -function-sections -data-sections 2>&1 | \
+RUN: %{lto2-elf} -addrsig -function-sections -data-sections 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,SECTIONS,ERR
SECTIONS: "-faddrsig"
SECTIONS: "-ffunction-sections"
SECTIONS: "-fdata-sections"
-RUN: %{command} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SECTIONS,ERR
+RUN: %{lto2-elf} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SECTIONS,ERR
NO-SECTIONS-NOT: "-faddrsig"
NO-SECTIONS-NOT: "-ffunction-sections"
NO-SECTIONS-NOT: "-fdata-sections"
## PIC is forwarded as -fpic for ELF targets but not for COFF targets because
## Clang does not accept -fpic for every target.
-RUN: %{command} -relocation-model=pic 2>&1 | \
+RUN: %{lto2-elf} -relocation-model=pic 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,PIC,ERR
PIC: "-fpic"
-RUN: %{command} -relocation-model=static 2>&1 | \
+RUN: %{lto2-elf} -relocation-model=static 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,NO-PIC,ERR
NO-PIC-NOT: "-fpic"
-RUN: %{command-coff} -relocation-model=pic 2>&1 | \
+RUN: %{lto2-coff} -relocation-model=pic 2>&1 | \
RUN: FileCheck %s --check-prefixes=COFF-PIC,ERR
COFF-PIC-NOT: "-fpic"
## Sample profile forwarding and common-input serialization.
-RUN: %{command} -lto-sample-profile-file=profile.prof 2>&1 | \
+RUN: %{lto2-elf} -lto-sample-profile-file=profile.prof 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,SAMPLE,ERR
SAMPLE: "-fprofile-sample-use=profile.prof"
SAMPLE: "inputs": [
SAMPLE: "profile.prof"
-RUN: %{command} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SAMPLE,ERR
+RUN: %{lto2-elf} 2>&1 | FileCheck %s --check-prefixes=ARGS,NO-SAMPLE,ERR
NO-SAMPLE-NOT: "-fprofile-sample-use=profile.prof"
NO-SAMPLE-NOT: "profile.prof"
@@ -80,10 +83,7 @@ RUN: %{lld} 2>&1 | \
RUN: FileCheck %s --check-prefixes=ARGS,NO-PGO-WARN,ERR
NO-PGO-WARN-NOT: "-no-pgo-warn-mismatch"
-## The validate.py distributor prints the DTLTO JSON and then exits without
-## producing native objects, so each llvm-lto2 command is expected to fail after
-## the JSON has been emitted. We check that we saw the expected failure mode
-## and not some other failure.
+## Check for the expected error from the use of validate.py.
ERR: DTLTO backend compilation: cannot open native object file:
#--- test.c
More information about the llvm-commits
mailing list