diff options
| author | bors <bors@rust-lang.org> | 2021-12-04 05:59:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-12-04 05:59:16 +0000 |
| commit | 887999d163bace7e79370b952bdd1f930ff4cdd5 (patch) | |
| tree | 0b2a5642dfe49a0cebe9744394169acebf412ccc /compiler/rustc_mir_dataflow/src/framework | |
| parent | f5815727786aa1ed2793af05cf65c5d79c290c67 (diff) | |
| parent | 3dbb621c72e57c7eee9c10f20316d76c59168f83 (diff) | |
| download | rust-887999d163bace7e79370b952bdd1f930ff4cdd5.tar.gz rust-887999d163bace7e79370b952bdd1f930ff4cdd5.zip | |
Auto merge of #88439 - cynecx:unwind_asm, r=Amanieu
Unwinding support for inline assembly r? `@Amanieu`
Diffstat (limited to 'compiler/rustc_mir_dataflow/src/framework')
4 files changed, 110 insertions, 31 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 8a9ced91eb3..6131ee79818 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -4,7 +4,9 @@ use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; +use super::{ + Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget, +}; pub trait Direction { fn is_forward() -> bool; @@ -235,14 +237,26 @@ impl Direction for Backward { // Apply terminator-specific edge effects. // // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally. - mir::TerminatorKind::Call { - destination: Some((return_place, dest)), - ref func, - ref args, - .. + mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. } + if dest == bb => + { + let mut tmp = exit_state.clone(); + analysis.apply_call_return_effect( + &mut tmp, + pred, + CallReturnPlaces::Call(return_place), + ); + propagate(pred, &tmp); + } + mir::TerminatorKind::InlineAsm { + destination: Some(dest), ref operands, .. } if dest == bb => { let mut tmp = exit_state.clone(); - analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place); + analysis.apply_call_return_effect( + &mut tmp, + pred, + CallReturnPlaces::InlineAsm(operands), + ); propagate(pred, &tmp); } @@ -258,6 +272,7 @@ impl Direction for Backward { | mir::TerminatorKind::Drop { unwind: Some(unwind), .. } | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. } | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. } + | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. } if unwind == bb => { if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { @@ -467,7 +482,7 @@ impl Direction for Forward { propagate(target, exit_state); } - Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => { + Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => { if let Some(unwind) = cleanup { if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { propagate(unwind, exit_state); @@ -477,13 +492,37 @@ impl Direction for Forward { if let Some((dest_place, target)) = destination { // N.B.: This must be done *last*, otherwise the unwind path will see the call // return effect. - analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place); + analysis.apply_call_return_effect( + exit_state, + bb, + CallReturnPlaces::Call(dest_place), + ); propagate(target, exit_state); } } - InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => { + InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination, + cleanup, + } => { + if let Some(unwind) = cleanup { + if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { + propagate(unwind, exit_state); + } + } + if let Some(target) = destination { + // N.B.: This must be done *last*, otherwise the unwind path will see the call + // return effect. + analysis.apply_call_return_effect( + exit_state, + bb, + CallReturnPlaces::InlineAsm(operands), + ); propagate(target, exit_state); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index a370f8e40f9..517bc086ef6 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::graphviz_safe_def_name; use rustc_middle::mir::{self, BasicBlock, Body, Location}; use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; -use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor}; +use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum OutputStyle { @@ -231,16 +231,15 @@ where // for the basic block itself. That way, we could display terminator-specific effects for // backward dataflow analyses as well as effects for `SwitchInt` terminators. match terminator.kind { - mir::TerminatorKind::Call { - destination: Some((return_place, _)), - ref func, - ref args, - .. - } => { + mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { let state_on_unwind = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { - analysis.apply_call_return_effect(state, block, func, args, return_place); + analysis.apply_call_return_effect( + state, + block, + CallReturnPlaces::Call(return_place), + ); }); write!( @@ -278,6 +277,31 @@ where })?; } + mir::TerminatorKind::InlineAsm { destination: Some(_), ref operands, .. } => { + self.write_row(w, "", "(on successful return)", |this, w, fmt| { + let state_on_unwind = this.results.get().clone(); + this.results.apply_custom_effect(|analysis, state| { + analysis.apply_call_return_effect( + state, + block, + CallReturnPlaces::InlineAsm(operands), + ); + }); + + write!( + w, + r#"<td balign="left" colspan="{colspan}" {fmt} align="left">{diff}</td>"#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_unwind, + this.results.analysis() + ), + ) + })?; + } + _ => {} }; diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index f0c9ac4c504..500fba8b114 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -160,9 +160,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { &self, state: &mut Self::Domain, block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, + return_places: CallReturnPlaces<'_, 'tcx>, ); /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator. @@ -276,9 +274,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { &self, trans: &mut impl GenKill<Self::Idx>, block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, + return_places: CallReturnPlaces<'_, 'tcx>, ); /// See `Analysis::apply_yield_resume_effect`. @@ -347,11 +343,9 @@ where &self, state: &mut A::Domain, block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, + return_places: CallReturnPlaces<'_, 'tcx>, ) { - self.call_return_effect(state, block, func, args, return_place); + self.call_return_effect(state, block, return_places); } fn apply_yield_resume_effect( @@ -542,5 +536,29 @@ pub trait SwitchIntEdgeEffects<D> { fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); } +/// List of places that are written to after a successful (non-unwind) return +/// from a `Call` or `InlineAsm`. +pub enum CallReturnPlaces<'a, 'tcx> { + Call(mir::Place<'tcx>), + InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]), +} + +impl<'tcx> CallReturnPlaces<'_, 'tcx> { + pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) { + match *self { + Self::Call(place) => f(place), + Self::InlineAsm(operands) => { + for op in operands { + match *op { + mir::InlineAsmOperand::Out { place: Some(place), .. } + | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place), + _ => {} + } + } + } + } + } +} + #[cfg(test)] mod tests; diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 6efa8daec48..01ca8ca9258 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -220,9 +220,7 @@ impl<D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { &self, _state: &mut Self::Domain, _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _return_place: mir::Place<'tcx>, + _return_places: CallReturnPlaces<'_, 'tcx>, ) { } } |
