optimize promote_consts
by cache the validate check
This commit is contained in:
parent
4799baa70d
commit
cb7f116c04
1 changed files with 69 additions and 40 deletions
|
@ -60,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
|
||||||
|
|
||||||
let mut rpo = traversal::reverse_postorder(body);
|
let mut rpo = traversal::reverse_postorder(body);
|
||||||
let ccx = ConstCx::new(tcx, body);
|
let ccx = ConstCx::new(tcx, body);
|
||||||
let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
|
let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
|
||||||
|
|
||||||
let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
|
let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
|
||||||
|
|
||||||
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
|
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
|
||||||
self.promoted_fragments.set(promoted);
|
self.promoted_fragments.set(promoted);
|
||||||
|
@ -77,7 +77,7 @@ pub enum TempState {
|
||||||
/// One direct assignment and any number of direct uses.
|
/// One direct assignment and any number of direct uses.
|
||||||
/// A borrow of this temp is promotable if the assigned
|
/// A borrow of this temp is promotable if the assigned
|
||||||
/// value is qualified as constant.
|
/// value is qualified as constant.
|
||||||
Defined { location: Location, uses: usize },
|
Defined { location: Location, uses: usize, valid: Valid },
|
||||||
/// Any other combination of assignments/uses.
|
/// Any other combination of assignments/uses.
|
||||||
Unpromotable,
|
Unpromotable,
|
||||||
/// This temp was part of an rvalue which got extracted
|
/// This temp was part of an rvalue which got extracted
|
||||||
|
@ -85,6 +85,13 @@ pub enum TempState {
|
||||||
PromotedOut,
|
PromotedOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Valid {
|
||||||
|
Unknown,
|
||||||
|
InValid,
|
||||||
|
Validated,
|
||||||
|
}
|
||||||
|
|
||||||
impl TempState {
|
impl TempState {
|
||||||
pub fn is_promotable(&self) -> bool {
|
pub fn is_promotable(&self) -> bool {
|
||||||
debug!("is_promotable: self={:?}", self);
|
debug!("is_promotable: self={:?}", self);
|
||||||
|
@ -133,7 +140,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
||||||
match context {
|
match context {
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Store)
|
PlaceContext::MutatingUse(MutatingUseContext::Store)
|
||||||
| PlaceContext::MutatingUse(MutatingUseContext::Call) => {
|
| PlaceContext::MutatingUse(MutatingUseContext::Call) => {
|
||||||
*temp = TempState::Defined { location, uses: 0 };
|
*temp = TempState::Defined { location, uses: 0, valid: Valid::Unknown };
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => { /* mark as unpromotable below */ }
|
_ => { /* mark as unpromotable below */ }
|
||||||
|
@ -188,7 +195,7 @@ pub fn collect_temps_and_candidates<'tcx>(
|
||||||
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
|
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
|
||||||
struct Validator<'a, 'tcx> {
|
struct Validator<'a, 'tcx> {
|
||||||
ccx: &'a ConstCx<'a, 'tcx>,
|
ccx: &'a ConstCx<'a, 'tcx>,
|
||||||
temps: &'a IndexVec<Local, TempState>,
|
temps: &'a mut IndexVec<Local, TempState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
|
impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
|
||||||
|
@ -202,7 +209,7 @@ impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
|
||||||
struct Unpromotable;
|
struct Unpromotable;
|
||||||
|
|
||||||
impl<'tcx> Validator<'_, 'tcx> {
|
impl<'tcx> Validator<'_, 'tcx> {
|
||||||
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
|
fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> {
|
||||||
let loc = candidate.location;
|
let loc = candidate.location;
|
||||||
let statement = &self.body[loc.block].statements[loc.statement_index];
|
let statement = &self.body[loc.block].statements[loc.statement_index];
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
|
@ -234,7 +241,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(eddyb) maybe cache this?
|
// FIXME(eddyb) maybe cache this?
|
||||||
fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
|
fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool {
|
||||||
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
||||||
let num_stmts = self.body[loc.block].statements.len();
|
let num_stmts = self.body[loc.block].statements.len();
|
||||||
|
|
||||||
|
@ -272,32 +279,54 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(eddyb) maybe cache this?
|
fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> {
|
||||||
fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
|
if let TempState::Defined { location: loc, uses, valid } = self.temps[local] {
|
||||||
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
match valid {
|
||||||
let block = &self.body[loc.block];
|
Valid::InValid => Err(Unpromotable),
|
||||||
let num_stmts = block.statements.len();
|
Valid::Validated => Ok(()),
|
||||||
|
Valid::Unknown => {
|
||||||
|
let ok = {
|
||||||
|
let block = &self.body[loc.block];
|
||||||
|
let num_stmts = block.statements.len();
|
||||||
|
|
||||||
if loc.statement_index < num_stmts {
|
if loc.statement_index < num_stmts {
|
||||||
let statement = &block.statements[loc.statement_index];
|
let statement = &block.statements[loc.statement_index];
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
|
StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
statement.source_info.span,
|
statement.source_info.span,
|
||||||
"{:?} is not an assignment",
|
"{:?} is not an assignment",
|
||||||
statement
|
statement
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let terminator = block.terminator();
|
let terminator = block.terminator();
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
|
TerminatorKind::Call { func, args, .. } => {
|
||||||
TerminatorKind::Yield { .. } => Err(Unpromotable),
|
self.validate_call(func, args)
|
||||||
kind => {
|
}
|
||||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
TerminatorKind::Yield { .. } => Err(Unpromotable),
|
||||||
}
|
kind => {
|
||||||
|
span_bug!(
|
||||||
|
terminator.source_info.span,
|
||||||
|
"{:?} not promotable",
|
||||||
|
kind
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.temps[local] = TempState::Defined {
|
||||||
|
location: loc,
|
||||||
|
uses,
|
||||||
|
valid: match ok {
|
||||||
|
Ok(()) => Valid::Validated,
|
||||||
|
Err(_) => Valid::InValid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +334,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
|
fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
|
||||||
match place.last_projection() {
|
match place.last_projection() {
|
||||||
None => self.validate_local(place.local),
|
None => self.validate_local(place.local),
|
||||||
Some((place_base, elem)) => {
|
Some((place_base, elem)) => {
|
||||||
|
@ -417,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
|
fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()),
|
Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()),
|
||||||
|
|
||||||
|
@ -447,7 +476,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
|
fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
|
||||||
match kind {
|
match kind {
|
||||||
// Reject these borrow types just to be safe.
|
// Reject these borrow types just to be safe.
|
||||||
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
||||||
|
@ -480,7 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
|
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
|
||||||
self.validate_operand(operand)?;
|
self.validate_operand(operand)?;
|
||||||
|
@ -623,7 +652,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_call(
|
fn validate_call(
|
||||||
&self,
|
&mut self,
|
||||||
callee: &Operand<'tcx>,
|
callee: &Operand<'tcx>,
|
||||||
args: &[Operand<'tcx>],
|
args: &[Operand<'tcx>],
|
||||||
) -> Result<(), Unpromotable> {
|
) -> Result<(), Unpromotable> {
|
||||||
|
@ -665,10 +694,10 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
|
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
|
||||||
pub fn validate_candidates(
|
pub fn validate_candidates(
|
||||||
ccx: &ConstCx<'_, '_>,
|
ccx: &ConstCx<'_, '_>,
|
||||||
temps: &IndexVec<Local, TempState>,
|
temps: &mut IndexVec<Local, TempState>,
|
||||||
candidates: &[Candidate],
|
candidates: &[Candidate],
|
||||||
) -> Vec<Candidate> {
|
) -> Vec<Candidate> {
|
||||||
let validator = Validator { ccx, temps };
|
let mut validator = Validator { ccx, temps };
|
||||||
|
|
||||||
candidates
|
candidates
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -720,7 +749,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
fn promote_temp(&mut self, temp: Local) -> Local {
|
fn promote_temp(&mut self, temp: Local) -> Local {
|
||||||
let old_keep_original = self.keep_original;
|
let old_keep_original = self.keep_original;
|
||||||
let loc = match self.temps[temp] {
|
let loc = match self.temps[temp] {
|
||||||
TempState::Defined { location, uses } if uses > 0 => {
|
TempState::Defined { location, uses, .. } if uses > 0 => {
|
||||||
if uses > 1 {
|
if uses > 1 {
|
||||||
self.keep_original = true;
|
self.keep_original = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue