Skip to content

Commit 26d260b

Browse files
committed
Run LLVM coverage instrumentation passes before optimization passes
This matches the behavior of Clang and allows us to remove several hacks which were needed to ensure functions weren't optimized away before reaching the instrumentation pass.
1 parent 3debe9a commit 26d260b

File tree

9 files changed

+92
-139
lines changed

9 files changed

+92
-139
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+5
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,11 @@ pub(crate) unsafe fn optimize(
548548
llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap());
549549
continue;
550550
}
551+
if pass_name == "insert-gcov-profiling" || pass_name == "instrprof" {
552+
// Instrumentation should be inserted before optimization.
553+
llvm::LLVMRustAddPass(mpm, find_pass(pass_name).unwrap());
554+
continue;
555+
}
551556

552557
if let Some(pass) = find_pass(pass_name) {
553558
extra_passes.push(pass);

compiler/rustc_middle/src/mir/mono.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,7 @@ impl<'tcx> MonoItem<'tcx> {
8484
.debugging_opts
8585
.inline_in_all_cgus
8686
.unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
87-
&& !tcx.sess.link_dead_code()
88-
&& !tcx.sess.instrument_coverage();
89-
// Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes
90-
// break coverage results. A test that failed at certain optimization levels is now
91-
// validated at that optimization level (via `compile-flags` directive):
92-
// * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and
93-
// also required disabling `internalize_symbols` in
94-
// `rustc_mir/monomorphize/partitioning/mod.rs`
87+
&& !tcx.sess.link_dead_code();
9588

9689
match *self {
9790
MonoItem::Fn(ref instance) => {

compiler/rustc_mir/src/monomorphize/partitioning/mod.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,7 @@ pub fn partition<'tcx>(
196196

197197
// Next we try to make as many symbols "internal" as possible, so LLVM has
198198
// more freedom to optimize.
199-
if !tcx.sess.link_dead_code() && !tcx.sess.instrument_coverage() {
200-
// Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes
201-
// break coverage results. Tests that failed at certain optimization levels are now
202-
// validated at those optimization levels (via `compile-flags` directive); for example:
203-
// * `src/test/run-make-fulldeps/coverage/async.rs` broke with `-C opt-level=1`
204-
// * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and
205-
// also required disabling `generate_gcu_internal_copies` in `rustc_middle/mir/mono.rs`
199+
if !tcx.sess.link_dead_code() {
206200
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
207201
partitioner.internalize_symbols(cx, &mut post_inlining);
208202
}

compiler/rustc_typeck/src/collect.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -2889,17 +2889,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
28892889
.emit();
28902890
InlineAttr::None
28912891
} else if list_contains_name(&items[..], sym::always) {
2892-
if tcx.sess.instrument_coverage() {
2893-
// Fixes Issue #82875. Forced inlining allows LLVM to discard functions
2894-
// marked with `#[inline(always)]`, which can break coverage reporting if
2895-
// that function was referenced from a coverage map.
2896-
//
2897-
// FIXME(#83429): Is there a better place, e.g., in codegen, to check and
2898-
// convert `Always` to `Hint`?
2899-
InlineAttr::Hint
2900-
} else {
2901-
InlineAttr::Always
2902-
}
2892+
InlineAttr::Always
29032893
} else if list_contains_name(&items[..], sym::never) {
29042894
InlineAttr::Never
29052895
} else {

src/test/run-make-fulldeps/coverage-llvmir/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ else
1717
COMDAT_IF_SUPPORTED=, comdat
1818
endif
1919

20-
DEFINE_INTERNAL=define hidden
20+
DEFINE_INTERNAL=define internal
2121

2222
ifdef IS_WINDOWS
2323
LLVM_FILECHECK_OPTIONS=\

src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@
2929
18| 2| println!("BOOM times {}!!!", self.strength);
3030
19| 2| }
3131
------------------
32-
| <generics::Firework<f64> as core::ops::drop::Drop>::drop:
32+
| <generics::Firework<i32> as core::ops::drop::Drop>::drop:
3333
| 17| 1| fn drop(&mut self) {
3434
| 18| 1| println!("BOOM times {}!!!", self.strength);
3535
| 19| 1| }
3636
------------------
37-
| <generics::Firework<i32> as core::ops::drop::Drop>::drop:
37+
| <generics::Firework<f64> as core::ops::drop::Drop>::drop:
3838
| 17| 1| fn drop(&mut self) {
3939
| 18| 1| println!("BOOM times {}!!!", self.strength);
4040
| 19| 1| }

src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@
3636
22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
3737
23| 2|}
3838
------------------
39-
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
39+
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
4040
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
4141
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
4242
| 23| 1|}
4343
------------------
44-
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
44+
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
4545
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
4646
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
4747
| 23| 1|}

src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt

+79-102
Original file line numberDiff line numberDiff line change
@@ -30,127 +30,104 @@
3030
^0
3131
29| 1| use_this_lib_crate();
3232
30| 1|}
33-
------------------
34-
| used_inline_crate::used_inline_function:
35-
| 20| 1|pub fn used_inline_function() {
36-
| 21| | // Initialize test constants in a way that cannot be determined at compile time, to ensure
37-
| 22| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
38-
| 23| | // dependent conditions.
39-
| 24| 1| let is_true = std::env::args().len() == 1;
40-
| 25| 1| let mut countdown = 0;
41-
| 26| 1| if is_true {
42-
| 27| 1| countdown = 10;
43-
| 28| 1| }
44-
| ^0
45-
| 29| 1| use_this_lib_crate();
46-
| 30| 1|}
47-
------------------
48-
| Unexecuted instantiation: used_inline_crate::used_inline_function
49-
------------------
50-
31| |// Expect for above function:
51-
32| |//
52-
33| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
53-
34| |//
54-
35| |// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which
55-
36| |// does not use it) and the `uses_inline_crate` binary (which does use/call it).
56-
37| |
57-
38| |#[inline(always)]
58-
39| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
59-
40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
60-
41| 2|}
33+
31| |
34+
32| |#[inline(always)]
35+
33| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
36+
34| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
37+
35| 2|}
6138
------------------
6239
| used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
63-
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
64-
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
65-
| 41| 1|}
40+
| 33| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
41+
| 34| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
42+
| 35| 1|}
6643
------------------
6744
| used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
68-
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
69-
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
70-
| 41| 1|}
45+
| 33| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
46+
| 34| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
47+
| 35| 1|}
7148
------------------
7249
| Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_>
7350
------------------
74-
42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
75-
43| |
76-
44| |#[inline(always)]
77-
45| 4|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
78-
46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
79-
47| 4|}
51+
36| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
52+
37| |
53+
38| |#[inline(always)]
54+
39| 4|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
55+
40| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
56+
41| 4|}
8057
------------------
8158
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
82-
| 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
83-
| 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
84-
| 47| 2|}
59+
| 39| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
60+
| 40| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
61+
| 41| 2|}
8562
------------------
8663
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
87-
| 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
88-
| 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
89-
| 47| 2|}
64+
| 39| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
65+
| 40| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
66+
| 41| 2|}
9067
------------------
91-
48| |
92-
49| |#[inline(always)]
93-
50| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
94-
51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
95-
52| 3|}
68+
42| |
69+
43| |#[inline(always)]
70+
44| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
71+
45| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
72+
46| 3|}
9673
------------------
9774
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
98-
| 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
99-
| 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
100-
| 52| 1|}
75+
| 44| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
76+
| 45| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
77+
| 46| 1|}
10178
------------------
10279
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
103-
| 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
104-
| 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
105-
| 52| 2|}
80+
| 44| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
81+
| 45| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
82+
| 46| 2|}
10683
------------------
107-
53| |
108-
54| |#[inline(always)]
109-
55| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
110-
56| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
111-
57| 3|}
84+
47| |
85+
48| |#[inline(always)]
86+
49| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
87+
50| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
88+
51| 3|}
11289
------------------
11390
| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
114-
| 55| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
115-
| 56| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
116-
| 57| 1|}
91+
| 49| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
92+
| 50| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
93+
| 51| 1|}
11794
------------------
11895
| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
119-
| 55| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
120-
| 56| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
121-
| 57| 2|}
122-
------------------
123-
58| |
124-
59| |#[inline(always)]
125-
60| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
126-
61| 0| println!("unused_generic_function with {:?}", arg);
127-
62| 0|}
128-
63| |
129-
64| |#[inline(always)]
130-
65| 0|pub fn unused_function() {
131-
66| 0| let is_true = std::env::args().len() == 1;
132-
67| 0| let mut countdown = 2;
133-
68| 0| if !is_true {
134-
69| 0| countdown = 20;
135-
70| 0| }
136-
71| 0|}
137-
72| |
138-
73| |#[inline(always)]
139-
74| 0|fn unused_private_function() {
140-
75| 0| let is_true = std::env::args().len() == 1;
141-
76| 0| let mut countdown = 2;
142-
77| 0| if !is_true {
143-
78| 0| countdown = 20;
144-
79| 0| }
145-
80| 0|}
146-
81| |
147-
82| 2|fn use_this_lib_crate() {
148-
83| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
149-
84| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
150-
85| 2| "used from library used_crate.rs",
151-
86| 2| );
152-
87| 2| let some_vec = vec![5, 6, 7, 8];
153-
88| 2| used_only_from_this_lib_crate_generic_function(some_vec);
154-
89| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
155-
90| 2|}
96+
| 49| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
97+
| 50| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
98+
| 51| 2|}
99+
------------------
100+
52| |
101+
53| |#[inline(always)]
102+
54| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
103+
55| 0| println!("unused_generic_function with {:?}", arg);
104+
56| 0|}
105+
57| |
106+
58| |#[inline(always)]
107+
59| 0|pub fn unused_function() {
108+
60| 0| let is_true = std::env::args().len() == 1;
109+
61| 0| let mut countdown = 2;
110+
62| 0| if !is_true {
111+
63| 0| countdown = 20;
112+
64| 0| }
113+
65| 0|}
114+
66| |
115+
67| |#[inline(always)]
116+
68| 0|fn unused_private_function() {
117+
69| 0| let is_true = std::env::args().len() == 1;
118+
70| 0| let mut countdown = 2;
119+
71| 0| if !is_true {
120+
72| 0| countdown = 20;
121+
73| 0| }
122+
74| 0|}
123+
75| |
124+
76| 2|fn use_this_lib_crate() {
125+
77| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
126+
78| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
127+
79| 2| "used from library used_crate.rs",
128+
80| 2| );
129+
81| 2| let some_vec = vec![5, 6, 7, 8];
130+
82| 2| used_only_from_this_lib_crate_generic_function(some_vec);
131+
83| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
132+
84| 2|}
156133

src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs

-6
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ pub fn used_inline_function() {
2828
}
2929
use_this_lib_crate();
3030
}
31-
// Expect for above function:
32-
//
33-
// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
34-
//
35-
// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which
36-
// does not use it) and the `uses_inline_crate` binary (which does use/call it).
3731

3832
#[inline(always)]
3933
pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {

0 commit comments

Comments
 (0)