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.
|
|
|
|
|
2015-11-09 20:54:17 -05:00
|
|
|
use hair::cx::Cx;
|
2016-03-23 12:26:37 -04:00
|
|
|
use rustc::middle::region::{CodeExtent, CodeExtentData};
|
2015-10-21 17:14:25 -04:00
|
|
|
use rustc::middle::ty::{FnOutput, Ty};
|
2015-11-19 16:37:34 +01:00
|
|
|
use rustc::mir::repr::*;
|
2015-08-18 17:59:21 -04:00
|
|
|
use rustc_data_structures::fnv::FnvHashMap;
|
2015-10-05 12:31:48 -04:00
|
|
|
use rustc_front::hir;
|
2016-03-23 05:01:30 -04:00
|
|
|
use std::ops::{Index, IndexMut};
|
2015-10-05 12:31:48 -04:00
|
|
|
use syntax::ast;
|
|
|
|
use syntax::codemap::Span;
|
|
|
|
|
2015-11-21 17:39:15 +03:00
|
|
|
pub struct Builder<'a, 'tcx: 'a> {
|
2015-10-05 12:31:48 -04:00
|
|
|
hir: Cx<'a, 'tcx>,
|
|
|
|
cfg: CFG<'tcx>,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2016-03-22 20:41:07 -04: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
|
2015-10-05 12:31:48 -04:00
|
|
|
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.
|
2016-03-23 05:01:30 -04:00
|
|
|
scope_auxiliary: ScopeAuxiliaryVec,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
|
|
|
// the current set of loops; see the `scope` module for more
|
|
|
|
// details
|
2015-10-05 12:31:48 -04:00
|
|
|
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
|
2016-03-23 04:59:44 -04:00
|
|
|
scope_datas: Vec<ScopeData>,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2015-10-05 12:31:48 -04:00
|
|
|
var_decls: Vec<VarDecl<'tcx>>,
|
|
|
|
var_indices: FnvHashMap<ast::NodeId, u32>,
|
|
|
|
temp_decls: Vec<TempDecl<'tcx>>,
|
2016-01-16 00:36:32 +02:00
|
|
|
unit_temp: Option<Lvalue<'tcx>>,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 12:31:48 -04:00
|
|
|
struct CFG<'tcx> {
|
2015-10-07 14:37:42 +02:00
|
|
|
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>,
|
|
|
|
}
|
|
|
|
|
2016-03-22 10:08:44 -04:00
|
|
|
#[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,
|
|
|
|
}
|
|
|
|
|
2016-03-23 05:01:30 -04:00
|
|
|
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
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 13:25:07 +01: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
|
|
|
|
2015-11-19 16:37:34 +01: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
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 13:25:07 +01:00
|
|
|
/// the main entry point for building MIR for a function
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2015-12-30 13:44:13 +02:00
|
|
|
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
2016-02-07 21:13:00 +02:00
|
|
|
span: Span,
|
2016-03-23 12:26:37 -04:00
|
|
|
fn_id: ast::NodeId,
|
|
|
|
body_id: ast::NodeId,
|
2015-10-21 17:14:25 -04:00
|
|
|
implicit_arguments: Vec<Ty<'tcx>>,
|
2015-11-09 20:54:17 -05:00
|
|
|
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
2015-10-21 17:14:25 -04:00
|
|
|
return_ty: FnOutput<'tcx>,
|
|
|
|
ast_block: &'tcx hir::Block)
|
2016-03-23 05:01:30 -04:00
|
|
|
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
2016-03-23 12:26:37 -04:00
|
|
|
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,
|
2016-03-22 20:41:07 -04:00
|
|
|
fn_span: span,
|
2015-08-18 17:59:21 -04:00
|
|
|
scopes: vec![],
|
2016-03-23 04:59:44 -04:00
|
|
|
scope_datas: vec![],
|
2016-03-23 05:01:30 -04:00
|
|
|
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
|
2015-08-18 17:59:21 -04:00
|
|
|
loop_scopes: vec![],
|
2015-12-30 13:44:13 +02:00
|
|
|
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
|
|
|
|
2016-03-23 12:26:37 -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
|
|
|
|
2016-03-22 16:05:28 -04:00
|
|
|
assert!(
|
|
|
|
builder.cfg.basic_blocks
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.all(|(index, block)| {
|
|
|
|
if block.terminator.is_none() {
|
2016-03-23 12:26:37 -04:00
|
|
|
panic!("no terminator on block {:?} in fn {:?}",
|
|
|
|
index, fn_id)
|
2016-03-22 16:05:28 -04:00
|
|
|
}
|
|
|
|
true
|
|
|
|
}));
|
|
|
|
|
2016-03-23 05:01:30 -04:00
|
|
|
(
|
|
|
|
Mir {
|
2016-03-09 11:04:26 -05:00
|
|
|
basic_blocks: builder.cfg.basic_blocks,
|
2016-03-23 04:59:44 -04:00
|
|
|
scopes: builder.scope_datas,
|
2016-03-09 11:04:26 -05:00
|
|
|
var_decls: builder.var_decls,
|
2016-03-23 12:26:37 -04:00
|
|
|
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
|
|
|
|
},
|
2016-03-23 05:01:30 -04:00
|
|
|
builder.scope_auxiliary,
|
|
|
|
)
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 12:31:48 -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,
|
2015-10-05 12:31:48 -04:00
|
|
|
implicit_arguments: Vec<Ty<'tcx>>,
|
2015-11-09 20:54:17 -05:00
|
|
|
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
2016-03-23 12:26:37 -04:00
|
|
|
argument_scope_id: ScopeId,
|
2015-10-05 12:31:48 -04:00
|
|
|
ast_block: &'tcx hir::Block)
|
2016-03-23 12:26:37 -04:00
|
|
|
-> BlockAnd<Vec<ArgDecl<'tcx>>>
|
2015-08-18 17:59:21 -04:00
|
|
|
{
|
2016-03-23 12:26:37 -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 =
|
2016-03-23 12:26:37 -04:00
|
|
|
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
|
|
|
}
|
2016-01-16 00:36:32 +02: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;
|