Skip to content

Commit c333a8e

Browse files
committed
[DTLTO][LLVM] Translate some LTO configuration state into clang options.
Intentionally minimal for now. Additional state translation will be added in future commits.
1 parent 3cd5f60 commit c333a8e

File tree

8 files changed

+251
-4
lines changed

8 files changed

+251
-4
lines changed

cross-project-tests/CMakeLists.txt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ set(CROSS_PROJECT_TEST_DEPS
1919
FileCheck
2020
check-gdb-llvm-support
2121
count
22-
llvm-dwarfdump
2322
llvm-config
23+
llvm-dwarfdump
24+
llvm-lto2
2425
llvm-objdump
25-
split-file
2626
not
27+
opt
28+
split-file
2729
)
2830

2931
if ("clang" IN_LIST LLVM_ENABLE_PROJECTS)
@@ -94,6 +96,13 @@ add_lit_testsuite(check-cross-amdgpu "Running AMDGPU cross-project tests"
9496
DEPENDS clang
9597
)
9698

99+
# DTLTO tests.
100+
add_lit_testsuite(check-cross-dtlto "Running DTLTO cross-project tests"
101+
${CMAKE_CURRENT_BINARY_DIR}/dtlto
102+
EXCLUDE_FROM_CHECK_ALL
103+
DEPENDS ${CROSS_PROJECT_TEST_DEPS}
104+
)
105+
97106
# Add check-cross-project-* targets.
98107
add_lit_testsuites(CROSS_PROJECT ${CMAKE_CURRENT_SOURCE_DIR}
99108
DEPENDS ${CROSS_PROJECT_TEST_DEPS}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Tests for DTLTO (integrated distributed ThinLTO) functionality.
2+
3+
These are integration tests as DTLTO invokes `clang` for code-generation.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
;; Check that the expected Clang arguments are generated by DTLTO for the
2+
;; backend compilations and are accepted by Clang.
3+
4+
; RUN: rm -rf %t && split-file %s %t && cd %t
5+
6+
;; Generate bitcode files with a summary index.
7+
; RUN: opt -thinlto-bc x86_64-unknown-linux-gnu.ll -o x86_64-unknown-linux-gnu.bc
8+
; RUN: opt -thinlto-bc x86_64-pc-windows-msvc.ll -o x86_64-pc-windows-msvc.bc
9+
10+
11+
;; Check that any invalid arguments would cause a Clang error. This property is
12+
;; relied on by the actual testcases later in this test.
13+
; RUN: not %clang -x ir x86_64-unknown-linux-gnu.ll \
14+
; RUN: -invalid-incorrect-not-an-option 2>&1 | FileCheck %s --check-prefix=SANITY1
15+
; SANITY1: unknown argument: '-invalid-incorrect-not-an-option'
16+
17+
18+
;; Define a substitution used to simplify the testcases.
19+
; DEFINE: %{distributor} = dummy
20+
; DEFINE: %{extra_flags} = dummy
21+
; DEFINE: %{triple} = dummy
22+
; DEFINE: %{command} = llvm-lto2 run \
23+
; DEFINE: -thinlto-distributor-arg=%llvm_src_root/utils/dtlto/%{distributor} \
24+
; DEFINE: -thinlto-remote-opt-tool-arg=-Wunused-command-line-argument \
25+
; DEFINE: @%{triple}.rsp %{extra_flags}
26+
27+
28+
;; Write common arguments to a response files.
29+
30+
; RUN: echo "x86_64-unknown-linux-gnu.bc -o x86_64-unknown-linux-gnu.o \
31+
; RUN: -dtlto \
32+
; RUN: -dtlto-remote-opt-tool=%clang \
33+
; RUN: -thinlto-remote-opt-tool-arg=-Werror \
34+
; RUN: -dtlto-distributor=%python \
35+
; RUN: -r=x86_64-unknown-linux-gnu.bc,globalfunc1,plx" > x86_64-unknown-linux-gnu.rsp
36+
37+
; RUN: echo "x86_64-pc-windows-msvc.bc -o x86_64-pc-windows-msvc.o \
38+
; RUN: -dtlto \
39+
; RUN: -dtlto-remote-opt-tool=%clang \
40+
; RUN: -thinlto-remote-opt-tool-arg=-Werror \
41+
; RUN: -thinlto-remote-opt-tool-arg=-Wno-override-module \
42+
; RUN: -dtlto-distributor=%python \
43+
; RUN: -r=x86_64-pc-windows-msvc.bc,globalfunc2,plx" > x86_64-pc-windows-msvc.rsp
44+
45+
46+
;; Check that boolean configuration states are translated as expected and Clang
47+
;; accepts them.
48+
49+
; RUN: echo " \
50+
; RUN: --addrsig=1 \
51+
; RUN: -function-sections=1 \
52+
; RUN: -data-sections=1" > on.rsp
53+
54+
; RUN: echo " \
55+
; RUN: --addrsig=0 \
56+
; RUN: -function-sections=0 \
57+
; RUN: -data-sections=0" > off.rsp
58+
59+
;; Perform DTLTO with configuration state set.
60+
; REDEFINE: %{extra_flags} = @on.rsp
61+
; REDEFINE: %{distributor} = local.py
62+
; REDEFINE: %{triple} = x86_64-unknown-linux-gnu
63+
; RUN: %{command}
64+
; REDEFINE: %{distributor} = validate.py
65+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=ON \
66+
; RUN: --implicit-check-not=-no-pgo-warn-mismatch
67+
; ON-DAG: "-faddrsig"
68+
; ON-DAG: "-ffunction-sections"
69+
; ON-DAG: "-fdata-sections"
70+
71+
;; Perform DTLTO with configuration state unset.
72+
; REDEFINE: %{extra_flags} = @off.rsp
73+
; REDEFINE: %{distributor} = local.py
74+
; RUN: %{command}
75+
; REDEFINE: %{distributor} = validate.py
76+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=OFF
77+
; OFF-NOT: --implicit-check-not=--faddrsig
78+
; OFF-NOT: --implicit-check-not=--ffunction-sections
79+
; OFF-NOT: --implicit-check-not=--fdata-sections
80+
; OFF-NOT: --implicit-check-not=-no-pgo-warn-mismatch
81+
82+
83+
;; Check optimisation level.
84+
85+
; RUN: llvm-lto2 run \
86+
; RUN: -thinlto-distributor-arg=%llvm_src_root/utils/dtlto/local.py \
87+
; RUN: @x86_64-unknown-linux-gnu.rsp \
88+
; RUN: -O3
89+
90+
; RUN: not llvm-lto2 run \
91+
; RUN: -thinlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py \
92+
; RUN: @x86_64-unknown-linux-gnu.rsp \
93+
; RUN: -O3 2>&1 | FileCheck %s --check-prefix=OPTLEVEL
94+
; OPTLEVEL-DAG: "-O3"
95+
96+
97+
;; Check relocation model.
98+
99+
; REDEFINE: %{extra_flags} = -relocation-model=pic
100+
; REDEFINE: %{distributor} = local.py
101+
; RUN: %{command}
102+
; REDEFINE: %{distributor} = validate.py
103+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=PIC
104+
; PIC: -fpic
105+
106+
107+
; REDEFINE: %{extra_flags} = -relocation-model=pic
108+
; REDEFINE: %{distributor} = local.py
109+
; REDEFINE: %{triple} = x86_64-pc-windows-msvc
110+
; RUN: %{command}
111+
; REDEFINE: %{distributor} = validate.py
112+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=NOPIC
113+
; REDEFINE: %{triple} = x86_64-unknown-linux-gnu
114+
; NOPIC-NOT: -fpic
115+
116+
;; Check specifying a sample profile.
117+
; REDEFINE: %{extra_flags} = --lto-sample-profile-file="missing.profdata"
118+
; REDEFINE: %{distributor} = local.py
119+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=SAMPLE_PROFILE_ERR
120+
; SAMPLE_PROFILE_ERR: no such file or directory: 'missing.profdata'
121+
; REDEFINE: %{distributor} = validate.py
122+
; RUN: not %{command} 2>&1 | FileCheck %s --check-prefix=SAMPLE_PROFILE
123+
; SAMPLE_PROFILE-DAG: "-fprofile-sample-use=missing.profdata"
124+
125+
126+
;--- x86_64-unknown-linux-gnu.ll
127+
128+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
129+
target triple = "x86_64-unknown-linux-gnu"
130+
131+
define void @globalfunc1() {
132+
entry:
133+
ret void
134+
}
135+
136+
;--- x86_64-pc-windows-msvc.ll
137+
138+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
139+
target triple = "x86_64-pc-windows-msvc"
140+
141+
define void @globalfunc2() {
142+
entry:
143+
ret void
144+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if any(feature not in config.available_features for feature in ["clang", "llvm-lto2", "opt"]):
2+
config.unsupported = True

cross-project-tests/lit.cfg.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
2020

2121
# suffixes: A list of file extensions to treat as test files.
22-
config.suffixes = [".c", ".cl", ".cpp", ".m"]
22+
config.suffixes = [".c", ".cl", ".cpp", ".m", ".ll"]
2323

2424
# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
2525
# subdirectories contain auxiliary inputs for various tests in their parent
@@ -96,6 +96,9 @@ def get_required_attr(config, attr_name):
9696
if lldb_path is not None:
9797
config.available_features.add("lldb")
9898

99+
for tool in ["llvm-lto2", "opt"]:
100+
if llvm_config.use_llvm_tool(tool):
101+
config.available_features.add(tool)
99102

100103
def configure_dexter_substitutions():
101104
"""Configure substitutions for host platform and return list of dependencies"""

llvm/lib/LTO/LTO.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2291,6 +2291,62 @@ class OutOfProcessThinBackend : public CGThinBackend {
22912291
return Error::success();
22922292
}
22932293

2294+
// Derive a set of Clang options that will be shared/common for all DTLTO
2295+
// backend compilations. We are intentionally minimal here as these options
2296+
// must remain synchronized with the behavior of Clang. DTLTO does not support
2297+
// all the features available with in-process LTO. More features are expected
2298+
// to be added over time. Users can specify Clang options directly if a
2299+
// feature is not supported. Note that explicitly specified options that imply
2300+
// additional input or output file dependencies must be communicated to the
2301+
// distribution system, potentially by setting extra options on the
2302+
// distributor program.
2303+
// TODO: If this strategy of deriving options proves insufficient, alternative
2304+
// approaches should be considered, such as:
2305+
// - A serialization/deserialization format for LTO configuration.
2306+
// - Modifying LLD to be the tool that performs the backend compilations.
2307+
void buildCommonRemoteOptToolOptions() {
2308+
const lto::Config &C = Conf;
2309+
auto &Ops = CodegenOptions;
2310+
llvm::Triple TT{Jobs.front().Triple};
2311+
2312+
Ops.push_back(Saver.save("-O" + Twine(C.OptLevel)));
2313+
2314+
if (C.Options.EmitAddrsig)
2315+
Ops.push_back("-faddrsig");
2316+
if (C.Options.FunctionSections)
2317+
Ops.push_back("-ffunction-sections");
2318+
if (C.Options.DataSections)
2319+
Ops.push_back("-fdata-sections");
2320+
2321+
if (C.RelocModel == Reloc::PIC_)
2322+
// Clang doesn't have -fpic for all triples.
2323+
if (!TT.isOSBinFormatCOFF())
2324+
Ops.push_back("-fpic");
2325+
2326+
// Turn on/off warnings about profile cfg mismatch (default on)
2327+
// --lto-pgo-warn-mismatch.
2328+
if (!C.PGOWarnMismatch) {
2329+
Ops.push_back("-mllvm");
2330+
Ops.push_back("-no-pgo-warn-mismatch");
2331+
}
2332+
2333+
// Enable sample-based profile guided optimizations.
2334+
// Sample profile file path --lto-sample-profile=<value>.
2335+
if (!C.SampleProfile.empty()) {
2336+
Ops.push_back(
2337+
Saver.save("-fprofile-sample-use=" + Twine(C.SampleProfile)));
2338+
AdditionalInputs.insert(C.SampleProfile);
2339+
}
2340+
2341+
// We don't know which of options will be used by Clang.
2342+
Ops.push_back("-Wno-unused-command-line-argument");
2343+
2344+
// Forward any supplied options.
2345+
if (!ThinLTORemoteOptToolArgs.empty())
2346+
for (auto &a : ThinLTORemoteOptToolArgs)
2347+
Ops.push_back(a);
2348+
}
2349+
22942350
// Generates a JSON file describing the backend compilations, for the
22952351
// distributor.
22962352
bool emitDistributorJson(StringRef DistributorJson) {
@@ -2327,7 +2383,7 @@ class OutOfProcessThinBackend : public CGThinBackend {
23272383
JOS.value(Array{"summary_index", "-fthinlto-index=", 0});
23282384
JOS.value(Saver.save("--target=" + Twine(Jobs.front().Triple)));
23292385

2330-
for (const auto &A : ThinLTORemoteOptToolArgs)
2386+
for (const auto &A : CodegenOptions)
23312387
JOS.value(A);
23322388
});
23332389
});
@@ -2391,6 +2447,8 @@ class OutOfProcessThinBackend : public CGThinBackend {
23912447
return make_error<StringError>(BCError + "all triples must be consistent",
23922448
inconvertibleErrorCode());
23932449

2450+
buildCommonRemoteOptToolOptions();
2451+
23942452
SString JsonFile = sys::path::parent_path(LinkerOutputFile);
23952453
sys::path::append(JsonFile, sys::path::stem(LinkerOutputFile) + "." + UID +
23962454
".dist-file.json");

llvm/test/ThinLTO/X86/dtlto/json.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ CHECK-NEXT: "-fthinlto-index="
4343
CHECK-NEXT: 0
4444
CHECK-NEXT: ]
4545
CHECK: "--target=x86_64-unknown-linux-gnu"
46+
CHECK: "-O2",
47+
CHECK: "-fpic"
48+
CHECK: "-Wno-unused-command-line-argument"
4649
CHECK: "--rota1=10"
4750
CHECK: "--rota2=20"
4851

llvm/utils/dtlto/local.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import subprocess
2+
import sys
3+
import json
4+
from pathlib import Path
5+
6+
if __name__ == "__main__":
7+
# Load the DTLTO information from the input JSON file.
8+
data = json.loads(Path(sys.argv[-1]).read_bytes())
9+
10+
# Iterate over the jobs and execute the codegen tool.
11+
for job in data["jobs"]:
12+
jobargs = []
13+
for arg in data["common"]["args"]:
14+
if isinstance(arg, list):
15+
# arg is a "template", into which an external filename is to be
16+
# inserted. The first element of arg names an array of strings
17+
# in the job. The remaining elements of arg are either indices
18+
# into the array or literal strings.
19+
files, rest = job[arg[0]], arg[1:]
20+
jobargs.append(
21+
"".join(files[x] if isinstance(x, int) else x for x in rest)
22+
)
23+
else:
24+
jobargs.append(arg)
25+
subprocess.check_call(jobargs)

0 commit comments

Comments
 (0)