302 lines
10 KiB
Rust
Raw Normal View History

2015-08-18 17:59:21 -04: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.
use hair::cx::Cx;
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::middle::ty::{FnOutput, Ty};
use rustc::mir::repr::*;
2015-08-18 17:59:21 -04:00
use rustc_data_structures::fnv::FnvHashMap;
use rustc_front::hir;
use std::ops::{Index, IndexMut};
use syntax::ast;
use syntax::codemap::Span;
2015-11-21 17:39:15 +03:00
pub struct Builder<'a, 'tcx: 'a> {
hir: Cx<'a, 'tcx>,
cfg: CFG<'tcx>,
2016-03-09 11:04:26 -05:00
fn_span: Span,
2016-03-09 11:04:26 -05:00
// the current set of scopes, updated as we traverse;
// see the `scope` module for more details
scopes: Vec<scope::Scope<'tcx>>,
2016-03-09 11:04:26 -05:00
// for each scope, a span of blocks that defines it;
// we track these for use in region and borrow checking,
// but these are liable to get out of date once optimization
// begins. They are also hopefully temporary, and will be
// no longer needed when we adopt graph-based regions.
scope_auxiliary: ScopeAuxiliaryVec,
2016-03-09 11:04:26 -05:00
// the current set of loops; see the `scope` module for more
// details
loop_scopes: Vec<scope::LoopScope>,
2016-03-09 11:04:26 -05:00
// the vector of all scopes that we have created thus far;
// we track this for debuginfo later
scope_datas: Vec<ScopeData>,
2016-03-09 11:04:26 -05:00
var_decls: Vec<VarDecl<'tcx>>,
var_indices: FnvHashMap<ast::NodeId, u32>,
temp_decls: Vec<TempDecl<'tcx>>,
unit_temp: Option<Lvalue<'tcx>>,
2015-08-18 17:59:21 -04:00
}
struct CFG<'tcx> {
basic_blocks: Vec<BasicBlockData<'tcx>>,
2015-08-18 17:59:21 -04:00
}
2016-03-09 11:04:26 -05:00
/// For each scope, we track the extent (from the HIR) and a
/// single-entry-multiple-exit subgraph that contains all the
/// statements/terminators within it.
///
/// This information is separated out from the main `ScopeData`
/// because it is short-lived. First, the extent contains node-ids,
/// so it cannot be saved and re-loaded. Second, any optimization will mess up
/// the dominator/postdominator information.
///
/// The intention is basically to use this information to do
/// regionck/borrowck and then throw it away once we are done.
pub struct ScopeAuxiliary {
/// extent of this scope from the MIR.
pub extent: CodeExtent,
/// "entry point": dominator of all nodes in the scope
pub dom: Location,
/// "exit points": mutual postdominators of all nodes in the scope
pub postdoms: Vec<Location>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
2016-03-09 11:04:26 -05:00
pub struct Location {
/// the location is within this block
pub block: BasicBlock,
/// the location is the start of the this statement; or, if `statement_index`
/// == num-statements, then the start of the terminator.
pub statement_index: usize,
}
pub struct ScopeAuxiliaryVec {
pub vec: Vec<ScopeAuxiliary>
}
impl Index<ScopeId> for ScopeAuxiliaryVec {
type Output = ScopeAuxiliary;
#[inline]
fn index(&self, index: ScopeId) -> &ScopeAuxiliary {
&self.vec[index.index()]
}
}
impl IndexMut<ScopeId> for ScopeAuxiliaryVec {
#[inline]
fn index_mut(&mut self, index: ScopeId) -> &mut ScopeAuxiliary {
&mut self.vec[index.index()]
}
2016-03-09 11:04:26 -05:00
}
2015-08-18 17:59:21 -04:00
///////////////////////////////////////////////////////////////////////////
/// The `BlockAnd` "monad" packages up the new basic block along with a
/// produced value (sometimes just unit, of course). The `unpack!`
/// macro (and methods below) makes working with `BlockAnd` much more
/// convenient.
2015-08-18 17:59:21 -04:00
#[must_use] // if you don't use one of these results, you're leaving a dangling edge
2015-11-21 17:39:15 +03:00
pub struct BlockAnd<T>(BasicBlock, T);
2015-08-18 17:59:21 -04:00
trait BlockAndExtension {
fn and<T>(self, v: T) -> BlockAnd<T>;
fn unit(self) -> BlockAnd<()>;
}
impl BlockAndExtension for BasicBlock {
2015-08-18 17:59:21 -04:00
fn and<T>(self, v: T) -> BlockAnd<T> {
BlockAnd(self, v)
}
fn unit(self) -> BlockAnd<()> {
BlockAnd(self, ())
}
}
/// Update a block pointer and return the value.
/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
macro_rules! unpack {
($x:ident = $c:expr) => {
{
let BlockAnd(b, v) = $c;
$x = b;
v
}
};
($c:expr) => {
{
let BlockAnd(b, ()) = $c;
b
}
};
}
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
2015-08-18 17:59:21 -04:00
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
2016-02-07 21:13:00 +02:00
span: Span,
fn_id: ast::NodeId,
body_id: ast::NodeId,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
return_ty: FnOutput<'tcx>,
ast_block: &'tcx hir::Block)
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
let tcx = hir.tcx();
2015-08-18 17:59:21 -04:00
let cfg = CFG { basic_blocks: vec![] };
let mut builder = Builder {
hir: hir,
cfg: cfg,
fn_span: span,
2015-08-18 17:59:21 -04:00
scopes: vec![],
scope_datas: vec![],
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
2015-08-18 17:59:21 -04:00
loop_scopes: vec![],
temp_decls: vec![],
2015-08-18 17:59:21 -04:00
var_decls: vec![],
var_indices: FnvHashMap(),
2016-02-07 21:13:00 +02:00
unit_temp: None,
2015-08-18 17:59:21 -04:00
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
2016-03-18 08:52:13 -04:00
let mut arg_decls = None; // assigned to `Some` in closures below
let call_site_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| {
let mut block = START_BLOCK;
let arg_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
unpack!(block = builder.in_scope(arg_extent, block, |builder, arg_scope_id| {
arg_decls = Some(unpack!(block = builder.args_and_body(block,
implicit_arguments,
explicit_arguments,
arg_scope_id,
ast_block)));
block.unit()
}));
builder.cfg.terminate(block, call_site_scope_id, span,
TerminatorKind::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, call_site_scope_id, span,
TerminatorKind::Return);
END_BLOCK.unit()
});
2015-08-18 17:59:21 -04:00
assert!(
builder.cfg.basic_blocks
.iter()
.enumerate()
.all(|(index, block)| {
if block.terminator.is_none() {
panic!("no terminator on block {:?} in fn {:?}",
index, fn_id)
}
true
}));
(
Mir {
2016-03-09 11:04:26 -05:00
basic_blocks: builder.cfg.basic_blocks,
scopes: builder.scope_datas,
2016-03-09 11:04:26 -05:00
var_decls: builder.var_decls,
arg_decls: arg_decls.take().expect("args never built?"),
2016-03-09 11:04:26 -05:00
temp_decls: builder.temp_decls,
return_ty: return_ty,
span: span
},
builder.scope_auxiliary,
)
2015-08-18 17:59:21 -04:00
}
impl<'a,'tcx> Builder<'a,'tcx> {
2015-08-18 17:59:21 -04:00
fn args_and_body(&mut self,
mut block: BasicBlock,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_scope_id: ScopeId,
ast_block: &'tcx hir::Block)
-> BlockAnd<Vec<ArgDecl<'tcx>>>
2015-08-18 17:59:21 -04:00
{
// to start, translate the argument patterns and collect the argument types.
let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
2015-12-30 06:55:51 -06:00
let arg_decls =
implicits
.chain(explicits)
.enumerate()
.map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(index as u32);
if let Some(pattern) = pattern {
let pattern = self.hir.irrefutable_pat(pattern);
unpack!(block = self.lvalue_into_pattern(block,
argument_scope_id,
pattern,
&lvalue));
}
// Make sure we drop (parts of) the argument even when not matched on.
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty);
ArgDecl { ty: ty, spread: false }
})
.collect();
// start the first basic block and translate the body
unpack!(block = self.ast_block(&Lvalue::ReturnPointer, block, ast_block));
block.and(arg_decls)
2015-08-18 17:59:21 -04:00
}
fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
match self.unit_temp {
Some(ref tmp) => tmp.clone(),
None => {
let ty = self.hir.unit_ty();
let tmp = self.temp(ty);
self.unit_temp = Some(tmp.clone());
tmp
}
}
}
2015-08-18 17:59:21 -04:00
}
///////////////////////////////////////////////////////////////////////////
// Builder methods are broken up into modules, depending on what kind
// of thing is being translated. Note that they use the `unpack` macro
// above extensively.
mod block;
mod cfg;
mod expr;
mod into;
mod matches;
mod misc;
mod scope;