Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//! NRVO on acyclic CFGs.
use crate::transform::{MirPass, MirSource};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
read_only, Body, BodyAndCache, Constant, Local, LocalKind, Location, Operand, Place, Rvalue,
StatementKind, Statement,
};
use rustc_middle::ty::TyCtxt;
use rustc_index::vec::IndexVec;
pub struct Nrvo;
impl<'tcx> MirPass<'tcx> for Nrvo {
fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
// We only run when the MIR optimization level is > 1.
if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
return;
}
// We do not handle cyclic CFGs yet.
if body.is_cfg_cyclic() {
return;
}
// Determine candidate pairs of locals.
let find = FindCandidates::new(body);
find.visit_body(body);
for candidate in find.into_candidate_iter() {
}
}
}
struct CandidateAssignment {
dest: Local,
src: Local,
loc: Location,
}
struct FindCandidates {
/// Collects assignments of the form `dest = src;`.
local_assignments: IndexVec<Local, Vec<(Local, Location)>>,
}
impl FindCandidates {
fn new(body: &Body<'_>) -> Self {
Self {
local_assignments: IndexVec::from_elem_n(Vec::new(), body.local_decls.len()),
}
}
fn into_candidate_iter(self) -> impl Iterator<Item = CandidateAssignment> {
self.local_assignments.into_iter_enumerated().flat_map(|(dest, vec)| {
vec.into_iter().map(move |(src, loc)| CandidateAssignment {
dest, src, loc,
})
})
}
}
impl<'tcx> Visitor<'tcx> for FindCandidates {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match &statement.kind {
StatementKind::Assign(box (dest, Rvalue::Use(operand))) => {
if let Some(src) = operand.place() {
// We only care about direct local-to-local assignments.
if dest.projection.is_empty() && src.projection.is_empty() {
self.local_assignments[dest.local].push((src.local, location));
}
}
}
_ => {}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment