Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
translate tuple-variant constructors using MIR
  • Loading branch information
arielb1 committed Mar 18, 2017
1 parent a559452 commit 0af3775
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 138 deletions.
13 changes: 10 additions & 3 deletions src/librustc/ty/mod.rs
Expand Up @@ -1264,10 +1264,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
def_id,
ROOT_CODE_EXTENT)
}
_ => {
Some(hir_map::NodeStructCtor(..)) |
Some(hir_map::NodeVariant(..)) => {
let def_id = tcx.hir.local_def_id(id);
tcx.construct_parameter_environment(tcx.hir.span(id),
def_id,
ROOT_CODE_EXTENT)
}
it => {
bug!("ParameterEnvironment::from_item(): \
`{}` is not an item",
tcx.hir.node_to_string(id))
`{}` = {:?} is unsupported",
tcx.hir.node_to_string(id), it)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_metadata/encoder.rs
Expand Up @@ -293,7 +293,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
predicates: Some(self.encode_predicates(def_id)),

ast: None,
mir: None,
mir: self.encode_mir(def_id),
}
}

Expand Down Expand Up @@ -426,7 +426,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
predicates: Some(self.encode_predicates(def_id)),

ast: None,
mir: None,
mir: self.encode_mir(def_id),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/lib.rs
Expand Up @@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!

#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(i128_type)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
Expand Down Expand Up @@ -50,6 +51,7 @@ pub mod callgraph;
pub mod def_use;
pub mod graphviz;
mod hair;
mod shim;
pub mod mir_map;
pub mod pretty;
pub mod transform;
Expand Down
63 changes: 63 additions & 0 deletions src/librustc_mir/mir_map.rs
Expand Up @@ -22,6 +22,7 @@ use rustc::dep_graph::DepNode;
use rustc::mir::Mir;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor;
use shim;
use pretty;
use hair::cx::Cx;

Expand All @@ -30,6 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::subst::Substs;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use syntax::abi::Abi;
use syntax::ast;
use syntax_pos::Span;
Expand All @@ -44,6 +46,31 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
tcx.item_mir(body_owner_def_id);
});

// Tuple struct/variant constructors don't have a BodyId, so we need
// to build them separately.
struct GatherCtors<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>
}
impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
fn visit_variant_data(&mut self,
v: &'tcx hir::VariantData,
_: ast::Name,
_: &'tcx hir::Generics,
_: ast::NodeId,
_: Span) {
if let hir::VariantData::Tuple(_, node_id) = *v {
self.tcx.item_mir(self.tcx.hir.local_def_id(node_id));
}
intravisit::walk_struct_def(self, v)
}
fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
NestedVisitorMap::None
}
}
tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut GatherCtors {
tcx: tcx
}.as_deep_visitor());
}
}

Expand Down Expand Up @@ -95,6 +122,10 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
_ => hir::BodyId { node_id: expr.id }
}
}
hir::map::NodeVariant(variant) =>
return create_constructor_shim(tcx, id, &variant.node.data),
hir::map::NodeStructCtor(ctor) =>
return create_constructor_shim(tcx, id, ctor),
_ => unsupported()
};

Expand Down Expand Up @@ -180,6 +211,38 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
}
}

fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor_id: ast::NodeId,
v: &'tcx hir::VariantData)
-> &'tcx RefCell<Mir<'tcx>>
{
let span = tcx.hir.span(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
let (mut mir, src) =
shim::build_adt_ctor(&infcx, ctor_id, fields, span);

// Convert the Mir to global types.
let tcx = infcx.tcx.global_tcx();
let mut globalizer = GlobalizeMir {
tcx: tcx,
span: mir.span
};
globalizer.visit_mir(&mut mir);
let mir = unsafe {
mem::transmute::<Mir, Mir<'tcx>>(mir)
};

pretty::dump_mir(tcx, "mir_map", &0, src, &mir);

tcx.alloc_mir(mir)
})
} else {
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
}
}

///////////////////////////////////////////////////////////////////////////
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from

Expand Down
109 changes: 109 additions & 0 deletions src/librustc_mir/shim.rs
@@ -0,0 +1,109 @@
// Copyright 2016 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 rustc::hir;
use rustc::infer;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::ty;

use rustc_data_structures::indexed_vec::{IndexVec, Idx};

use syntax::ast;
use syntax_pos::Span;

use std::iter;

fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
-> IndexVec<Local, LocalDecl<'tcx>>
{
iter::once(LocalDecl {
mutability: Mutability::Mut,
ty: sig.output(),
name: None,
source_info: None
}).chain(sig.inputs().iter().map(|ity| LocalDecl {
mutability: Mutability::Not,
ty: *ity,
name: None,
source_info: None,
})).collect()
}

pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
ctor_id: ast::NodeId,
fields: &[hir::StructField],
span: Span)
-> (Mir<'tcx>, MirSource)
{
let tcx = infcx.tcx;
let def_id = tcx.hir.local_def_id(ctor_id);
let sig = match tcx.item_type(def_id).sty {
ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty)
.expect("LBR in ADT constructor signature"),
_ => bug!("unexpected type for ctor {:?}", def_id)
};
let sig = tcx.erase_regions(&sig);

let (adt_def, substs) = match sig.output().sty {
ty::TyAdt(adt_def, substs) => (adt_def, substs),
_ => bug!("unexpected type for ADT ctor {:?}", sig.output())
};

debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);

let local_decls = local_decls_for_sig(&sig);

let source_info = SourceInfo {
span: span,
scope: ARGUMENT_VISIBILITY_SCOPE
};

let variant_no = if adt_def.is_enum() {
adt_def.variant_index_with_id(def_id)
} else {
0
};

// return = ADT(arg0, arg1, ...); return
let start_block = BasicBlockData {
statements: vec![Statement {
source_info: source_info,
kind: StatementKind::Assign(
Lvalue::Local(RETURN_POINTER),
Rvalue::Aggregate(
AggregateKind::Adt(adt_def, variant_no, substs, None),
(1..sig.inputs().len()+1).map(|i| {
Operand::Consume(Lvalue::Local(Local::new(i)))
}).collect()
)
)
}],
terminator: Some(Terminator {
source_info: source_info,
kind: TerminatorKind::Return,
}),
is_cleanup: false
};

let mir = Mir::new(
IndexVec::from_elem_n(start_block, 1),
IndexVec::from_elem_n(
VisibilityScopeData { span: span, parent_scope: None }, 1
),
IndexVec::new(),
sig.output(),
local_decls,
sig.inputs().len(),
vec![],
span
);
(mir, MirSource::Fn(ctor_id))
}
78 changes: 4 additions & 74 deletions src/librustc_trans/base.rs
Expand Up @@ -34,10 +34,8 @@ use back::linker::LinkerInfo;
use back::symbol_export::{self, ExportedSymbols};
use llvm::{Linkage, ValueRef, Vector, get_param};
use llvm;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::def_id::LOCAL_CRATE;
use middle::lang_items::StartFnLangItem;
use rustc::ty::subst::Substs;
use rustc::mir::tcx::LvalueTy;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
Expand All @@ -47,9 +45,8 @@ use rustc::util::common::time;
use session::config::{self, NoDebugInfo};
use rustc_incremental::IncrementalHashesMap;
use session::{self, DataTypeKind, Session};
use abi::{self, FnType};
use abi;
use mir::lvalue::LvalueRef;
use adt;
use attributes;
use builder::Builder;
use callee::{Callee};
Expand All @@ -65,7 +62,7 @@ use context::{SharedCrateContext, CrateContextList};
use debuginfo;
use declare;
use machine;
use machine::{llalign_of_min, llsize_of};
use machine::llsize_of;
use meth;
use mir;
use monomorphize::{self, Instance};
Expand All @@ -76,7 +73,6 @@ use trans_item::{TransItem, DefPathBasedNames};
use type_::Type;
use type_of;
use value::Value;
use Disr;
use util::nodemap::{NodeSet, FxHashMap, FxHashSet};

use libc::c_uint;
Expand Down Expand Up @@ -615,72 +611,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
mir::trans_mir(ccx, lldecl, &mir, instance, sig);
}

pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
disr: Disr,
llfn: ValueRef) {
attributes::inline(llfn, attributes::InlineAttr::Hint);
attributes::set_frame_pointer_elimination(ccx, llfn);

let ctor_ty = common::def_ty(ccx.shared(), def_id, substs);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
let fn_ty = FnType::new(ccx, sig, &[]);

let bcx = Builder::new_block(ccx, llfn, "entry-block");
if !fn_ty.ret.is_ignore() {
// But if there are no nested returns, we skip the indirection
// and have a single retslot
let dest = if fn_ty.ret.is_indirect() {
get_param(llfn, 0)
} else {
// We create an alloca to hold a pointer of type `ret.original_ty`
// which will hold the pointer to the right alloca which has the
// final ret value
bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
};
// Can return unsized value
let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output(), Alignment::AbiAligned);
dest_val.ty = LvalueTy::Downcast {
adt_def: sig.output().ty_adt_def().unwrap(),
substs: substs,
variant_index: disr.0 as usize,
};
let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
let mut arg_idx = 0;
for (i, arg_ty) in sig.inputs().iter().enumerate() {
let (lldestptr, _) = dest_val.trans_field_ptr(&bcx, i);
let arg = &fn_ty.args[arg_idx];
arg_idx += 1;
if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
let meta = &fn_ty.args[arg_idx];
arg_idx += 1;
arg.store_fn_arg(&bcx, &mut llarg_idx, get_dataptr(&bcx, lldestptr));
meta.store_fn_arg(&bcx, &mut llarg_idx, get_meta(&bcx, lldestptr));
} else {
arg.store_fn_arg(&bcx, &mut llarg_idx, lldestptr);
}
}
adt::trans_set_discr(&bcx, sig.output(), dest, disr);

if fn_ty.ret.is_indirect() {
bcx.ret_void();
return;
}

if let Some(cast_ty) = fn_ty.ret.cast {
bcx.ret(bcx.load(
bcx.pointercast(dest, cast_ty.ptr_to()),
Some(llalign_of_min(ccx, fn_ty.ret.ty))
));
} else {
bcx.ret(bcx.load(dest, None))
}
} else {
bcx.ret_void();
}
}

pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
// applicable to variable declarations and may not really make sense for
Expand Down Expand Up @@ -721,7 +651,7 @@ pub fn set_link_section(ccx: &CrateContext,
}

/// Create the `main` function which will initialise the rust runtime and call
/// users main function.
/// users main function.
pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
let (main_def_id, span) = match *ccx.sess().entry_fn.borrow() {
Some((id, span)) => {
Expand Down

0 comments on commit 0af3775

Please sign in to comment.