1
Fork 0

Add initial AST and MIR support for unwinding from inline assembly

This commit is contained in:
Amanieu d'Antras 2021-08-30 01:23:33 +01:00 committed by cynecx
parent 532d2b14c0
commit 940b2eabad
39 changed files with 355 additions and 212 deletions

View file

@ -1,6 +1,6 @@
use super::*;
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
@ -84,9 +84,7 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
_dest_place: mir::Place<'tcx>,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}

View file

@ -2,7 +2,7 @@
//!
//! A local will be maybe initialized if *any* projections of that local might be initialized.
use crate::GenKill;
use crate::{CallReturnPlaces, GenKill};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
@ -53,11 +53,9 @@ impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
&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>,
) {
trans.gen(return_place.local)
return_places.for_each(|place| trans.gen(place.local));
}
/// See `Analysis::apply_yield_resume_effect`.
@ -83,7 +81,11 @@ where
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
match context {
// These are handled specially in `call_return_effect` and `yield_resume_effect`.
PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
PlaceContext::MutatingUse(
MutatingUseContext::Call
| MutatingUseContext::AsmOutput
| MutatingUseContext::Yield,
) => {}
// Otherwise, when a place is mutated, we must consider it possibly initialized.
PlaceContext::MutatingUse(_) => self.trans.gen(local),

View file

@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Local, Location};
use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
/// A [live-variable dataflow analysis][liveness].
///
@ -94,13 +94,13 @@ impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
dest_place: mir::Place<'tcx>,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
if let Some(local) = dest_place.as_local() {
trans.kill(local);
}
return_places.for_each(|place| {
if let Some(local) = place.as_local() {
trans.kill(local);
}
});
}
fn yield_resume_effect(
@ -167,12 +167,16 @@ impl DefUse {
// destination place for a `Call` return or `Yield` resume respectively. Since this is
// only a `Def` when the function returns successfully, we handle this case separately
// in `call_return_effect` above.
PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
PlaceContext::MutatingUse(
MutatingUseContext::Call
| MutatingUseContext::AsmOutput
| MutatingUseContext::Yield,
) => None,
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
| MutatingUseContext::AsmOutput
| MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,

View file

@ -11,7 +11,7 @@ use rustc_middle::ty::{self, TyCtxt};
use crate::drop_flag_effects_for_function_entry;
use crate::drop_flag_effects_for_location;
use crate::elaborate_drops::DropFlagState;
use crate::framework::SwitchIntEdgeEffects;
use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects};
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::on_lookup_result_bits;
use crate::MoveDataParamEnv;
@ -354,21 +354,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
dest_place: mir::Place<'tcx>,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| {
trans.gen(mpi);
},
);
return_places.for_each(|place| {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.gen(mpi);
},
);
});
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@ -472,21 +472,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
dest_place: mir::Place<'tcx>,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 0 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| {
trans.kill(mpi);
},
);
return_places.for_each(|place| {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 0 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.kill(mpi);
},
);
});
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@ -591,21 +591,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
dest_place: mir::Place<'tcx>,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| {
trans.gen(mpi);
},
);
return_places.for_each(|place| {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(
self.tcx,
self.body,
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.gen(mpi);
},
);
});
}
}
@ -679,9 +679,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
_dest_place: mir::Place<'tcx>,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
let move_data = self.move_data();
let init_loc_map = &move_data.init_loc_map;

View file

@ -1,7 +1,7 @@
pub use super::*;
use crate::storage::AlwaysLiveLocals;
use crate::{GenKill, Results, ResultsRefCursor};
use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use std::cell::RefCell;
@ -68,9 +68,7 @@ impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
&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>,
) {
// Nothing to do when a call returns successfully
}
@ -226,7 +224,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
terminator: &mir::Terminator<'tcx>,
loc: Location,
) {
match &terminator.kind {
match terminator.kind {
// For call terminators the destination requires storage for the call
// and after the call returns successfully, but not after a panic.
// Since `propagate_call_unwind` doesn't exist, we have to kill the
@ -235,6 +233,11 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
trans.kill(place.local);
}
// The same applies to InlineAsm outputs.
TerminatorKind::InlineAsm { ref operands, .. } => {
CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
}
// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.
TerminatorKind::Call { destination: None, .. }
@ -247,7 +250,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::Goto { .. }
| TerminatorKind::InlineAsm { .. }
| TerminatorKind::Resume
| TerminatorKind::Return
| TerminatorKind::SwitchInt { .. }
@ -261,11 +263,9 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
&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>,
) {
trans.gen(return_place.local);
return_places.for_each(|place| trans.gen(place.local));
}
fn yield_resume_effect(