Auto merge of #29886 - michaelwoerister:mir-erase-regions, r=nikomatsakis
This change adds a `MirPass` erasing all early-bound regions from MIR, right before storing it in the MIR map. I've added some assertions at neuralgic points in `trans::mir` doing cheap checks whether region have actually been erased. Here are some assumptions that I worked under: - AdtDef references stay untouched. It's the `Substs` accompanying them that need to be handled (e.g. in `AggregateKind::Adt`). - We can't really get rid of late-bound regions at this point because there is no version `BareFnTy` (for example) that comes without one. These still have to be handled on demand in trans. Are this assumptions right? r? @nikomatsakis
This commit is contained in:
commit
3c68f646e9
@ -167,7 +167,7 @@ pub fn compile_input(sess: Session,
|
||||
tcx.print_debug_stats();
|
||||
}
|
||||
let trans = phase_4_translate_to_llvm(tcx,
|
||||
&mir_map,
|
||||
mir_map,
|
||||
analysis);
|
||||
|
||||
if log_enabled!(::log::INFO) {
|
||||
@ -849,7 +849,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
/// Run the translation phase to LLVM, after which the AST and analysis can
|
||||
/// be discarded.
|
||||
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
mir_map: &MirMap<'tcx>,
|
||||
mut mir_map: MirMap<'tcx>,
|
||||
analysis: ty::CrateAnalysis)
|
||||
-> trans::CrateTranslation {
|
||||
let time_passes = tcx.sess.time_passes();
|
||||
@ -858,10 +858,14 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
"resolving dependency formats",
|
||||
|| dependency_format::calculate(&tcx.sess));
|
||||
|
||||
time(time_passes,
|
||||
"erasing regions from MIR",
|
||||
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
|
||||
|
||||
// Option dance to work around the lack of stack once closures.
|
||||
time(time_passes,
|
||||
"translation",
|
||||
move || trans::trans_crate(tcx, mir_map, analysis))
|
||||
move || trans::trans_crate(tcx, &mir_map, analysis))
|
||||
}
|
||||
|
||||
/// Run LLVM itself, producing a bitcode file, assembly file or object file
|
||||
|
234
src/librustc_mir/transform/erase_regions.rs
Normal file
234
src/librustc_mir/transform/erase_regions.rs
Normal file
@ -0,0 +1,234 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//! This pass erases all early-bound regions from the types occuring in the MIR.
|
||||
//! We want to do this once just before trans, so trans does not have to take
|
||||
//! care erasing regions all over the place.
|
||||
|
||||
use repr::*;
|
||||
use rustc::middle::ty;
|
||||
use transform::MirPass;
|
||||
use mir_map::MirMap;
|
||||
|
||||
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
|
||||
let mut eraser = EraseRegions::new(tcx);
|
||||
|
||||
for mir in mir_map.iter_mut().map(|(_, v)| v) {
|
||||
eraser.run_on_mir(mir);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EraseRegions<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirPass<'tcx> for EraseRegions<'a, 'tcx> {
|
||||
|
||||
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
|
||||
|
||||
for basic_block in &mut mir.basic_blocks {
|
||||
self.erase_regions_basic_block(basic_block);
|
||||
}
|
||||
|
||||
self.erase_regions_return_ty(&mut mir.return_ty);
|
||||
|
||||
self.erase_regions_tys(mir.var_decls.iter_mut().map(|d| &mut d.ty));
|
||||
self.erase_regions_tys(mir.arg_decls.iter_mut().map(|d| &mut d.ty));
|
||||
self.erase_regions_tys(mir.temp_decls.iter_mut().map(|d| &mut d.ty));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
|
||||
|
||||
pub fn new(tcx: &'a ty::ctxt<'tcx>) -> EraseRegions<'a, 'tcx> {
|
||||
EraseRegions {
|
||||
tcx: tcx
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_basic_block(&mut self,
|
||||
basic_block: &mut BasicBlockData<'tcx>) {
|
||||
for statement in &mut basic_block.statements {
|
||||
self.erase_regions_statement(statement);
|
||||
}
|
||||
|
||||
self.erase_regions_terminator(&mut basic_block.terminator);
|
||||
}
|
||||
|
||||
fn erase_regions_statement(&mut self,
|
||||
statement: &mut Statement<'tcx>) {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(ref mut lvalue, ref mut rvalue) => {
|
||||
self.erase_regions_lvalue(lvalue);
|
||||
self.erase_regions_rvalue(rvalue);
|
||||
}
|
||||
StatementKind::Drop(_, ref mut lvalue) => {
|
||||
self.erase_regions_lvalue(lvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_terminator(&mut self,
|
||||
terminator: &mut Terminator<'tcx>) {
|
||||
match *terminator {
|
||||
Terminator::Goto { .. } |
|
||||
Terminator::Diverge |
|
||||
Terminator::Return |
|
||||
Terminator::Panic { .. } => {
|
||||
/* nothing to do */
|
||||
}
|
||||
Terminator::If { ref mut cond, .. } => {
|
||||
self.erase_regions_operand(cond);
|
||||
}
|
||||
Terminator::Switch { ref mut discr, .. } => {
|
||||
self.erase_regions_lvalue(discr);
|
||||
}
|
||||
Terminator::SwitchInt {
|
||||
ref mut discr,
|
||||
ref mut switch_ty,
|
||||
..
|
||||
} => {
|
||||
self.erase_regions_lvalue(discr);
|
||||
*switch_ty = self.tcx.erase_regions(switch_ty);
|
||||
},
|
||||
Terminator::Call {
|
||||
data: CallData {
|
||||
ref mut destination,
|
||||
ref mut func,
|
||||
ref mut args
|
||||
},
|
||||
..
|
||||
} => {
|
||||
self.erase_regions_lvalue(destination);
|
||||
self.erase_regions_operand(func);
|
||||
for arg in &mut *args {
|
||||
self.erase_regions_operand(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_operand(&mut self, operand: &mut Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Consume(ref mut lvalue) => {
|
||||
self.erase_regions_lvalue(lvalue);
|
||||
}
|
||||
Operand::Constant(ref mut constant) => {
|
||||
self.erase_regions_constant(constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>) {
|
||||
match *lvalue {
|
||||
Lvalue::Var(_) |
|
||||
Lvalue::Temp(_) |
|
||||
Lvalue::Arg(_) |
|
||||
Lvalue::Static(_) |
|
||||
Lvalue::ReturnPointer => {}
|
||||
Lvalue::Projection(ref mut lvalue_projection) => {
|
||||
self.erase_regions_lvalue(&mut lvalue_projection.base);
|
||||
match lvalue_projection.elem {
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Field(_) |
|
||||
ProjectionElem::Downcast(..) |
|
||||
ProjectionElem::ConstantIndex {..} => { /* nothing to do */ }
|
||||
ProjectionElem::Index(ref mut index) => {
|
||||
self.erase_regions_operand(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref mut operand) => {
|
||||
self.erase_regions_operand(operand)
|
||||
}
|
||||
Rvalue::Repeat(ref mut operand, ref mut constant) => {
|
||||
self.erase_regions_operand(operand);
|
||||
self.erase_regions_constant(constant);
|
||||
}
|
||||
Rvalue::Ref(ref mut region, _, ref mut lvalue) => {
|
||||
*region = ty::ReStatic;
|
||||
self.erase_regions_lvalue(lvalue);
|
||||
}
|
||||
Rvalue::Len(ref mut lvalue) => self.erase_regions_lvalue(lvalue),
|
||||
Rvalue::Cast(_, ref mut operand, ref mut ty) => {
|
||||
self.erase_regions_operand(operand);
|
||||
*ty = self.tcx.erase_regions(ty);
|
||||
}
|
||||
Rvalue::BinaryOp(_, ref mut operand1, ref mut operand2) => {
|
||||
self.erase_regions_operand(operand1);
|
||||
self.erase_regions_operand(operand2);
|
||||
}
|
||||
Rvalue::UnaryOp(_, ref mut operand) => {
|
||||
self.erase_regions_operand(operand);
|
||||
}
|
||||
Rvalue::Box(ref mut ty) => *ty = self.tcx.erase_regions(ty),
|
||||
Rvalue::Aggregate(ref mut aggregate_kind, ref mut operands) => {
|
||||
match *aggregate_kind {
|
||||
AggregateKind::Vec |
|
||||
AggregateKind::Tuple => {},
|
||||
AggregateKind::Adt(_, _, ref mut substs) => {
|
||||
let erased = self.tcx.erase_regions(*substs);
|
||||
*substs = self.tcx.mk_substs(erased);
|
||||
}
|
||||
AggregateKind::Closure(def_id, ref mut closure_substs) => {
|
||||
let cloned = Box::new(closure_substs.clone());
|
||||
let ty = self.tcx.mk_closure_from_closure_substs(def_id,
|
||||
cloned);
|
||||
let erased = self.tcx.erase_regions(&ty);
|
||||
*closure_substs = match erased.sty {
|
||||
ty::TyClosure(_, ref closure_substs) => &*closure_substs,
|
||||
_ => unreachable!()
|
||||
};
|
||||
}
|
||||
}
|
||||
for operand in &mut *operands {
|
||||
self.erase_regions_operand(operand);
|
||||
}
|
||||
}
|
||||
Rvalue::Slice { ref mut input, .. } => {
|
||||
self.erase_regions_lvalue(input);
|
||||
}
|
||||
Rvalue::InlineAsm(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_constant(&mut self, constant: &mut Constant<'tcx>) {
|
||||
constant.ty = self.tcx.erase_regions(&constant.ty);
|
||||
match constant.literal {
|
||||
Literal::Item { ref mut substs, .. } => {
|
||||
*substs = self.tcx.mk_substs(self.tcx.erase_regions(substs));
|
||||
}
|
||||
Literal::Value { .. } => { /* nothing to do */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_return_ty(&mut self, fn_output: &mut ty::FnOutput<'tcx>) {
|
||||
match *fn_output {
|
||||
ty::FnConverging(ref mut ty) => {
|
||||
*ty = self.tcx.erase_regions(ty);
|
||||
},
|
||||
ty::FnDiverging => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn erase_regions_tys<'b, T>(&mut self, tys: T)
|
||||
where T: Iterator<Item = &'b mut ty::Ty<'tcx>>,
|
||||
'tcx: 'b
|
||||
{
|
||||
for ty in tys {
|
||||
*ty = self.tcx.erase_regions(ty);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,10 +9,11 @@
|
||||
// except according to those terms.
|
||||
|
||||
pub mod simplify_cfg;
|
||||
pub mod erase_regions;
|
||||
mod util;
|
||||
|
||||
use repr::Mir;
|
||||
|
||||
pub trait MirPass {
|
||||
fn run_on_mir(&mut self, mir: &mut Mir);
|
||||
pub trait MirPass<'tcx> {
|
||||
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>);
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ impl SimplifyCfg {
|
||||
}
|
||||
}
|
||||
|
||||
impl MirPass for SimplifyCfg {
|
||||
fn run_on_mir(&mut self, mir: &mut Mir) {
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
|
||||
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
changed = self.simplify_branches(mir);
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::ty::Ty;
|
||||
use middle::ty::{Ty, HasTypeFlags};
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::consts::{self, TrueConst};
|
||||
@ -63,6 +63,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
|
||||
assert!(!ty.has_erasable_regions());
|
||||
|
||||
OperandRef {
|
||||
ty: ty,
|
||||
val: val
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use llvm::ValueRef;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc::middle::ty::{self, Ty, HasTypeFlags};
|
||||
use rustc_mir::repr as mir;
|
||||
use rustc_mir::tcx::LvalueTy;
|
||||
use trans::adt;
|
||||
@ -45,6 +45,7 @@ impl<'tcx> LvalueRef<'tcx> {
|
||||
name: &str)
|
||||
-> LvalueRef<'tcx>
|
||||
{
|
||||
assert!(!ty.has_erasable_regions());
|
||||
let lltemp = base::alloc_ty(bcx, ty, name);
|
||||
LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use llvm::ValueRef;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc::middle::ty::{Ty, HasTypeFlags};
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::base;
|
||||
use trans::common::{self, Block};
|
||||
@ -122,6 +122,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
}
|
||||
datum::ByRef => OperandValue::Ref(tr_lvalue.llval)
|
||||
};
|
||||
|
||||
assert!(!ty.has_erasable_regions());
|
||||
|
||||
OperandRef {
|
||||
val: val,
|
||||
ty: ty
|
||||
|
@ -231,7 +231,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
|
||||
driver::phase_3_run_analysis_passes(
|
||||
&sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| {
|
||||
|
||||
let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis);
|
||||
let trans = driver::phase_4_translate_to_llvm(tcx, mir_map, analysis);
|
||||
|
||||
let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user