2015-11-03 05:35:09 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-06-20 15:55:14 -05:00
|
|
|
//! An analysis to determine which locals require allocas and
|
2015-11-03 05:35:09 -06:00
|
|
|
//! which do not.
|
|
|
|
|
2016-01-21 10:57:43 -06:00
|
|
|
use rustc_data_structures::bitvec::BitVector;
|
2016-06-07 09:28:36 -05:00
|
|
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
2017-03-07 09:09:01 -06:00
|
|
|
use rustc::middle::const_val::ConstVal;
|
|
|
|
use rustc::mir::{self, Location, TerminatorKind, Literal};
|
2017-12-01 06:31:47 -06:00
|
|
|
use rustc::mir::visit::{Visitor, PlaceContext};
|
2016-06-05 11:38:22 -05:00
|
|
|
use rustc::mir::traversal;
|
2017-08-04 03:25:13 -05:00
|
|
|
use rustc::ty;
|
2017-09-20 10:17:23 -05:00
|
|
|
use rustc::ty::layout::LayoutOf;
|
2017-09-21 12:40:50 -05:00
|
|
|
use type_of::LayoutLlvmExt;
|
2018-01-04 23:34:28 -06:00
|
|
|
use super::FunctionCx;
|
2015-11-03 05:35:09 -06:00
|
|
|
|
2018-01-04 23:34:28 -06:00
|
|
|
pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
|
|
|
|
let mir = fx.mir;
|
|
|
|
let mut analyzer = LocalAnalyzer::new(fx);
|
2015-11-03 05:35:09 -06:00
|
|
|
|
|
|
|
analyzer.visit_mir(mir);
|
|
|
|
|
2016-09-24 18:38:27 -05:00
|
|
|
for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
|
2018-01-04 23:34:28 -06:00
|
|
|
let ty = fx.monomorphize(&ty);
|
2016-06-20 15:55:14 -05:00
|
|
|
debug!("local {} has type {:?}", index, ty);
|
2018-01-04 23:34:28 -06:00
|
|
|
let layout = fx.cx.layout_of(ty);
|
2017-10-04 20:22:23 -05:00
|
|
|
if layout.is_llvm_immediate() {
|
2015-11-03 05:35:09 -06:00
|
|
|
// These sorts of types are immediates that we can store
|
|
|
|
// in an ValueRef without an alloca.
|
2017-10-06 02:25:35 -05:00
|
|
|
} else if layout.is_llvm_scalar_pair() {
|
2016-05-25 03:58:08 -05:00
|
|
|
// We allow pairs and uses of any of their 2 fields.
|
2015-11-03 05:35:09 -06:00
|
|
|
} else {
|
|
|
|
// These sorts of types require an alloca. Note that
|
2017-09-21 12:40:50 -05:00
|
|
|
// is_llvm_immediate() may *still* be true, particularly
|
2015-11-03 05:35:09 -06:00
|
|
|
// for newtypes, but we currently force some types
|
|
|
|
// (e.g. structs) into an alloca unconditionally, just so
|
|
|
|
// that we don't have to deal with having two pathways
|
2015-11-03 14:50:04 -06:00
|
|
|
// (gep vs extractvalue etc).
|
2017-12-01 06:39:51 -06:00
|
|
|
analyzer.mark_as_memory(mir::Local::new(index));
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
analyzer.memory_locals
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2016-12-17 20:54:32 -06:00
|
|
|
struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> {
|
2018-01-04 23:34:28 -06:00
|
|
|
fx: &'mir FunctionCx<'a, 'tcx>,
|
2017-12-01 06:39:51 -06:00
|
|
|
memory_locals: BitVector,
|
2016-01-21 10:57:43 -06:00
|
|
|
seen_assigned: BitVector
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2016-12-17 20:54:32 -06:00
|
|
|
impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> {
|
2018-01-04 23:34:28 -06:00
|
|
|
fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> {
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
let mut analyzer = LocalAnalyzer {
|
2018-01-04 23:34:28 -06:00
|
|
|
fx,
|
|
|
|
memory_locals: BitVector::new(fx.mir.local_decls.len()),
|
|
|
|
seen_assigned: BitVector::new(fx.mir.local_decls.len())
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// Arguments get assigned to by means of the function being called
|
2018-01-04 23:34:28 -06:00
|
|
|
for idx in 0..fx.mir.arg_count {
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
analyzer.seen_assigned.insert(idx + 1);
|
2016-01-21 10:57:43 -06:00
|
|
|
}
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
|
|
|
|
analyzer
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
fn mark_as_memory(&mut self, local: mir::Local) {
|
|
|
|
debug!("marking {:?} as memory", local);
|
|
|
|
self.memory_locals.insert(local.index());
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
2016-01-21 10:57:43 -06:00
|
|
|
|
2016-06-20 15:55:14 -05:00
|
|
|
fn mark_assigned(&mut self, local: mir::Local) {
|
|
|
|
if !self.seen_assigned.insert(local.index()) {
|
2017-12-01 06:39:51 -06:00
|
|
|
self.mark_as_memory(local);
|
2016-01-21 10:57:43 -06:00
|
|
|
}
|
|
|
|
}
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2016-12-17 20:54:32 -06:00
|
|
|
impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
2015-11-03 05:35:09 -06:00
|
|
|
fn visit_assign(&mut self,
|
|
|
|
block: mir::BasicBlock,
|
2017-12-01 06:39:51 -06:00
|
|
|
place: &mir::Place<'tcx>,
|
2016-08-08 20:46:06 -05:00
|
|
|
rvalue: &mir::Rvalue<'tcx>,
|
|
|
|
location: Location) {
|
2017-12-01 06:39:51 -06:00
|
|
|
debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue);
|
2015-11-03 05:35:09 -06:00
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
if let mir::Place::Local(index) = *place {
|
2016-06-20 15:55:14 -05:00
|
|
|
self.mark_assigned(index);
|
2018-01-04 23:34:28 -06:00
|
|
|
if !self.fx.rvalue_creates_operand(rvalue) {
|
2017-12-01 06:39:51 -06:00
|
|
|
self.mark_as_memory(index);
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
2016-06-20 15:55:14 -05:00
|
|
|
} else {
|
2017-12-01 06:39:51 -06:00
|
|
|
self.visit_place(place, PlaceContext::Store, location);
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2016-08-08 20:46:06 -05:00
|
|
|
self.visit_rvalue(rvalue, location);
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2016-06-20 15:55:14 -05:00
|
|
|
fn visit_terminator_kind(&mut self,
|
|
|
|
block: mir::BasicBlock,
|
2016-08-08 20:46:06 -05:00
|
|
|
kind: &mir::TerminatorKind<'tcx>,
|
|
|
|
location: Location) {
|
2016-06-20 15:55:14 -05:00
|
|
|
match *kind {
|
|
|
|
mir::TerminatorKind::Call {
|
2017-05-11 17:38:26 -05:00
|
|
|
func: mir::Operand::Constant(box mir::Constant {
|
2017-03-07 09:09:01 -06:00
|
|
|
literal: Literal::Value {
|
2017-08-04 03:25:13 -05:00
|
|
|
value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
|
2017-03-07 09:09:01 -06:00
|
|
|
}, ..
|
2016-06-20 15:55:14 -05:00
|
|
|
}),
|
|
|
|
ref args, ..
|
2018-01-04 23:34:28 -06:00
|
|
|
} if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => {
|
2016-06-20 15:55:14 -05:00
|
|
|
// box_free(x) shares with `drop x` the property that it
|
|
|
|
// is not guaranteed to be statically dominated by the
|
|
|
|
// definition of x, so x must always be in an alloca.
|
2017-12-01 06:39:51 -06:00
|
|
|
if let mir::Operand::Move(ref place) = args[0] {
|
|
|
|
self.visit_place(place, PlaceContext::Drop, location);
|
2016-06-20 15:55:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2016-08-08 20:46:06 -05:00
|
|
|
self.super_terminator_kind(block, kind, location);
|
2016-06-20 15:55:14 -05:00
|
|
|
}
|
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
fn visit_place(&mut self,
|
|
|
|
place: &mir::Place<'tcx>,
|
2017-12-01 06:31:47 -06:00
|
|
|
context: PlaceContext<'tcx>,
|
2016-08-08 20:46:06 -05:00
|
|
|
location: Location) {
|
2017-12-01 06:39:51 -06:00
|
|
|
debug!("visit_place(place={:?}, context={:?})", place, context);
|
2018-01-04 23:34:28 -06:00
|
|
|
let cx = self.fx.cx;
|
2015-11-03 05:35:09 -06:00
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
if let mir::Place::Projection(ref proj) = *place {
|
2017-10-08 18:31:06 -05:00
|
|
|
// Allow uses of projections that are ZSTs or from scalar fields.
|
2017-11-17 09:19:57 -06:00
|
|
|
let is_consume = match context {
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::Copy | PlaceContext::Move => true,
|
2017-11-17 09:19:57 -06:00
|
|
|
_ => false
|
|
|
|
};
|
|
|
|
if is_consume {
|
2018-01-04 23:34:28 -06:00
|
|
|
let base_ty = proj.base.ty(self.fx.mir, cx.tcx);
|
|
|
|
let base_ty = self.fx.monomorphize(&base_ty);
|
2017-10-08 16:38:10 -05:00
|
|
|
|
|
|
|
// ZSTs don't require any actual memory access.
|
2018-01-04 23:04:08 -06:00
|
|
|
let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx);
|
2018-01-04 23:34:28 -06:00
|
|
|
let elem_ty = self.fx.monomorphize(&elem_ty);
|
2018-01-04 23:04:08 -06:00
|
|
|
if cx.layout_of(elem_ty).is_zst() {
|
2017-10-08 16:38:10 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let mir::ProjectionElem::Field(..) = proj.elem {
|
2018-01-04 23:04:08 -06:00
|
|
|
let layout = cx.layout_of(base_ty.to_ty(cx.tcx));
|
2017-10-08 18:31:06 -05:00
|
|
|
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
|
2017-11-17 09:19:57 -06:00
|
|
|
// Recurse with the same context, instead of `Projection`,
|
2017-10-08 16:38:10 -05:00
|
|
|
// potentially stopping at non-operand projections,
|
2017-12-01 06:39:51 -06:00
|
|
|
// which would trigger `mark_as_memory` on locals.
|
|
|
|
self.visit_place(&proj.base, context, location);
|
2017-10-08 16:38:10 -05:00
|
|
|
return;
|
2016-05-25 03:58:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
// A deref projection only reads the pointer, never needs the place.
|
2017-09-03 11:14:31 -05:00
|
|
|
if let mir::ProjectionElem::Deref = proj.elem {
|
2017-12-01 06:39:51 -06:00
|
|
|
return self.visit_place(&proj.base, PlaceContext::Copy, location);
|
2017-09-03 11:14:31 -05:00
|
|
|
}
|
|
|
|
}
|
2016-08-13 22:34:14 -05:00
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
self.super_place(place, context, location);
|
2017-09-03 11:14:31 -05:00
|
|
|
}
|
2016-08-13 22:34:14 -05:00
|
|
|
|
2017-09-03 11:14:31 -05:00
|
|
|
fn visit_local(&mut self,
|
|
|
|
&index: &mir::Local,
|
2017-12-01 06:31:47 -06:00
|
|
|
context: PlaceContext<'tcx>,
|
2017-09-03 11:14:31 -05:00
|
|
|
_: Location) {
|
|
|
|
match context {
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::Call => {
|
2017-09-03 11:14:31 -05:00
|
|
|
self.mark_assigned(index);
|
|
|
|
}
|
2016-08-13 22:34:14 -05:00
|
|
|
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::StorageLive |
|
|
|
|
PlaceContext::StorageDead |
|
|
|
|
PlaceContext::Validate |
|
|
|
|
PlaceContext::Copy |
|
|
|
|
PlaceContext::Move => {}
|
2016-06-09 10:15:15 -05:00
|
|
|
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::Inspect |
|
|
|
|
PlaceContext::Store |
|
2017-12-19 16:05:14 -06:00
|
|
|
PlaceContext::AsmOutput |
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::Borrow { .. } |
|
|
|
|
PlaceContext::Projection(..) => {
|
2017-12-01 06:39:51 -06:00
|
|
|
self.mark_as_memory(index);
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
|
2017-12-01 06:31:47 -06:00
|
|
|
PlaceContext::Drop => {
|
2018-01-04 23:34:28 -06:00
|
|
|
let ty = mir::Place::Local(index).ty(self.fx.mir, self.fx.cx.tcx);
|
|
|
|
let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
|
2017-09-03 11:14:31 -05:00
|
|
|
|
2017-12-01 06:39:51 -06:00
|
|
|
// Only need the place if we're actually dropping it.
|
2018-01-04 23:34:28 -06:00
|
|
|
if self.fx.cx.type_needs_drop(ty) {
|
2017-12-01 06:39:51 -06:00
|
|
|
self.mark_as_memory(index);
|
2017-09-03 11:14:31 -05:00
|
|
|
}
|
2016-06-09 10:14:47 -05:00
|
|
|
}
|
|
|
|
}
|
2015-11-03 05:35:09 -06:00
|
|
|
}
|
|
|
|
}
|
2016-05-29 14:01:06 -05:00
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum CleanupKind {
|
|
|
|
NotCleanup,
|
|
|
|
Funclet,
|
|
|
|
Internal { funclet: mir::BasicBlock }
|
|
|
|
}
|
|
|
|
|
2017-05-23 15:47:15 -05:00
|
|
|
impl CleanupKind {
|
|
|
|
pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
|
|
|
|
match self {
|
|
|
|
CleanupKind::NotCleanup => None,
|
|
|
|
CleanupKind::Funclet => Some(for_bb),
|
|
|
|
CleanupKind::Internal { funclet } => Some(funclet),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-17 20:54:32 -06:00
|
|
|
pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock, CleanupKind> {
|
2016-06-07 09:28:36 -05:00
|
|
|
fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
|
|
|
|
mir: &mir::Mir<'tcx>) {
|
2016-06-07 13:20:50 -05:00
|
|
|
for (bb, data) in mir.basic_blocks().iter_enumerated() {
|
2016-05-29 14:01:06 -05:00
|
|
|
match data.terminator().kind {
|
|
|
|
TerminatorKind::Goto { .. } |
|
|
|
|
TerminatorKind::Resume |
|
2017-12-18 18:17:16 -06:00
|
|
|
TerminatorKind::Abort |
|
2016-05-29 14:01:06 -05:00
|
|
|
TerminatorKind::Return |
|
2016-12-26 07:34:03 -06:00
|
|
|
TerminatorKind::GeneratorDrop |
|
2016-06-08 11:26:19 -05:00
|
|
|
TerminatorKind::Unreachable |
|
2016-12-26 07:34:03 -06:00
|
|
|
TerminatorKind::SwitchInt { .. } |
|
2017-10-13 08:36:15 -05:00
|
|
|
TerminatorKind::Yield { .. } |
|
|
|
|
TerminatorKind::FalseEdges { .. } => {
|
2016-05-29 14:01:06 -05:00
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
TerminatorKind::Call { cleanup: unwind, .. } |
|
2016-05-25 00:39:32 -05:00
|
|
|
TerminatorKind::Assert { cleanup: unwind, .. } |
|
2016-05-29 14:01:06 -05:00
|
|
|
TerminatorKind::DropAndReplace { unwind, .. } |
|
|
|
|
TerminatorKind::Drop { unwind, .. } => {
|
|
|
|
if let Some(unwind) = unwind {
|
|
|
|
debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
|
|
|
|
bb, data, unwind);
|
2016-06-07 09:28:36 -05:00
|
|
|
result[unwind] = CleanupKind::Funclet;
|
2016-05-29 14:01:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-07 09:28:36 -05:00
|
|
|
fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
|
|
|
|
mir: &mir::Mir<'tcx>) {
|
2016-06-07 13:20:50 -05:00
|
|
|
let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());
|
2016-05-29 14:01:06 -05:00
|
|
|
|
|
|
|
let mut set_successor = |funclet: mir::BasicBlock, succ| {
|
2016-06-07 09:28:36 -05:00
|
|
|
match funclet_succs[funclet] {
|
2016-05-29 14:01:06 -05:00
|
|
|
ref mut s @ None => {
|
|
|
|
debug!("set_successor: updating successor of {:?} to {:?}",
|
|
|
|
funclet, succ);
|
|
|
|
*s = Some(succ);
|
|
|
|
},
|
|
|
|
Some(s) => if s != succ {
|
|
|
|
span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}",
|
|
|
|
funclet, s, succ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for (bb, data) in traversal::reverse_postorder(mir) {
|
2016-06-07 09:28:36 -05:00
|
|
|
let funclet = match result[bb] {
|
2016-05-29 14:01:06 -05:00
|
|
|
CleanupKind::NotCleanup => continue,
|
|
|
|
CleanupKind::Funclet => bb,
|
|
|
|
CleanupKind::Internal { funclet } => funclet,
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
|
2016-06-07 09:28:36 -05:00
|
|
|
bb, data, result[bb], funclet);
|
2016-05-29 14:01:06 -05:00
|
|
|
|
|
|
|
for &succ in data.terminator().successors().iter() {
|
2016-06-07 09:28:36 -05:00
|
|
|
let kind = result[succ];
|
2016-05-29 14:01:06 -05:00
|
|
|
debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
|
|
|
|
funclet, succ, kind);
|
|
|
|
match kind {
|
|
|
|
CleanupKind::NotCleanup => {
|
2016-06-07 09:28:36 -05:00
|
|
|
result[succ] = CleanupKind::Internal { funclet: funclet };
|
2016-05-29 14:01:06 -05:00
|
|
|
}
|
|
|
|
CleanupKind::Funclet => {
|
2017-05-18 15:58:39 -05:00
|
|
|
if funclet != succ {
|
|
|
|
set_successor(funclet, succ);
|
|
|
|
}
|
2016-05-29 14:01:06 -05:00
|
|
|
}
|
|
|
|
CleanupKind::Internal { funclet: succ_funclet } => {
|
|
|
|
if funclet != succ_funclet {
|
|
|
|
// `succ` has 2 different funclet going into it, so it must
|
|
|
|
// be a funclet by itself.
|
|
|
|
|
|
|
|
debug!("promoting {:?} to a funclet and updating {:?}", succ,
|
|
|
|
succ_funclet);
|
2016-06-07 09:28:36 -05:00
|
|
|
result[succ] = CleanupKind::Funclet;
|
2016-05-29 14:01:06 -05:00
|
|
|
set_successor(succ_funclet, succ);
|
|
|
|
set_successor(funclet, succ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-07 13:20:50 -05:00
|
|
|
let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());
|
2016-05-29 14:01:06 -05:00
|
|
|
|
|
|
|
discover_masters(&mut result, mir);
|
|
|
|
propagate(&mut result, mir);
|
|
|
|
debug!("cleanup_kinds: result={:?}", result);
|
|
|
|
result
|
|
|
|
}
|