Skip to content

Commit d30b99f

Browse files
committed
Auto merge of #57514 - michaelwoerister:xlto-tests, r=alexcrichton
compiletest: Support opt-in Clang-based run-make tests and use them for testing xLTO. Some cross-language run-make tests need a Clang compiler that matches the LLVM version of `rustc`. Since such a compiler usually isn't available these tests (marked with the `needs-matching-clang` directive) are ignored by default. For some CI jobs we do need these tests to run unconditionally though. In order to support this a `--force-clang-based-tests` flag is added to compiletest. If this flag is specified, `compiletest` will fail if it can't detect an appropriate version of Clang. @rust-lang/infra The PR doesn't yet enable the tests yet. Do you have any recommendation for which jobs to enable them? cc #57438 r? @alexcrichton
2 parents f40aaa6 + b17c10d commit d30b99f

File tree

15 files changed

+175
-21
lines changed

15 files changed

+175
-21
lines changed

config.toml.example

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@
101101
# that your host compiler ships with libc++.
102102
#use-libcxx = true
103103

104+
# The value specified here will be passed as `-DLLVM_USE_LINKER` to CMake.
105+
#use-linker = "lld"
106+
107+
104108
# =============================================================================
105109
# General build configuration options
106110
# =============================================================================

src/bootstrap/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub struct Config {
7777
pub llvm_experimental_targets: String,
7878
pub llvm_link_jobs: Option<u32>,
7979
pub llvm_version_suffix: Option<String>,
80+
pub llvm_use_linker: Option<String>,
8081

8182
pub lld_enabled: bool,
8283
pub lldb_enabled: bool,
@@ -261,6 +262,7 @@ struct Llvm {
261262
cxxflags: Option<String>,
262263
ldflags: Option<String>,
263264
use_libcxx: Option<bool>,
265+
use_linker: Option<String>,
264266
}
265267

266268
#[derive(Deserialize, Default, Clone)]
@@ -527,6 +529,7 @@ impl Config {
527529
config.llvm_cxxflags = llvm.cxxflags.clone();
528530
config.llvm_ldflags = llvm.ldflags.clone();
529531
set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
532+
config.llvm_use_linker = llvm.use_linker.clone();
530533
}
531534

532535
if let Some(ref rust) = toml.rust {

src/bootstrap/native.rs

+4
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ impl Step for Llvm {
234234
cfg.define("LLVM_VERSION_SUFFIX", suffix);
235235
}
236236

237+
if let Some(ref linker) = builder.config.llvm_use_linker {
238+
cfg.define("LLVM_USE_LINKER", linker);
239+
}
240+
237241
if let Some(ref python) = builder.config.python {
238242
cfg.define("PYTHON_EXECUTABLE", python);
239243
}

src/bootstrap/test.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -1088,9 +1088,7 @@ impl Step for Compiletest {
10881088
};
10891089
let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
10901090
// Test against the lldb that was just built.
1091-
builder.llvm_out(target)
1092-
.join("bin")
1093-
.join("lldb")
1091+
builder.llvm_out(target).join("bin").join("lldb")
10941092
} else {
10951093
PathBuf::from("lldb")
10961094
};
@@ -1107,6 +1105,26 @@ impl Step for Compiletest {
11071105
}
11081106
}
11091107

1108+
if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
1109+
match &var.to_string_lossy().to_lowercase()[..] {
1110+
"1" | "yes" | "on" => {
1111+
assert!(builder.config.lldb_enabled,
1112+
"RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \
1113+
be built.");
1114+
let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1115+
cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1116+
}
1117+
"0" | "no" | "off" => {
1118+
// Nothing to do.
1119+
}
1120+
other => {
1121+
// Let's make sure typos don't get unnoticed
1122+
panic!("Unrecognized option '{}' set in \
1123+
RUSTBUILD_FORCE_CLANG_BASED_TESTS", other);
1124+
}
1125+
}
1126+
}
1127+
11101128
// Get paths from cmd args
11111129
let paths = match &builder.config.cmd {
11121130
Subcommand::Test { ref paths, .. } => &paths[..],

src/bootstrap/tool.rs

+27-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::fs;
22
use std::env;
3-
use std::iter;
43
use std::path::PathBuf;
54
use std::process::{Command, exit};
65
use std::collections::HashSet;
@@ -666,27 +665,41 @@ impl<'a> Builder<'a> {
666665

667666
// Add the llvm/bin directory to PATH since it contains lots of
668667
// useful, platform-independent tools
669-
if tool.uses_llvm_tools() {
668+
if tool.uses_llvm_tools() && !self.config.dry_run {
669+
let mut additional_paths = vec![];
670+
670671
if let Some(llvm_bin_path) = self.llvm_bin_path() {
671-
if host.contains("windows") {
672-
// On Windows, PATH and the dynamic library path are the same,
673-
// so we just add the LLVM bin path to lib_path
674-
lib_paths.push(llvm_bin_path);
675-
} else {
676-
let old_path = env::var_os("PATH").unwrap_or_default();
677-
let new_path = env::join_paths(iter::once(llvm_bin_path)
678-
.chain(env::split_paths(&old_path)))
679-
.expect("Could not add LLVM bin path to PATH");
680-
cmd.env("PATH", new_path);
681-
}
672+
additional_paths.push(llvm_bin_path);
673+
}
674+
675+
// If LLD is available, add that too.
676+
if self.config.lld_enabled {
677+
let lld_install_root = self.ensure(native::Lld {
678+
target: self.config.build,
679+
});
680+
681+
let lld_bin_path = lld_install_root.join("bin");
682+
additional_paths.push(lld_bin_path);
683+
}
684+
685+
if host.contains("windows") {
686+
// On Windows, PATH and the dynamic library path are the same,
687+
// so we just add the LLVM bin path to lib_path
688+
lib_paths.extend(additional_paths);
689+
} else {
690+
let old_path = env::var_os("PATH").unwrap_or_default();
691+
let new_path = env::join_paths(additional_paths.into_iter()
692+
.chain(env::split_paths(&old_path)))
693+
.expect("Could not add LLVM bin path to PATH");
694+
cmd.env("PATH", new_path);
682695
}
683696
}
684697

685698
add_lib_path(lib_paths, cmd);
686699
}
687700

688701
fn llvm_bin_path(&self) -> Option<PathBuf> {
689-
if self.config.llvm_enabled && !self.config.dry_run {
702+
if self.config.llvm_enabled {
690703
let llvm_config = self.ensure(native::Llvm {
691704
target: self.config.build,
692705
emscripten: false,
+23-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM ubuntu:16.04
1+
FROM ubuntu:18.10
22

33
RUN apt-get update && apt-get install -y --no-install-recommends \
44
g++ \
@@ -7,18 +7,37 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
77
curl \
88
ca-certificates \
99
python2.7 \
10+
python2.7-dev \
11+
libxml2-dev \
12+
libncurses-dev \
13+
libedit-dev \
14+
swig \
15+
doxygen \
1016
git \
1117
cmake \
1218
sudo \
1319
gdb \
14-
xz-utils
20+
xz-utils \
21+
lld \
22+
clang
1523

1624
COPY scripts/sccache.sh /scripts/
1725
RUN sh /scripts/sccache.sh
1826

27+
ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1
1928
ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
29+
2030
ENV RUST_CONFIGURE_ARGS \
2131
--build=x86_64-unknown-linux-gnu \
2232
--enable-debug \
23-
--enable-optimize
24-
ENV SCRIPT python2.7 ../x.py build
33+
--enable-lld \
34+
--enable-lldb \
35+
--enable-optimize \
36+
--set llvm.use-linker=lld \
37+
--set target.x86_64-unknown-linux-gnu.linker=clang \
38+
--set target.x86_64-unknown-linux-gnu.cc=clang \
39+
--set target.x86_64-unknown-linux-gnu.cxx=clang++
40+
41+
ENV SCRIPT \
42+
python2.7 ../x.py build && \
43+
python2.7 ../x.py test src/test/run-make-fulldeps --test-args clang
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# needs-matching-clang
2+
3+
# This test makes sure that cross-language inlining actually works by checking
4+
# the generated machine code.
5+
6+
-include ../tools.mk
7+
8+
all: cpp-executable rust-executable
9+
10+
cpp-executable:
11+
$(RUSTC) -Zcross-lang-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs
12+
$(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3
13+
# Make sure we don't find a call instruction to the function we expect to
14+
# always be inlined.
15+
llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined"
16+
# As a sanity check, make sure we do find a call instruction to a
17+
# non-inlined function
18+
llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined"
19+
20+
rust-executable:
21+
$(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2
22+
(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
23+
$(RUSTC) -Zcross-lang-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain
24+
llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined"
25+
llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdint.h>
2+
3+
uint32_t c_always_inlined() {
4+
return 1234;
5+
}
6+
7+
__attribute__((noinline)) uint32_t c_never_inlined() {
8+
return 12345;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdint.h>
2+
3+
// A trivial function defined in Rust, returning a constant value. This should
4+
// always be inlined.
5+
uint32_t rust_always_inlined();
6+
7+
8+
uint32_t rust_never_inlined();
9+
10+
int main(int argc, char** argv) {
11+
return rust_never_inlined() + rust_always_inlined();
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[link(name = "xyz")]
2+
extern "C" {
3+
fn c_always_inlined() -> u32;
4+
fn c_never_inlined() -> u32;
5+
}
6+
7+
fn main() {
8+
unsafe {
9+
println!("blub: {}", c_always_inlined() + c_never_inlined());
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![crate_type="staticlib"]
2+
3+
#[no_mangle]
4+
pub extern "C" fn rust_always_inlined() -> u32 {
5+
42
6+
}
7+
8+
#[no_mangle]
9+
#[inline(never)]
10+
pub extern "C" fn rust_never_inlined() -> u32 {
11+
421
12+
}

src/tools/compiletest/src/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ pub struct Config {
144144
/// (or, alternatively, to silently run them like regular run-pass tests).
145145
pub force_valgrind: bool,
146146

147+
/// The path to the Clang executable to run Clang-based tests with. If
148+
/// `None` then these tests will be ignored.
149+
pub run_clang_based_tests_with: Option<String>,
150+
147151
/// The directory containing the tests to run
148152
pub src_base: PathBuf,
149153

src/tools/compiletest/src/header.rs

+9
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ impl EarlyProps {
111111
if ignore_llvm(config, ln) {
112112
props.ignore = Ignore::Ignore;
113113
}
114+
115+
if config.run_clang_based_tests_with.is_none() &&
116+
config.parse_needs_matching_clang(ln) {
117+
props.ignore = Ignore::Ignore;
118+
}
114119
}
115120

116121
if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) &&
@@ -707,6 +712,10 @@ impl Config {
707712
}
708713
}
709714

715+
fn parse_needs_matching_clang(&self, line: &str) -> bool {
716+
self.parse_name_directive(line, "needs-matching-clang")
717+
}
718+
710719
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
711720
/// or `normalize-stderr-32bit`.
712721
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {

src/tools/compiletest/src/main.rs

+7
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
108108
"force-valgrind",
109109
"fail if Valgrind tests cannot be run under Valgrind",
110110
)
111+
.optopt(
112+
"",
113+
"run-clang-based-tests-with",
114+
"path to Clang executable",
115+
"PATH",
116+
)
111117
.optopt(
112118
"",
113119
"llvm-filecheck",
@@ -298,6 +304,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
298304
docck_python: matches.opt_str("docck-python").unwrap(),
299305
valgrind_path: matches.opt_str("valgrind-path"),
300306
force_valgrind: matches.opt_present("force-valgrind"),
307+
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
301308
llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)),
302309
src_base,
303310
build_base: opt_path(matches, "build-base"),

src/tools/compiletest/src/runtest.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,10 @@ impl<'test> TestCx<'test> {
26332633
cmd.env("RUSTC_LINKER", linker);
26342634
}
26352635

2636+
if let Some(ref clang) = self.config.run_clang_based_tests_with {
2637+
cmd.env("CLANG", clang);
2638+
}
2639+
26362640
// We don't want RUSTFLAGS set from the outside to interfere with
26372641
// compiler flags set in the test cases:
26382642
cmd.env_remove("RUSTFLAGS");

0 commit comments

Comments
 (0)