1 use super::Error; 2 3 use super::debug; 4 use super::graph; 5 use super::spans; 6 7 use debug::{DebugCounters, NESTED_INDENT}; 8 use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops}; 9 use spans::CoverageSpan; 10 11 use rustc_data_structures::graph::WithNumNodes; 12 use rustc_index::bit_set::BitSet; 13 use rustc_middle::mir::coverage::*; 14 15 /// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR 16 /// `Coverage` statements. 17 pub(super) struct CoverageCounters { 18 function_source_hash: u64, 19 next_counter_id: u32, 20 num_expressions: u32, 21 pub debug_counters: DebugCounters, 22 } 23 24 impl CoverageCounters { new(function_source_hash: u64) -> Self25 pub fn new(function_source_hash: u64) -> Self { 26 Self { 27 function_source_hash, 28 next_counter_id: CounterValueReference::START.as_u32(), 29 num_expressions: 0, 30 debug_counters: DebugCounters::new(), 31 } 32 } 33 34 /// Activate the `DebugCounters` data structures, to provide additional debug formatting 35 /// features when formatting `CoverageKind` (counter) values. enable_debug(&mut self)36 pub fn enable_debug(&mut self) { 37 self.debug_counters.enable(); 38 } 39 40 /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or 41 /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s 42 /// representing intermediate values. make_bcb_counters( &mut self, basic_coverage_blocks: &mut CoverageGraph, coverage_spans: &[CoverageSpan], ) -> Result<Vec<CoverageKind>, Error>43 pub fn make_bcb_counters( 44 &mut self, 45 basic_coverage_blocks: &mut CoverageGraph, 46 coverage_spans: &[CoverageSpan], 47 ) -> Result<Vec<CoverageKind>, Error> { 48 let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks); 49 bcb_counters.make_bcb_counters(coverage_spans) 50 } 51 make_counter<F>(&mut self, debug_block_label_fn: F) -> CoverageKind where F: Fn() -> Option<String>,52 fn make_counter<F>(&mut self, debug_block_label_fn: F) -> CoverageKind 53 where 54 F: Fn() -> Option<String>, 55 { 56 let counter = CoverageKind::Counter { 57 function_source_hash: self.function_source_hash, 58 id: self.next_counter(), 59 }; 60 if self.debug_counters.is_enabled() { 61 self.debug_counters.add_counter(&counter, (debug_block_label_fn)()); 62 } 63 counter 64 } 65 make_expression<F>( &mut self, lhs: ExpressionOperandId, op: Op, rhs: ExpressionOperandId, debug_block_label_fn: F, ) -> CoverageKind where F: Fn() -> Option<String>,66 fn make_expression<F>( 67 &mut self, 68 lhs: ExpressionOperandId, 69 op: Op, 70 rhs: ExpressionOperandId, 71 debug_block_label_fn: F, 72 ) -> CoverageKind 73 where 74 F: Fn() -> Option<String>, 75 { 76 let id = self.next_expression(); 77 let expression = CoverageKind::Expression { id, lhs, op, rhs }; 78 if self.debug_counters.is_enabled() { 79 self.debug_counters.add_counter(&expression, (debug_block_label_fn)()); 80 } 81 expression 82 } 83 make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind84 pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind { 85 let some_debug_block_label = if self.debug_counters.is_enabled() { 86 self.debug_counters.some_block_label(counter_operand).cloned() 87 } else { 88 None 89 }; 90 self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || { 91 some_debug_block_label.clone() 92 }) 93 } 94 95 /// Counter IDs start from one and go up. next_counter(&mut self) -> CounterValueReference96 fn next_counter(&mut self) -> CounterValueReference { 97 assert!(self.next_counter_id < u32::MAX - self.num_expressions); 98 let next = self.next_counter_id; 99 self.next_counter_id += 1; 100 CounterValueReference::from(next) 101 } 102 103 /// Expression IDs start from u32::MAX and go down because an Expression can reference 104 /// (add or subtract counts) of both Counter regions and Expression regions. The counter 105 /// expression operand IDs must be unique across both types. next_expression(&mut self) -> InjectedExpressionId106 fn next_expression(&mut self) -> InjectedExpressionId { 107 assert!(self.next_counter_id < u32::MAX - self.num_expressions); 108 let next = u32::MAX - self.num_expressions; 109 self.num_expressions += 1; 110 InjectedExpressionId::from(next) 111 } 112 } 113 114 /// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be 115 /// injected with `CoverageSpan`s. `Expressions` have no runtime overhead, so if a viable expression 116 /// (adding or subtracting two other counters or expressions) can compute the same result as an 117 /// embedded counter, an `Expression` should be used. 118 struct BcbCounters<'a> { 119 coverage_counters: &'a mut CoverageCounters, 120 basic_coverage_blocks: &'a mut CoverageGraph, 121 } 122 123 impl<'a> BcbCounters<'a> { new( coverage_counters: &'a mut CoverageCounters, basic_coverage_blocks: &'a mut CoverageGraph, ) -> Self124 fn new( 125 coverage_counters: &'a mut CoverageCounters, 126 basic_coverage_blocks: &'a mut CoverageGraph, 127 ) -> Self { 128 Self { coverage_counters, basic_coverage_blocks } 129 } 130 131 /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches 132 /// can be counted by `Expression` by subtracting the other branch from the branching 133 /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`. 134 /// One way to predict which branch executes the least is by considering loops. A loop is exited 135 /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost 136 /// always executed less than the branch that does not exit the loop. 137 /// 138 /// Returns any non-code-span expressions created to represent intermediate values (such as to 139 /// add two counters so the result can be subtracted from another counter), or an Error with 140 /// message for subsequent debugging. make_bcb_counters( &mut self, coverage_spans: &[CoverageSpan], ) -> Result<Vec<CoverageKind>, Error>141 fn make_bcb_counters( 142 &mut self, 143 coverage_spans: &[CoverageSpan], 144 ) -> Result<Vec<CoverageKind>, Error> { 145 debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); 146 let num_bcbs = self.basic_coverage_blocks.num_nodes(); 147 let mut collect_intermediate_expressions = Vec::with_capacity(num_bcbs); 148 149 let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs); 150 for covspan in coverage_spans { 151 bcbs_with_coverage.insert(covspan.bcb); 152 } 153 154 // Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated 155 // `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or 156 // expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming 157 // edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple 158 // incoming edges). 159 // 160 // The `TraverseCoverageGraphWithLoops` traversal ensures that, when a loop is encountered, 161 // all `BasicCoverageBlock` nodes in the loop are visited before visiting any node outside 162 // the loop. The `traversal` state includes a `context_stack`, providing a way to know if 163 // the current BCB is in one or more nested loops or not. 164 let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks); 165 while let Some(bcb) = traversal.next(self.basic_coverage_blocks) { 166 if bcbs_with_coverage.contains(bcb) { 167 debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb); 168 let branching_counter_operand = 169 self.get_or_make_counter_operand(bcb, &mut collect_intermediate_expressions)?; 170 171 if self.bcb_needs_branch_counters(bcb) { 172 self.make_branch_counters( 173 &mut traversal, 174 bcb, 175 branching_counter_operand, 176 &mut collect_intermediate_expressions, 177 )?; 178 } 179 } else { 180 debug!( 181 "{:?} does not have any `CoverageSpan`s. A counter will only be added if \ 182 and when a covered BCB has an expression dependency.", 183 bcb, 184 ); 185 } 186 } 187 188 if traversal.is_complete() { 189 Ok(collect_intermediate_expressions) 190 } else { 191 Error::from_string(format!( 192 "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}", 193 traversal.unvisited(), 194 )) 195 } 196 } 197 make_branch_counters( &mut self, traversal: &mut TraverseCoverageGraphWithLoops, branching_bcb: BasicCoverageBlock, branching_counter_operand: ExpressionOperandId, collect_intermediate_expressions: &mut Vec<CoverageKind>, ) -> Result<(), Error>198 fn make_branch_counters( 199 &mut self, 200 traversal: &mut TraverseCoverageGraphWithLoops, 201 branching_bcb: BasicCoverageBlock, 202 branching_counter_operand: ExpressionOperandId, 203 collect_intermediate_expressions: &mut Vec<CoverageKind>, 204 ) -> Result<(), Error> { 205 let branches = self.bcb_branches(branching_bcb); 206 debug!( 207 "{:?} has some branch(es) without counters:\n {}", 208 branching_bcb, 209 branches 210 .iter() 211 .map(|branch| { 212 format!("{:?}: {:?}", branch, branch.counter(&self.basic_coverage_blocks)) 213 }) 214 .collect::<Vec<_>>() 215 .join("\n "), 216 ); 217 218 // Use the `traversal` state to decide if a subset of the branches exit a loop, making it 219 // likely that branch is executed less than branches that do not exit the same loop. In this 220 // case, any branch that does not exit the loop (and has not already been assigned a 221 // counter) should be counted by expression, if possible. (If a preferred expression branch 222 // is not selected based on the loop context, select any branch without an existing 223 // counter.) 224 let expression_branch = self.choose_preferred_expression_branch(traversal, &branches); 225 226 // Assign a Counter or Expression to each branch, plus additional `Expression`s, as needed, 227 // to sum up intermediate results. 228 let mut some_sumup_counter_operand = None; 229 for branch in branches { 230 // Skip the selected `expression_branch`, if any. It's expression will be assigned after 231 // all others. 232 if branch != expression_branch { 233 let branch_counter_operand = if branch.is_only_path_to_target() { 234 debug!( 235 " {:?} has only one incoming edge (from {:?}), so adding a \ 236 counter", 237 branch, branching_bcb 238 ); 239 self.get_or_make_counter_operand( 240 branch.target_bcb, 241 collect_intermediate_expressions, 242 )? 243 } else { 244 debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch); 245 self.get_or_make_edge_counter_operand( 246 branching_bcb, 247 branch.target_bcb, 248 collect_intermediate_expressions, 249 )? 250 }; 251 if let Some(sumup_counter_operand) = 252 some_sumup_counter_operand.replace(branch_counter_operand) 253 { 254 let intermediate_expression = self.coverage_counters.make_expression( 255 branch_counter_operand, 256 Op::Add, 257 sumup_counter_operand, 258 || None, 259 ); 260 debug!( 261 " [new intermediate expression: {}]", 262 self.format_counter(&intermediate_expression) 263 ); 264 let intermediate_expression_operand = intermediate_expression.as_operand_id(); 265 collect_intermediate_expressions.push(intermediate_expression); 266 some_sumup_counter_operand.replace(intermediate_expression_operand); 267 } 268 } 269 } 270 271 // Assign the final expression to the `expression_branch` by subtracting the total of all 272 // other branches from the counter of the branching BCB. 273 let sumup_counter_operand = 274 some_sumup_counter_operand.expect("sumup_counter_operand should have a value"); 275 debug!( 276 "Making an expression for the selected expression_branch: {:?} \ 277 (expression_branch predecessors: {:?})", 278 expression_branch, 279 self.bcb_predecessors(expression_branch.target_bcb), 280 ); 281 let expression = self.coverage_counters.make_expression( 282 branching_counter_operand, 283 Op::Subtract, 284 sumup_counter_operand, 285 || Some(format!("{:?}", expression_branch)), 286 ); 287 debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression)); 288 let bcb = expression_branch.target_bcb; 289 if expression_branch.is_only_path_to_target() { 290 self.basic_coverage_blocks[bcb].set_counter(expression)?; 291 } else { 292 self.basic_coverage_blocks[bcb].set_edge_counter_from(branching_bcb, expression)?; 293 } 294 Ok(()) 295 } 296 get_or_make_counter_operand( &mut self, bcb: BasicCoverageBlock, collect_intermediate_expressions: &mut Vec<CoverageKind>, ) -> Result<ExpressionOperandId, Error>297 fn get_or_make_counter_operand( 298 &mut self, 299 bcb: BasicCoverageBlock, 300 collect_intermediate_expressions: &mut Vec<CoverageKind>, 301 ) -> Result<ExpressionOperandId, Error> { 302 self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1) 303 } 304 recursive_get_or_make_counter_operand( &mut self, bcb: BasicCoverageBlock, collect_intermediate_expressions: &mut Vec<CoverageKind>, debug_indent_level: usize, ) -> Result<ExpressionOperandId, Error>305 fn recursive_get_or_make_counter_operand( 306 &mut self, 307 bcb: BasicCoverageBlock, 308 collect_intermediate_expressions: &mut Vec<CoverageKind>, 309 debug_indent_level: usize, 310 ) -> Result<ExpressionOperandId, Error> { 311 // If the BCB already has a counter, return it. 312 if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() { 313 debug!( 314 "{}{:?} already has a counter: {}", 315 NESTED_INDENT.repeat(debug_indent_level), 316 bcb, 317 self.format_counter(counter_kind), 318 ); 319 return Ok(counter_kind.as_operand_id()); 320 } 321 322 // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). 323 // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the 324 // program results in a tight infinite loop, but it should still compile. 325 let one_path_to_target = self.bcb_has_one_path_to_target(bcb); 326 if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { 327 let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb))); 328 if one_path_to_target { 329 debug!( 330 "{}{:?} gets a new counter: {}", 331 NESTED_INDENT.repeat(debug_indent_level), 332 bcb, 333 self.format_counter(&counter_kind), 334 ); 335 } else { 336 debug!( 337 "{}{:?} has itself as its own predecessor. It can't be part of its own \ 338 Expression sum, so it will get its own new counter: {}. (Note, the compiled \ 339 code will generate an infinite loop.)", 340 NESTED_INDENT.repeat(debug_indent_level), 341 bcb, 342 self.format_counter(&counter_kind), 343 ); 344 } 345 return self.basic_coverage_blocks[bcb].set_counter(counter_kind); 346 } 347 348 // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the 349 // counters and/or expressions of its incoming edges. This will recursively get or create 350 // counters for those incoming edges first, then call `make_expression()` to sum them up, 351 // with additional intermediate expressions as needed. 352 let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter(); 353 debug!( 354 "{}{:?} has multiple incoming edges and will get an expression that sums them up...", 355 NESTED_INDENT.repeat(debug_indent_level), 356 bcb, 357 ); 358 let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( 359 predecessors.next().unwrap(), 360 bcb, 361 collect_intermediate_expressions, 362 debug_indent_level + 1, 363 )?; 364 let mut some_sumup_edge_counter_operand = None; 365 for predecessor in predecessors { 366 let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( 367 predecessor, 368 bcb, 369 collect_intermediate_expressions, 370 debug_indent_level + 1, 371 )?; 372 if let Some(sumup_edge_counter_operand) = 373 some_sumup_edge_counter_operand.replace(edge_counter_operand) 374 { 375 let intermediate_expression = self.coverage_counters.make_expression( 376 sumup_edge_counter_operand, 377 Op::Add, 378 edge_counter_operand, 379 || None, 380 ); 381 debug!( 382 "{}new intermediate expression: {}", 383 NESTED_INDENT.repeat(debug_indent_level), 384 self.format_counter(&intermediate_expression) 385 ); 386 let intermediate_expression_operand = intermediate_expression.as_operand_id(); 387 collect_intermediate_expressions.push(intermediate_expression); 388 some_sumup_edge_counter_operand.replace(intermediate_expression_operand); 389 } 390 } 391 let counter_kind = self.coverage_counters.make_expression( 392 first_edge_counter_operand, 393 Op::Add, 394 some_sumup_edge_counter_operand.unwrap(), 395 || Some(format!("{:?}", bcb)), 396 ); 397 debug!( 398 "{}{:?} gets a new counter (sum of predecessor counters): {}", 399 NESTED_INDENT.repeat(debug_indent_level), 400 bcb, 401 self.format_counter(&counter_kind) 402 ); 403 self.basic_coverage_blocks[bcb].set_counter(counter_kind) 404 } 405 get_or_make_edge_counter_operand( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, collect_intermediate_expressions: &mut Vec<CoverageKind>, ) -> Result<ExpressionOperandId, Error>406 fn get_or_make_edge_counter_operand( 407 &mut self, 408 from_bcb: BasicCoverageBlock, 409 to_bcb: BasicCoverageBlock, 410 collect_intermediate_expressions: &mut Vec<CoverageKind>, 411 ) -> Result<ExpressionOperandId, Error> { 412 self.recursive_get_or_make_edge_counter_operand( 413 from_bcb, 414 to_bcb, 415 collect_intermediate_expressions, 416 1, 417 ) 418 } 419 recursive_get_or_make_edge_counter_operand( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, collect_intermediate_expressions: &mut Vec<CoverageKind>, debug_indent_level: usize, ) -> Result<ExpressionOperandId, Error>420 fn recursive_get_or_make_edge_counter_operand( 421 &mut self, 422 from_bcb: BasicCoverageBlock, 423 to_bcb: BasicCoverageBlock, 424 collect_intermediate_expressions: &mut Vec<CoverageKind>, 425 debug_indent_level: usize, 426 ) -> Result<ExpressionOperandId, Error> { 427 // If the source BCB has only one successor (assumed to be the given target), an edge 428 // counter is unnecessary. Just get or make a counter for the source BCB. 429 let successors = self.bcb_successors(from_bcb).iter(); 430 if successors.len() == 1 { 431 return self.recursive_get_or_make_counter_operand( 432 from_bcb, 433 collect_intermediate_expressions, 434 debug_indent_level + 1, 435 ); 436 } 437 438 // If the edge already has a counter, return it. 439 if let Some(counter_kind) = self.basic_coverage_blocks[to_bcb].edge_counter_from(from_bcb) { 440 debug!( 441 "{}Edge {:?}->{:?} already has a counter: {}", 442 NESTED_INDENT.repeat(debug_indent_level), 443 from_bcb, 444 to_bcb, 445 self.format_counter(counter_kind) 446 ); 447 return Ok(counter_kind.as_operand_id()); 448 } 449 450 // Make a new counter to count this edge. 451 let counter_kind = 452 self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb))); 453 debug!( 454 "{}Edge {:?}->{:?} gets a new counter: {}", 455 NESTED_INDENT.repeat(debug_indent_level), 456 from_bcb, 457 to_bcb, 458 self.format_counter(&counter_kind) 459 ); 460 self.basic_coverage_blocks[to_bcb].set_edge_counter_from(from_bcb, counter_kind) 461 } 462 463 /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was 464 /// found, select any branch. choose_preferred_expression_branch( &self, traversal: &TraverseCoverageGraphWithLoops, branches: &[BcbBranch], ) -> BcbBranch465 fn choose_preferred_expression_branch( 466 &self, 467 traversal: &TraverseCoverageGraphWithLoops, 468 branches: &[BcbBranch], 469 ) -> BcbBranch { 470 let branch_needs_a_counter = 471 |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); 472 473 let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches); 474 if let Some(reloop_branch_without_counter) = 475 some_reloop_branch.filter(branch_needs_a_counter) 476 { 477 debug!( 478 "Selecting reloop_branch={:?} that still needs a counter, to get the \ 479 `Expression`", 480 reloop_branch_without_counter 481 ); 482 reloop_branch_without_counter 483 } else { 484 let &branch_without_counter = branches 485 .iter() 486 .find(|&&branch| branch.counter(&self.basic_coverage_blocks).is_none()) 487 .expect( 488 "needs_branch_counters was `true` so there should be at least one \ 489 branch", 490 ); 491 debug!( 492 "Selecting any branch={:?} that still needs a counter, to get the \ 493 `Expression` because there was no `reloop_branch`, or it already had a \ 494 counter", 495 branch_without_counter 496 ); 497 branch_without_counter 498 } 499 } 500 501 /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has 502 /// multiple incoming edges) can have a counter computed by expression. 503 /// 504 /// If at least one of the branches leads outside of a loop (`found_loop_exit` is 505 /// true), and at least one other branch does not exit the loop (the first of which 506 /// is captured in `some_reloop_branch`), it's likely any reloop branch will be 507 /// executed far more often than loop exit branch, making the reloop branch a better 508 /// candidate for an expression. find_some_reloop_branch( &self, traversal: &TraverseCoverageGraphWithLoops, branches: &[BcbBranch], ) -> Option<BcbBranch>509 fn find_some_reloop_branch( 510 &self, 511 traversal: &TraverseCoverageGraphWithLoops, 512 branches: &[BcbBranch], 513 ) -> Option<BcbBranch> { 514 let branch_needs_a_counter = 515 |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); 516 517 let mut some_reloop_branch: Option<BcbBranch> = None; 518 for context in traversal.context_stack.iter().rev() { 519 if let Some((backedge_from_bcbs, _)) = &context.loop_backedges { 520 let mut found_loop_exit = false; 521 for &branch in branches.iter() { 522 if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { 523 self.bcb_dominates(branch.target_bcb, backedge_from_bcb) 524 }) { 525 if let Some(reloop_branch) = some_reloop_branch { 526 if reloop_branch.counter(&self.basic_coverage_blocks).is_none() { 527 // we already found a candidate reloop_branch that still 528 // needs a counter 529 continue; 530 } 531 } 532 // The path from branch leads back to the top of the loop. Set this 533 // branch as the `reloop_branch`. If this branch already has a 534 // counter, and we find another reloop branch that doesn't have a 535 // counter yet, that branch will be selected as the `reloop_branch` 536 // instead. 537 some_reloop_branch = Some(branch); 538 } else { 539 // The path from branch leads outside this loop 540 found_loop_exit = true; 541 } 542 if found_loop_exit 543 && some_reloop_branch.filter(branch_needs_a_counter).is_some() 544 { 545 // Found both a branch that exits the loop and a branch that returns 546 // to the top of the loop (`reloop_branch`), and the `reloop_branch` 547 // doesn't already have a counter. 548 break; 549 } 550 } 551 if !found_loop_exit { 552 debug!( 553 "No branches exit the loop, so any branch without an existing \ 554 counter can have the `Expression`." 555 ); 556 break; 557 } 558 if some_reloop_branch.is_some() { 559 debug!( 560 "Found a branch that exits the loop and a branch the loops back to \ 561 the top of the loop (`reloop_branch`). The `reloop_branch` will \ 562 get the `Expression`, as long as it still needs a counter." 563 ); 564 break; 565 } 566 // else all branches exited this loop context, so run the same checks with 567 // the outer loop(s) 568 } 569 } 570 some_reloop_branch 571 } 572 573 #[inline] bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock]574 fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { 575 &self.basic_coverage_blocks.predecessors[bcb] 576 } 577 578 #[inline] bcb_successors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock]579 fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { 580 &self.basic_coverage_blocks.successors[bcb] 581 } 582 583 #[inline] bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec<BcbBranch>584 fn bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec<BcbBranch> { 585 self.bcb_successors(from_bcb) 586 .iter() 587 .map(|&to_bcb| BcbBranch::from_to(from_bcb, to_bcb, &self.basic_coverage_blocks)) 588 .collect::<Vec<_>>() 589 } 590 bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool591 fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool { 592 let branch_needs_a_counter = 593 |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); 594 let branches = self.bcb_branches(bcb); 595 branches.len() > 1 && branches.iter().any(branch_needs_a_counter) 596 } 597 598 /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be 599 /// the entry point for the function.) 600 #[inline] bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool601 fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { 602 self.bcb_predecessors(bcb).len() <= 1 603 } 604 605 #[inline] bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool606 fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { 607 self.basic_coverage_blocks.dominates(dom, node) 608 } 609 610 #[inline] format_counter(&self, counter_kind: &CoverageKind) -> String611 fn format_counter(&self, counter_kind: &CoverageKind) -> String { 612 self.coverage_counters.debug_counters.format_counter(counter_kind) 613 } 614 } 615