Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b9ad718

Browse files
committedFeb 23, 2024
Auto merge of rust-lang#120656 - Zalathar:filecheck-flags, r=wesleywiser
Allow tests to specify a `//@ filecheck-flags:` header This allows individual codegen/assembly/mir-opt tests to pass extra flags to the LLVM `filecheck` tool as needed. --- The original motivation was noticing that `tests/run-make/instrument-coverage` was very close to being an ordinary codegen test, except that it needs some extra logic to set up platform-specific variables to be passed into filecheck. I then saw the comment in `verify_with_filecheck` indicating that a `filecheck-flags` header might be useful for other purposes as well.
2 parents 8f359be + e56cc84 commit b9ad718

File tree

14 files changed

+190
-168
lines changed

14 files changed

+190
-168
lines changed
 

‎src/tools/compiletest/src/header.rs

+8
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ pub struct TestProps {
197197
/// Extra flags to pass to `llvm-cov` when producing coverage reports.
198198
/// Only used by the "coverage-run" test mode.
199199
pub llvm_cov_flags: Vec<String>,
200+
/// Extra flags to pass to LLVM's `filecheck` tool, in tests that use it.
201+
pub filecheck_flags: Vec<String>,
200202
}
201203

202204
mod directives {
@@ -236,6 +238,7 @@ mod directives {
236238
pub const REMAP_SRC_BASE: &'static str = "remap-src-base";
237239
pub const COMPARE_OUTPUT_LINES_BY_SUBSET: &'static str = "compare-output-lines-by-subset";
238240
pub const LLVM_COV_FLAGS: &'static str = "llvm-cov-flags";
241+
pub const FILECHECK_FLAGS: &'static str = "filecheck-flags";
239242
// This isn't a real directive, just one that is probably mistyped often
240243
pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
241244
}
@@ -286,6 +289,7 @@ impl TestProps {
286289
mir_unit_test: None,
287290
remap_src_base: false,
288291
llvm_cov_flags: vec![],
292+
filecheck_flags: vec![],
289293
}
290294
}
291295

@@ -542,6 +546,10 @@ impl TestProps {
542546
if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) {
543547
self.llvm_cov_flags.extend(split_flags(&flags));
544548
}
549+
550+
if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) {
551+
self.filecheck_flags.extend(split_flags(&flags));
552+
}
545553
},
546554
);
547555

‎src/tools/compiletest/src/runtest.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -2906,25 +2906,32 @@ impl<'test> TestCx<'test> {
29062906
fn verify_with_filecheck(&self, output: &Path) -> ProcRes {
29072907
let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
29082908
filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file);
2909-
// It would be more appropriate to make most of the arguments configurable through
2910-
// a comment-attribute similar to `compile-flags`. For example, --check-prefixes is a very
2911-
// useful flag.
2912-
//
2913-
// For now, though…
2914-
let prefix_for_target =
2915-
if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" };
2916-
let prefixes = if let Some(rev) = self.revision {
2917-
format!("CHECK,{},{}", prefix_for_target, rev)
2918-
} else {
2919-
format!("CHECK,{}", prefix_for_target)
2920-
};
2921-
if self.config.llvm_version.unwrap_or(0) >= 130000 {
2922-
filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]);
2923-
} else {
2924-
filecheck.args(&["--check-prefixes", &prefixes]);
2909+
2910+
// FIXME: Consider making some of these prefix flags opt-in per test,
2911+
// via `filecheck-flags` or by adding new header directives.
2912+
2913+
// Because we use custom prefixes, we also have to register the default prefix.
2914+
filecheck.arg("--check-prefix=CHECK");
2915+
2916+
// Some tests use the current revision name as a check prefix.
2917+
if let Some(rev) = self.revision {
2918+
filecheck.arg("--check-prefix").arg(rev);
29252919
}
2920+
2921+
// Some tests also expect either the MSVC or NONMSVC prefix to be defined.
2922+
let msvc_or_not = if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" };
2923+
filecheck.arg("--check-prefix").arg(msvc_or_not);
2924+
2925+
// The filecheck tool normally fails if a prefix is defined but not used.
2926+
// However, we define several prefixes globally for all tests.
2927+
filecheck.arg("--allow-unused-prefixes");
2928+
29262929
// Provide more context on failures.
29272930
filecheck.args(&["--dump-input-context", "100"]);
2931+
2932+
// Add custom flags supplied by the `filecheck-flags:` test header.
2933+
filecheck.args(&self.props.filecheck_flags);
2934+
29282935
self.compose_and_run(filecheck, "", None, None)
29292936
}
29302937

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//@ edition: 2021
2+
//@ needs-profiler-support
3+
//@ compile-flags: -Cinstrument-coverage -Copt-level=0
4+
//@ revisions: LINUX DARWIN WINDOWS
5+
6+
//@ [LINUX] only-linux
7+
//@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data
8+
//@ [LINUX] filecheck-flags: -DINSTR_PROF_NAME=__llvm_prf_names
9+
//@ [LINUX] filecheck-flags: -DINSTR_PROF_CNTS=__llvm_prf_cnts
10+
//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVMAP=__llvm_covmap
11+
//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
12+
//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
13+
14+
//@ [DARWIN] only-macos
15+
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support
16+
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names
17+
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts
18+
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVMAP=__LLVM_COV,__llvm_covmap
19+
//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun
20+
//@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED=
21+
22+
//@ [WINDOWS] only-windows
23+
//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M
24+
//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M
25+
//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M
26+
//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M
27+
//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M
28+
//@ [WINDOWS] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
29+
30+
// ignore-tidy-linelength
31+
32+
pub fn will_be_called() -> &'static str {
33+
let val = "called";
34+
println!("{}", val);
35+
val
36+
}
37+
38+
pub fn will_not_be_called() -> bool {
39+
println!("should not have been called");
40+
false
41+
}
42+
43+
pub fn print<T>(left: &str, value: T, right: &str)
44+
where
45+
T: std::fmt::Display,
46+
{
47+
println!("{}{}{}", left, value, right);
48+
}
49+
50+
pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
51+
where
52+
F: FnOnce(&T)
53+
{
54+
if should_wrap {
55+
wrapper(&inner)
56+
}
57+
}
58+
59+
fn main() {
60+
let less = 1;
61+
let more = 100;
62+
63+
if less < more {
64+
wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
65+
wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
66+
} else {
67+
wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
68+
}
69+
}
70+
71+
// Check for metadata, variables, declarations, and function definitions injected
72+
// into LLVM IR when compiling with -Cinstrument-coverage.
73+
74+
// WINDOWS: $__llvm_profile_runtime_user = comdat any
75+
76+
// CHECK: @__llvm_coverage_mapping = private constant
77+
// CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
78+
79+
// CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
80+
// CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
81+
82+
// WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32
83+
84+
// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
85+
// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
86+
87+
// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
88+
// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called
89+
// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
90+
91+
// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
92+
// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
93+
94+
// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
95+
// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main
96+
// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
97+
98+
// CHECK: @__llvm_prf_nm = private constant
99+
// CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1
100+
101+
// CHECK: @llvm.used = appending global
102+
// CHECK-SAME: @__llvm_coverage_mapping
103+
// CHECK-SAME: @__llvm_prf_nm
104+
// CHECK-SAME: section "llvm.metadata"
105+
106+
// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} {
107+
// CHECK-NEXT: start:
108+
// CHECK-NOT: define internal
109+
// CHECK: atomicrmw add ptr
110+
// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
111+
112+
// CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
113+
114+
// WINDOWS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
115+
// WINDOWS-NEXT: %1 = load i32, ptr @__llvm_profile_runtime
116+
// WINDOWS-NEXT: ret i32 %1
117+
// WINDOWS-NEXT: }
118+
119+
// CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind }
120+
// WINDOWS: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Simple test that uses the default CHECK prefix and should always succeed.
2+
3+
// CHECK: main
4+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Arguments provided via `filecheck-flags` should be passed to `filecheck`.
2+
3+
//@ revisions: good bad
4+
//@ [good] filecheck-flags: --check-prefix=CUSTOM
5+
//@ [bad] should-fail
6+
7+
// CUSTOM: main
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// This is exactly like `msvc-prefix-good.rs`, except that it should always fail.
2+
3+
//@ should-fail
4+
5+
// MSVC: text that should not match
6+
// NONMSVC: text that should not match
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// One of MSVC or NONMSVC should always be defined, so this test should pass.
2+
3+
// (one of these should always be present)
4+
5+
// MSVC: main
6+
// NONMSVC: main
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// A test that doesn't include any filecheck directives should fail.
2+
3+
//@ should-fail
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// The current revision name is registered as a filecheck prefix.
2+
3+
//@ revisions: GOOD BAD
4+
//@ [BAD] should-fail
5+
6+
// GOOD: main
7+
// BAD: text that should not match
8+
fn main() {}

‎tests/run-make/coverage-llvmir/Makefile

-64
This file was deleted.

‎tests/run-make/coverage-llvmir/filecheck.testprog.txt

-50
This file was deleted.

‎tests/run-make/coverage-llvmir/testprog.rs

-38
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.