Skip to content

MIR: Add pass that erases all regions right before trans #29886

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

Merged
merged 1 commit into from
Nov 18, 2015
Merged
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
10 changes: 7 additions & 3 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand All @@ -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
Expand Down
234 changes: 234 additions & 0 deletions src/librustc_mir/transform/erase_regions.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
5 changes: 3 additions & 2 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>);
}
4 changes: 2 additions & 2 deletions src/librustc_mir/transform/simplify_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_trans/trans/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -63,6 +63,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
unimplemented!()
}
};

assert!(!ty.has_erasable_regions());

OperandRef {
ty: ty,
val: val
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/trans/mir/lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
}
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_trans/trans/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-make/execution-engine/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down