Skip to content

[perf] test MCP510 #113382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
}
}

fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
self.borrows.initialize_start_block(body, &mut state.borrows);
self.uninits.initialize_start_block(body, &mut state.uninits);
self.ever_inits.initialize_start_block(body, &mut state.ever_inits);
}

fn apply_early_statement_effect(
Expand Down Expand Up @@ -83,30 +84,36 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
term: &'mir mir::Terminator<'tcx>,
loc: Location,
) -> TerminatorEdges<'mir, 'tcx> {
self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);
let _edges1 = self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
let _edges2 = self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
let edges3 =
self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);

// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
// analysis doesn't use.
TerminatorEdges::None
// assert_eq!(_edges1, _edges2);
// assert_eq!(_edges2, edges3);

edges3
}

fn apply_call_return_effect(
&mut self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
state: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
self.borrows.apply_call_return_effect(&mut state.borrows, block, return_places);
self.uninits.apply_call_return_effect(&mut state.uninits, block, return_places);
self.ever_inits.apply_call_return_effect(&mut state.ever_inits, block, return_places);
}
}

impl JoinSemiLattice for BorrowckDomain {
fn join(&mut self, _other: &Self) -> bool {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
fn join(&mut self, other: &Self) -> bool {
let mut changed = false;
changed |= self.borrows.join(&other.borrows);
changed |= self.uninits.join(&other.uninits);
changed |= self.ever_inits.join(&other.ever_inits);
changed
}
}

Expand Down
202 changes: 193 additions & 9 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,15 +436,19 @@ fn do_mir_borrowck<'tcx>(
// Compute and report region errors, if any.
mbcx.report_region_errors(nll_errors);

let (mut flow_analysis, flow_entry_states) =
get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
visit_results(
body,
traversal::reverse_postorder(body).map(|(bb, _)| bb),
&mut flow_analysis,
&flow_entry_states,
&mut mbcx,
);
if body.basic_blocks.is_cfg_cyclic() {
let (mut flow_analysis, flow_entry_states) =
get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
visit_results(
body,
traversal::reverse_postorder(body).map(|(bb, _)| bb),
&mut flow_analysis,
&flow_entry_states,
&mut mbcx,
);
} else {
compute_dataflow(tcx, body, &move_data, &borrow_set, &regioncx, &mut mbcx);
}

mbcx.report_move_errors();

Expand Down Expand Up @@ -497,6 +501,186 @@ fn do_mir_borrowck<'tcx>(
result
}

fn compute_dataflow<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,

move_data: &'a MoveData<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,

vis: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
) {
let borrows = Borrows::new(tcx, body, regioncx, borrow_set);
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data);
let ever_inits = EverInitializedPlaces::new(body, move_data);

let mut analysis = Borrowck { borrows, uninits, ever_inits };

// Set up lazy state for the CFG
use rustc_middle::mir;
use rustc_mir_dataflow::JoinSemiLattice;

let mut results: IndexVec<BasicBlock, Option<BorrowckDomain>> =
IndexVec::from_elem_n(None, body.basic_blocks.len());

// Ensure the start block has some state in it;
results[mir::START_BLOCK] = Some(analysis.bottom_value(body));
analysis.initialize_start_block(body, results[mir::START_BLOCK].as_mut().unwrap());

for (_idx, (block, block_data)) in traversal::reverse_postorder(body).enumerate() {
// Apply effects in block
let mut block_state = results[block].take().unwrap_or_else(|| analysis.bottom_value(body));

vis.visit_block_start(&mut block_state);

for (statement_index, statement) in block_data.statements.iter().enumerate() {
let location = Location { block, statement_index };
analysis.apply_early_statement_effect(&mut block_state, statement, location);
vis.visit_after_early_statement_effect(
&mut analysis,
&block_state,
statement,
location,
);

analysis.apply_primary_statement_effect(&mut block_state, statement, location);
vis.visit_after_primary_statement_effect(
&mut analysis,
&block_state,
statement,
location,
);
}
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_early_terminator_effect(&mut block_state, terminator, location);
vis.visit_after_early_terminator_effect(&mut analysis, &block_state, terminator, location);

let edges =
analysis.apply_primary_terminator_effect(&mut block_state, terminator, location);
vis.visit_after_primary_terminator_effect(
&mut analysis,
&block_state,
terminator,
location,
);

// notify visitor the block is ready
vis.visit_block_end(&mut block_state);

match edges {
TerminatorEdges::None => {}
TerminatorEdges::Single(target) => match results[target].as_mut() {
None => {
results[target] = Some(block_state);
}
Some(existing_state) => {
existing_state.join(&block_state);
}
},
TerminatorEdges::Double(target, unwind) if target == unwind => {
// wtf
match results[target].as_mut() {
None => {
results[target] = Some(block_state);
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}
TerminatorEdges::Double(target, unwind) => match results.pick2_mut(target, unwind) {
(None, None) => {
results[target] = Some(block_state.clone());
results[unwind] = Some(block_state);
}
(None, Some(unwind_state)) => {
unwind_state.join(&block_state);
results[target] = Some(block_state);
}
(Some(target_state), None) => {
target_state.join(&block_state);
results[unwind] = Some(block_state);
}
(Some(target_state), Some(unwind_state)) => {
target_state.join(&block_state);
unwind_state.join(&block_state);
}
},
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
// This must be done *first*, otherwise the unwind path will see the assignments.
if let Some(cleanup) = cleanup {
match results[cleanup].as_mut() {
None => {
results[cleanup] = Some(block_state.clone());
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}

if !return_.is_empty() {
analysis.apply_call_return_effect(&mut block_state, block, place);

// fixme: optimize, if we've merged the previous target states instead
// of moving, we don't need to clone it.

let target_count = return_.len();
for &target in return_.iter().take(target_count - 1) {
match results[target].as_mut() {
None => {
results[target] = Some(block_state.clone());
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}

let target = *return_.last().unwrap();
match results[target].as_mut() {
None => {
results[target] = Some(block_state.clone());
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}
}
TerminatorEdges::SwitchInt { targets, discr } => {
if let Some(_data) = analysis.get_switch_int_data(block, discr) {
todo!("wat. this is unused in tests");
} else {
let target_count = targets.all_targets().len();
for &target in targets.all_targets().iter().take(target_count - 1) {
match results[target].as_mut() {
None => {
results[target] = Some(block_state.clone());
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}

let target = *targets.all_targets().last().unwrap();
match results[target].as_mut() {
None => {
results[target] = Some(block_state.clone());
}
Some(existing_state) => {
existing_state.join(&block_state);
}
}
}
}
}
}
}

fn get_flow_results<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/mir/basic_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct Cache {
predecessors: OnceLock<Predecessors>,
reverse_postorder: OnceLock<Vec<BasicBlock>>,
dominators: OnceLock<Dominators<BasicBlock>>,
is_cyclic: OnceLock<bool>,
}

impl<'tcx> BasicBlocks<'tcx> {
Expand All @@ -45,6 +46,12 @@ impl<'tcx> BasicBlocks<'tcx> {
self.cache.dominators.get_or_init(|| dominators(self))
}

/// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
#[inline]
pub fn is_cfg_cyclic(&self) -> bool {
*self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self))
}

/// Returns predecessors for each basic block.
#[inline]
pub fn predecessors(&self) -> &Predecessors {
Expand Down
Loading