Skip to content

Commit

Permalink
Make process_obligations' computation of completed optional.
Browse files Browse the repository at this point in the history
It's only used in tests.

This reduces instruction counts on several benchmarks by 0.5--1%.
  • Loading branch information
nnethercote committed Oct 30, 2018
1 parent d586d5d commit dbc3c6e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 72 deletions.
7 changes: 4 additions & 3 deletions src/librustc/traits/fulfill.rs
Expand Up @@ -12,8 +12,9 @@ use infer::InferCtxt;
use mir::interpret::{GlobalId, ErrorHandled};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
use ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, ObligationForest};
use rustc_data_structures::obligation_forest::{ObligationProcessor, ProcessResult};
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_data_structures::obligation_forest::{ProcessResult};
use std::marker::PhantomData;
use hir::def_id::DefId;

Expand Down Expand Up @@ -98,7 +99,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
selcx,
register_region_obligations: self.register_region_obligations
});
}, DoCompleted::No);
debug!("select: outcome={:#?}", outcome);

// FIXME: if we kept the original cache key, we could mark projection
Expand Down
54 changes: 34 additions & 20 deletions src/librustc_data_structures/obligation_forest/mod.rs
Expand Up @@ -162,8 +162,8 @@ enum NodeState {
#[derive(Debug)]
pub struct Outcome<O, E> {
/// Obligations that were completely evaluated, including all
/// (transitive) subobligations.
pub completed: Vec<O>,
/// (transitive) subobligations. Only computed if requested.
pub completed: Option<Vec<O>>,

/// Backtrace of obligations that were found to be in error.
pub errors: Vec<Error<O, E>>,
Expand All @@ -177,6 +177,14 @@ pub struct Outcome<O, E> {
pub stalled: bool,
}

/// Should `process_obligations` compute the `Outcome::completed` field of its
/// result?
#[derive(PartialEq)]
pub enum DoCompleted {
No,
Yes,
}

#[derive(Debug, PartialEq, Eq)]
pub struct Error<O, E> {
pub error: E,
Expand Down Expand Up @@ -282,8 +290,8 @@ impl<O: ForestObligation> ObligationForest<O> {
});
}
}
let successful_obligations = self.compress();
assert!(successful_obligations.is_empty());
let successful_obligations = self.compress(DoCompleted::Yes);
assert!(successful_obligations.unwrap().is_empty());
errors
}

Expand Down Expand Up @@ -311,7 +319,8 @@ impl<O: ForestObligation> ObligationForest<O> {
/// be called in a loop until `outcome.stalled` is false.
///
/// This CANNOT be unrolled (presently, at least).
pub fn process_obligations<P>(&mut self, processor: &mut P) -> Outcome<O, P::Error>
pub fn process_obligations<P>(&mut self, processor: &mut P, do_completed: DoCompleted)
-> Outcome<O, P::Error>
where P: ObligationProcessor<Obligation=O>
{
debug!("process_obligations(len={})", self.nodes.len());
Expand Down Expand Up @@ -366,7 +375,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// There's no need to perform marking, cycle processing and compression when nothing
// changed.
return Outcome {
completed: vec![],
completed: if do_completed == DoCompleted::Yes { Some(vec![]) } else { None },
errors,
stalled,
};
Expand All @@ -376,12 +385,12 @@ impl<O: ForestObligation> ObligationForest<O> {
self.process_cycles(processor);

// Now we have to compress the result
let completed_obligations = self.compress();
let completed = self.compress(do_completed);

debug!("process_obligations: complete");

Outcome {
completed: completed_obligations,
completed,
errors,
stalled,
}
Expand Down Expand Up @@ -524,7 +533,7 @@ impl<O: ForestObligation> ObligationForest<O> {
/// Beforehand, all nodes must be marked as `Done` and no cycles
/// on these nodes may be present. This is done by e.g. `process_cycles`.
#[inline(never)]
fn compress(&mut self) -> Vec<O> {
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
let nodes_len = self.nodes.len();
let mut node_rewrites: Vec<_> = self.scratch.take().unwrap();
node_rewrites.extend(0..nodes_len);
Expand Down Expand Up @@ -573,21 +582,26 @@ impl<O: ForestObligation> ObligationForest<O> {
if dead_nodes == 0 {
node_rewrites.truncate(0);
self.scratch = Some(node_rewrites);
return vec![];
return if do_completed == DoCompleted::Yes { Some(vec![]) } else { None };
}

// Pop off all the nodes we killed and extract the success
// stories.
let successful = (0..dead_nodes)
.map(|_| self.nodes.pop().unwrap())
.flat_map(|node| {
match node.state.get() {
NodeState::Error => None,
NodeState::Done => Some(node.obligation),
_ => unreachable!()
}
})
.collect();
let successful = if do_completed == DoCompleted::Yes {
Some((0..dead_nodes)
.map(|_| self.nodes.pop().unwrap())
.flat_map(|node| {
match node.state.get() {
NodeState::Error => None,
NodeState::Done => Some(node.obligation),
_ => unreachable!()
}
})
.collect())
} else {
self.nodes.truncate(self.nodes.len() - dead_nodes);
None
};
self.apply_rewrites(&node_rewrites);

node_rewrites.truncate(0);
Expand Down

0 comments on commit dbc3c6e

Please sign in to comment.