Skip to content

Commit 7e49a9e

Browse files
committed
moved to post_borrowck_cleanup & used MirPatch
1 parent e4df7e7 commit 7e49a9e

File tree

4 files changed

+65
-58
lines changed

4 files changed

+65
-58
lines changed

src/librustc_mir/interpret/intrinsics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
389389
);
390390
self.copy_op(self.operand_index(args[0], index)?, dest)?;
391391
}
392+
sym::count_code_region => (),
392393
_ => return Ok(false),
393394
}
394395

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::transform::{MirPass, MirSource};
2-
use rustc_index::vec::Idx;
2+
use crate::util::patch::MirPatch;
33
use rustc_middle::mir::interpret::Scalar;
44
use rustc_middle::mir::*;
5-
use rustc_middle::mir::{Local, LocalDecl};
65
use rustc_middle::ty;
76
use rustc_middle::ty::Ty;
87
use rustc_middle::ty::TyCtxt;
@@ -16,69 +15,62 @@ pub struct InstrumentCoverage;
1615
* the intrinsic llvm.instrprof.increment.
1716
*/
1817

19-
// FIXME(richkadel): As a first step, counters are only injected at the top of each function.
20-
// The complete solution will inject counters at each conditional code branch.
21-
2218
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
2319
fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
2420
if tcx.sess.opts.debugging_opts.instrument_coverage {
25-
if let Some(callee_fn_def_id) = tcx.lang_items().count_code_region_fn() {
26-
debug!("instrumenting {:?}", src.def_id());
27-
instrument_coverage(tcx, callee_fn_def_id, body);
28-
}
21+
debug!("instrumenting {:?}", src.def_id());
22+
instrument_coverage(tcx, body);
2923
}
3024
}
3125
}
3226

33-
pub fn instrument_coverage<'tcx>(
34-
tcx: TyCtxt<'tcx>,
35-
callee_fn_def_id: DefId,
36-
body: &mut Body<'tcx>,
37-
) {
27+
// The first counter (start of the function) is index zero.
28+
const INIT_FUNCTION_COUNTER: u128 = 0;
29+
30+
/// Injects calls to placeholder function `count_code_region()`.
31+
// FIXME(richkadel): As a first step, counters are only injected at the top of each function.
32+
// The complete solution will inject counters at each conditional code branch.
33+
pub fn instrument_coverage<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
3834
let span = body.span.shrink_to_lo();
3935

40-
let ret_ty = tcx.fn_sig(callee_fn_def_id).output();
36+
let count_code_region_fn =
37+
function_handle(tcx, span, tcx.lang_items().count_code_region_fn().unwrap());
38+
let counter_index = const_int_operand(tcx, span, tcx.types.u32, INIT_FUNCTION_COUNTER);
39+
40+
let mut patch = MirPatch::new(body);
41+
42+
let new_block = patch.new_block(placeholder_block(SourceInfo::outermost(body.span)));
43+
let next_block = START_BLOCK;
44+
45+
let temp = patch.new_temp(tcx.mk_unit(), body.span);
46+
patch.patch_terminator(
47+
new_block,
48+
TerminatorKind::Call {
49+
func: count_code_region_fn,
50+
args: vec![counter_index],
51+
// new_block will swapped with the next_block, after applying patch
52+
destination: Some((Place::from(temp), new_block)),
53+
cleanup: None,
54+
from_hir_call: false,
55+
},
56+
);
57+
58+
patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
59+
patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
60+
61+
patch.apply(body);
62+
63+
// To insert the `new_block` in front of the first block in the counted branch (for example,
64+
// the START_BLOCK, at the top of the function), just swap the indexes, leaving the rest of the
65+
// graph unchanged.
66+
body.basic_blocks_mut().swap(next_block, new_block);
67+
}
68+
69+
fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, span: Span, fn_def_id: DefId) -> Operand<'tcx> {
70+
let ret_ty = tcx.fn_sig(fn_def_id).output();
4171
let ret_ty = ret_ty.no_bound_vars().unwrap();
4272
let substs = tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(ret_ty)));
43-
44-
let count_code_region_fn: Operand<'_> =
45-
Operand::function_handle(tcx, callee_fn_def_id, substs, span);
46-
47-
let index = const_int_operand(tcx, span.clone(), tcx.types.u32, 0);
48-
49-
let args = vec![index];
50-
51-
let source_info = SourceInfo { span: span, scope: OUTERMOST_SOURCE_SCOPE };
52-
53-
let new_block = START_BLOCK + body.basic_blocks().len();
54-
55-
let next_local = body.local_decls.len();
56-
let new_temp = Local::new(next_local);
57-
let unit_temp = Place::from(new_temp);
58-
59-
let storage_live = Statement { source_info, kind: StatementKind::StorageLive(new_temp) };
60-
let storage_dead = Statement { source_info, kind: StatementKind::StorageDead(new_temp) };
61-
62-
let count_code_region_call = TerminatorKind::Call {
63-
func: count_code_region_fn,
64-
args,
65-
destination: Some((unit_temp, new_block)),
66-
cleanup: None,
67-
from_hir_call: false,
68-
};
69-
70-
body.local_decls.push(LocalDecl::new(tcx.mk_unit(), body.span));
71-
body.basic_blocks_mut().push(BasicBlockData {
72-
statements: vec![storage_live],
73-
is_cleanup: false,
74-
terminator: Some(Terminator { source_info, kind: count_code_region_call }),
75-
});
76-
77-
body.basic_blocks_mut().swap(START_BLOCK, new_block);
78-
body[new_block].statements.push(storage_dead);
79-
80-
// FIXME(richkadel): ALSO add each computed Span for each conditional branch to the coverage map
81-
// and provide that map to LLVM to encode in the final binary.
73+
Operand::function_handle(tcx, fn_def_id, substs, span)
8274
}
8375

8476
fn const_int_operand<'tcx>(
@@ -98,3 +90,15 @@ fn const_int_operand<'tcx>(
9890
literal: ty::Const::from_scalar(tcx, Scalar::from_uint(val, size), ty),
9991
})
10092
}
93+
94+
fn placeholder_block<'tcx>(source_info: SourceInfo) -> BasicBlockData<'tcx> {
95+
BasicBlockData {
96+
statements: vec![],
97+
terminator: Some(Terminator {
98+
source_info,
99+
// this gets overwritten by the counter Call
100+
kind: TerminatorKind::Unreachable,
101+
}),
102+
is_cleanup: false,
103+
}
104+
}

src/librustc_mir/transform/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,6 @@ fn mir_validated(
288288
&[&[
289289
// What we need to run borrowck etc.
290290
&promote_pass,
291-
// FIXME(richkadel): is this the best place for the InstrumentCoverage pass?
292-
&instrument_coverage::InstrumentCoverage,
293291
&simplify::SimplifyCfg::new("qualify-consts"),
294292
]],
295293
);
@@ -340,6 +338,10 @@ fn run_post_borrowck_cleanup_passes<'tcx>(
340338
// `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
341339
// but before optimizations begin.
342340
&add_retag::AddRetag,
341+
// If the `instrument-coverage` option is enabled, analyze the CFG, identify each
342+
// conditional branch, construct a coverage map to be passed to LLVM, and inject counters
343+
// where needed.
344+
&instrument_coverage::InstrumentCoverage,
343345
&simplify::SimplifyCfg::new("elaborate-drops"),
344346
];
345347

src/librustc_session/options.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
877877
(such as entering an empty infinite loop) by inserting llvm.sideeffect \
878878
(default: no)"),
879879
instrument_coverage: bool = (false, parse_bool, [TRACKED],
880-
"instrument the generated code with LLVM code region counters for \
881-
generating coverage reports (default: no)"),
880+
"instrument the generated code with LLVM code region counters to \
881+
(in the future) generate coverage reports (experimental; default: no)"),
882882
instrument_mcount: bool = (false, parse_bool, [TRACKED],
883883
"insert function instrument code for mcount-based tracing (default: no)"),
884884
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],

0 commit comments

Comments
 (0)