Auto merge of #29217 - nikomatsakis:mir-trans, r=dotdash
This branch implements a variant of trans that is based on MIR. It is very incomplete (intentionally), and had only the goal of laying out enough work to enable more incremental follow-on patches. Currently, only fns tagged with `#[rustc_mir]` use the new trans code. I plan to build up a meta-issue as well that tracks the various "not-yet-implemented" points. The only fn that has been tested so far is this amazingly complex "spike" fn: ```rust #[rustc_mir] fn sum(x: i32, y: i32) -> i32 { x + y } ``` In general, the most interesting commit is the last one. There are some points on which I would like feedback from @rust-lang/compiler: - I did not use `Datum`. Originally, I thought that maybe just a `ValueRef` would be enough but I wound up with two very simple structures, `LvalueRef` and `OperandRef`, that just package up a `ValueRef` and a type. Because of MIR's structure, you don't wind up mixing by-ref and by-value so much, and I tend to think that a thinner abstraction layer is better here, but I'm not sure. - Related to the above, I expect that sooner or later we will analyze temps (and maybe variables too) to find those whose address is never taken and which are word-sized and which perhaps meet a few other criteria. For those, we'll probably want to avoid the alloca, just because it means prettier code. - I generally tried to re-use data structures from elsewhere in trans, though I'm sure we can trim these down. - I didn't do any debuginfo primarily because it seems to want node-ids and we have only spans. I haven't really read into that code so I don't know what's going on there. r? @nrc
This commit is contained in:
commit
a216e84727
@ -103,7 +103,7 @@ DEPS_rustc_mir := rustc rustc_front syntax
|
||||
DEPS_rustc_resolve := rustc rustc_front log syntax
|
||||
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
|
||||
DEPS_rustc_privacy := rustc rustc_front log syntax
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
|
||||
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
|
||||
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
|
||||
|
||||
|
@ -121,6 +121,13 @@ pub struct Tables<'tcx> {
|
||||
/// Records the type of each closure. The def ID is the ID of the
|
||||
/// expression defining the closure.
|
||||
pub closure_kinds: DefIdMap<ty::ClosureKind>,
|
||||
|
||||
/// For each fn, records the "liberated" types of its arguments
|
||||
/// and return type. Liberated means that all bound regions
|
||||
/// (including late-bound regions) are replaced with free
|
||||
/// equivalents. This table is not used in trans (since regions
|
||||
/// are erased there) and hence is not serialized to metadata.
|
||||
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
@ -133,6 +140,7 @@ impl<'tcx> Tables<'tcx> {
|
||||
upvar_capture_map: FnvHashMap(),
|
||||
closure_tys: DefIdMap(),
|
||||
closure_kinds: DefIdMap(),
|
||||
liberated_fn_sigs: NodeMap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1731,6 +1731,13 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
|
||||
self.fields.iter().find(|f| f.name == name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_of_field_named(&self,
|
||||
name: ast::Name)
|
||||
-> Option<usize> {
|
||||
self.fields.iter().position(|f| f.name == name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> {
|
||||
self.find_field_named(name).unwrap()
|
||||
|
@ -11,6 +11,7 @@
|
||||
use rustc::front;
|
||||
use rustc::front::map as hir_map;
|
||||
use rustc_mir as mir;
|
||||
use rustc_mir::mir_map::MirMap;
|
||||
use rustc::session::Session;
|
||||
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
|
||||
use rustc::session::search_paths::PathKind;
|
||||
@ -22,6 +23,7 @@ use rustc::middle::dependency_format;
|
||||
use rustc::middle;
|
||||
use rustc::plugin::registry::Registry;
|
||||
use rustc::plugin;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc::util::common::time;
|
||||
use rustc_borrowck as borrowck;
|
||||
use rustc_resolve as resolve;
|
||||
@ -146,7 +148,7 @@ pub fn compile_input(sess: Session,
|
||||
&arenas,
|
||||
&id,
|
||||
control.make_glob_map,
|
||||
|tcx, analysis| {
|
||||
|tcx, mir_map, analysis| {
|
||||
|
||||
{
|
||||
let state = CompileState::state_after_analysis(input,
|
||||
@ -170,7 +172,7 @@ pub fn compile_input(sess: Session,
|
||||
println!("Pre-trans");
|
||||
tcx.print_debug_stats();
|
||||
}
|
||||
let trans = phase_4_translate_to_llvm(tcx, analysis);
|
||||
let trans = phase_4_translate_to_llvm(tcx, &mir_map, analysis);
|
||||
|
||||
if log_enabled!(::log::INFO) {
|
||||
println!("Post-trans");
|
||||
@ -670,6 +672,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
f: F)
|
||||
-> R
|
||||
where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>,
|
||||
MirMap<'tcx>,
|
||||
ty::CrateAnalysis) -> R
|
||||
{
|
||||
let time_passes = sess.time_passes();
|
||||
@ -751,18 +754,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
time(time_passes, "match checking", ||
|
||||
middle::check_match::check_crate(tcx));
|
||||
|
||||
match tcx.sess.opts.unstable_features {
|
||||
let mir_map = match tcx.sess.opts.unstable_features {
|
||||
UnstableFeatures::Disallow => {
|
||||
// use this as a shorthand for beta/stable, and skip
|
||||
// MIR construction there until known regressions are
|
||||
// addressed
|
||||
NodeMap()
|
||||
}
|
||||
UnstableFeatures::Allow | UnstableFeatures::Cheat => {
|
||||
let _mir_map =
|
||||
time(time_passes, "MIR dump", ||
|
||||
mir::mir_map::build_mir_for_crate(tcx));
|
||||
time(time_passes, "MIR dump", ||
|
||||
mir::mir_map::build_mir_for_crate(tcx))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
time(time_passes, "liveness checking", ||
|
||||
middle::liveness::check_crate(tcx));
|
||||
@ -804,7 +807,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
// The above three passes generate errors w/o aborting
|
||||
tcx.sess.abort_if_errors();
|
||||
|
||||
f(tcx, ty::CrateAnalysis {
|
||||
f(tcx, mir_map, ty::CrateAnalysis {
|
||||
export_map: export_map,
|
||||
exported_items: exported_items,
|
||||
public_items: public_items,
|
||||
@ -817,8 +820,10 @@ 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: &ty::ctxt, analysis: ty::CrateAnalysis)
|
||||
-> trans::CrateTranslation {
|
||||
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
mir_map: &MirMap<'tcx>,
|
||||
analysis: ty::CrateAnalysis)
|
||||
-> trans::CrateTranslation {
|
||||
let time_passes = tcx.sess.time_passes();
|
||||
|
||||
time(time_passes, "resolving dependency formats", ||
|
||||
@ -826,7 +831,7 @@ pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis)
|
||||
|
||||
// Option dance to work around the lack of stack once closures.
|
||||
time(time_passes, "translation", move ||
|
||||
trans::trans_crate(tcx, analysis))
|
||||
trans::trans_crate(tcx, mir_map, analysis))
|
||||
}
|
||||
|
||||
/// Run LLVM itself, producing a bitcode file, assembly file or object file
|
||||
|
@ -182,7 +182,7 @@ impl PpSourceMode {
|
||||
arenas,
|
||||
id,
|
||||
resolve::MakeGlobMap::No,
|
||||
|tcx, _| {
|
||||
|tcx, _, _| {
|
||||
let annotation = TypedAnnotation { tcx: tcx };
|
||||
f(&annotation, payload, &ast_map.forest.krate)
|
||||
})
|
||||
@ -782,7 +782,7 @@ pub fn pretty_print_input(sess: Session,
|
||||
&arenas,
|
||||
&id,
|
||||
resolve::MakeGlobMap::No,
|
||||
|tcx, _| {
|
||||
|tcx, _, _| {
|
||||
print_flowgraph(variants, tcx, code, mode, out)
|
||||
})
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
|
||||
// schedule a shallow free of that memory, lest we unwind:
|
||||
let extent = this.extent_of_innermost_scope().unwrap();
|
||||
this.schedule_drop(expr_span, extent, DropKind::Shallow, &result, value_ty);
|
||||
this.schedule_drop(expr_span, extent, DropKind::Free, &result, value_ty);
|
||||
|
||||
// initialize the box contents:
|
||||
let contents = result.clone().deref();
|
||||
@ -149,16 +149,19 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
|
||||
}
|
||||
ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above
|
||||
// first process the set of fields
|
||||
// first process the set of fields that were provided
|
||||
// (evaluating them in order given by user)
|
||||
let fields_map: FnvHashMap<_, _> =
|
||||
fields.into_iter()
|
||||
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
|
||||
.collect();
|
||||
|
||||
let field_names = this.hir.fields(adt_def, variant_index);
|
||||
|
||||
// if base expression is given, evaluate it now
|
||||
let base = base.map(|base| unpack!(block = this.as_lvalue(block, base)));
|
||||
|
||||
// get list of all fields that we will need
|
||||
let field_names = this.hir.all_fields(adt_def, variant_index);
|
||||
|
||||
// for the actual values we use, take either the
|
||||
// expr the user specified or, if they didn't
|
||||
// specify something for this field name, create a
|
||||
|
@ -211,10 +211,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
this.cfg.start_new_block().unit()
|
||||
}
|
||||
ExprKind::Call { fun, args } => {
|
||||
let fun = unpack!(block = this.as_lvalue(block, fun));
|
||||
let fun = unpack!(block = this.as_operand(block, fun));
|
||||
let args: Vec<_> =
|
||||
args.into_iter()
|
||||
.map(|arg| unpack!(block = this.as_lvalue(block, arg)))
|
||||
.map(|arg| unpack!(block = this.as_operand(block, arg)))
|
||||
.collect();
|
||||
let success = this.cfg.start_new_block();
|
||||
let panic = this.diverge_cleanup();
|
||||
|
@ -92,6 +92,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
.collect();
|
||||
self.cfg.terminate(block, Terminator::Switch {
|
||||
discr: lvalue.clone(),
|
||||
adt_def: adt_def,
|
||||
targets: target_blocks.clone()
|
||||
});
|
||||
target_blocks
|
||||
@ -99,27 +100,28 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
// call PartialEq::eq(discrim, constant)
|
||||
let constant = self.push_literal(block, test.span, ty.clone(), value);
|
||||
let constant = self.literal_operand(test.span, ty.clone(), value);
|
||||
let item_ref = self.hir.partial_eq(ty);
|
||||
self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant)
|
||||
self.call_comparison_fn(block, test.span, item_ref,
|
||||
Operand::Consume(lvalue.clone()), constant)
|
||||
}
|
||||
|
||||
TestKind::Range { lo, hi, ty } => {
|
||||
// Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`.
|
||||
let lo = self.push_literal(block, test.span, ty.clone(), lo);
|
||||
let hi = self.push_literal(block, test.span, ty.clone(), hi);
|
||||
let lo = self.literal_operand(test.span, ty.clone(), lo);
|
||||
let hi = self.literal_operand(test.span, ty.clone(), hi);
|
||||
let item_ref = self.hir.partial_le(ty);
|
||||
|
||||
let lo_blocks = self.call_comparison_fn(block,
|
||||
test.span,
|
||||
item_ref.clone(),
|
||||
lo,
|
||||
lvalue.clone());
|
||||
Operand::Consume(lvalue.clone()));
|
||||
|
||||
let hi_blocks = self.call_comparison_fn(lo_blocks[0],
|
||||
test.span,
|
||||
item_ref,
|
||||
lvalue.clone(),
|
||||
Operand::Consume(lvalue.clone()),
|
||||
hi);
|
||||
|
||||
let failure = self.cfg.start_new_block();
|
||||
@ -164,14 +166,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>,
|
||||
lvalue1: Lvalue<'tcx>,
|
||||
lvalue2: Lvalue<'tcx>)
|
||||
lvalue1: Operand<'tcx>,
|
||||
lvalue2: Operand<'tcx>)
|
||||
-> Vec<BasicBlock> {
|
||||
let target_blocks = vec![self.cfg.start_new_block(), self.cfg.start_new_block()];
|
||||
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
let eq_result = self.temp(bool_ty);
|
||||
let func = self.push_item_ref(block, span, item_ref);
|
||||
let func = self.item_ref_operand(span, item_ref);
|
||||
let call_blocks = [self.cfg.start_new_block(), self.diverge_cleanup()];
|
||||
self.cfg.terminate(block,
|
||||
Terminator::Call {
|
||||
|
@ -34,20 +34,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
lvalue
|
||||
}
|
||||
|
||||
pub fn push_literal(&mut self,
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
literal: Literal<'tcx>)
|
||||
-> Lvalue<'tcx> {
|
||||
let temp = self.temp(ty.clone());
|
||||
pub fn literal_operand(&mut self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
literal: Literal<'tcx>)
|
||||
-> Operand<'tcx> {
|
||||
let constant = Constant {
|
||||
span: span,
|
||||
ty: ty,
|
||||
literal: literal,
|
||||
};
|
||||
self.cfg.push_assign_constant(block, span, &temp, constant);
|
||||
temp
|
||||
Operand::Constant(constant)
|
||||
}
|
||||
|
||||
pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
|
||||
@ -63,15 +60,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
temp
|
||||
}
|
||||
|
||||
pub fn push_item_ref(&mut self,
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>)
|
||||
-> Lvalue<'tcx> {
|
||||
pub fn item_ref_operand(&mut self,
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>)
|
||||
-> Operand<'tcx> {
|
||||
let literal = Literal::Item {
|
||||
def_id: item_ref.def_id,
|
||||
substs: item_ref.substs,
|
||||
};
|
||||
self.push_literal(block, span, item_ref.ty, literal)
|
||||
self.literal_operand(span, item_ref.ty, literal)
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,14 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hair;
|
||||
use hair::cx::{Cx, PatNode};
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc::middle::ty::{FnOutput, Ty};
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc_front::hir;
|
||||
use repr::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use tcx::{Cx, PatNode};
|
||||
|
||||
struct Builder<'a, 'tcx: 'a> {
|
||||
hir: Cx<'a, 'tcx>,
|
||||
@ -75,13 +75,14 @@ macro_rules! unpack {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// construct() -- the main entry point for building MIR for a function
|
||||
|
||||
pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>,
|
||||
_span: Span,
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> Mir<'tcx> {
|
||||
pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
|
||||
_span: Span,
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
|
||||
argument_extent: CodeExtent,
|
||||
return_ty: FnOutput<'tcx>,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> Mir<'tcx> {
|
||||
let cfg = CFG { basic_blocks: vec![] };
|
||||
|
||||
// it's handy to have a temporary of type `()` sometimes, so make
|
||||
@ -121,6 +122,7 @@ pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>,
|
||||
var_decls: builder.var_decls,
|
||||
arg_decls: arg_decls,
|
||||
temp_decls: builder.temp_decls,
|
||||
return_ty: return_ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hair::*;
|
||||
|
||||
use tcx::Cx;
|
||||
use tcx::pattern::PatNode;
|
||||
use tcx::to_ref::ToRef;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::pattern::PatNode;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use rustc::middle::region::{BlockRemainder, CodeExtentData};
|
||||
use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
@ -34,22 +33,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Stmt {
|
||||
type Output = Stmt<'tcx>;
|
||||
|
||||
fn make_mirror<'a>(self, _cx: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> {
|
||||
// In order to get the scoping correct, we eagerly mirror
|
||||
// statements when we translate the enclosing block, so we
|
||||
// should in fact never get to this point.
|
||||
panic!("statements are eagerly mirrored");
|
||||
}
|
||||
}
|
||||
|
||||
fn mirror_stmts<'a, 'tcx: 'a, STMTS>(cx: &mut Cx<'a, 'tcx>,
|
||||
block_id: ast::NodeId,
|
||||
mut stmts: STMTS)
|
||||
-> Vec<StmtRef<'tcx>>
|
||||
where STMTS: Iterator<Item = (usize, &'tcx P<hir::Stmt>)>
|
||||
fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
||||
block_id: ast::NodeId,
|
||||
mut stmts: STMTS)
|
||||
-> Vec<StmtRef<'tcx>>
|
||||
where STMTS: Iterator<Item=(usize, &'tcx P<hir::Stmt>)>
|
||||
{
|
||||
let mut result = vec![];
|
||||
while let Some((index, stmt)) = stmts.next() {
|
@ -12,16 +12,16 @@ use hair::*;
|
||||
use repr::*;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use std::rc::Rc;
|
||||
use tcx::Cx;
|
||||
use tcx::block;
|
||||
use tcx::pattern::PatNode;
|
||||
use tcx::to_ref::ToRef;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::block;
|
||||
use hair::cx::pattern::PatNode;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use rustc::front::map;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::def;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::pat_util;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc::middle::ty::{self, VariantDef, Ty};
|
||||
use rustc_front::hir;
|
||||
use rustc_front::util as hir_util;
|
||||
use syntax::parse::token;
|
||||
@ -170,11 +170,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
hir::ExprStruct(_, ref fields, ref base) => {
|
||||
match expr_ty.sty {
|
||||
ty::TyStruct(adt, substs) => {
|
||||
let field_refs = field_refs(&adt.variants[0], fields);
|
||||
ExprKind::Adt {
|
||||
adt_def: adt,
|
||||
variant_index: 0,
|
||||
substs: substs,
|
||||
fields: fields.to_ref(),
|
||||
fields: field_refs,
|
||||
base: base.to_ref(),
|
||||
}
|
||||
}
|
||||
@ -183,11 +184,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
def::DefVariant(enum_id, variant_id, true) => {
|
||||
debug_assert!(adt.did == enum_id);
|
||||
let index = adt.variant_index_with_id(variant_id);
|
||||
let field_refs = field_refs(&adt.variants[index], fields);
|
||||
ExprKind::Adt {
|
||||
adt_def: adt,
|
||||
variant_index: index,
|
||||
substs: substs,
|
||||
fields: fields.to_ref(),
|
||||
fields: field_refs,
|
||||
base: base.to_ref(),
|
||||
}
|
||||
}
|
||||
@ -238,11 +240,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
}
|
||||
};
|
||||
|
||||
let field_expr_ref = |s: &'tcx P<hir::Expr>, nm: &str| {
|
||||
FieldExprRef {
|
||||
name: Field::Named(token::intern(nm)),
|
||||
expr: s.to_ref(),
|
||||
}
|
||||
let field_expr_ref = |s: &'tcx P<hir::Expr>, name: &str| {
|
||||
let name = token::intern(name);
|
||||
let index = adt_def.variants[0].index_of_field_named(name).unwrap();
|
||||
FieldExprRef { name: Field::new(index), expr: s.to_ref() }
|
||||
};
|
||||
|
||||
let start_field = start.as_ref()
|
||||
@ -293,12 +294,25 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
hir::ExprLoop(ref body, _) =>
|
||||
ExprKind::Loop { condition: None,
|
||||
body: block::to_expr_ref(cx, body) },
|
||||
hir::ExprField(ref source, name) =>
|
||||
ExprKind::Field { lhs: source.to_ref(),
|
||||
name: Field::Named(name.node) },
|
||||
hir::ExprField(ref source, name) => {
|
||||
let index = match cx.tcx.expr_ty_adjusted(source).sty {
|
||||
ty::TyStruct(adt_def, _) =>
|
||||
adt_def.variants[0].index_of_field_named(name.node),
|
||||
ref ty =>
|
||||
cx.tcx.sess.span_bug(
|
||||
self.span,
|
||||
&format!("field of non-struct: {:?}", ty)),
|
||||
};
|
||||
let index = index.unwrap_or_else(|| {
|
||||
cx.tcx.sess.span_bug(
|
||||
self.span,
|
||||
&format!("no index found for field `{}`", name.node));
|
||||
});
|
||||
ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
|
||||
}
|
||||
hir::ExprTupField(ref source, index) =>
|
||||
ExprKind::Field { lhs: source.to_ref(),
|
||||
name: Field::Indexed(index.node) },
|
||||
name: Field::new(index.node as usize) },
|
||||
hir::ExprCast(ref source, _) =>
|
||||
ExprKind::Cast { source: source.to_ref() },
|
||||
hir::ExprBox(ref value) =>
|
||||
@ -616,7 +630,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
|
||||
// at this point we have `self.n`, which loads up the upvar
|
||||
let field_kind = ExprKind::Field {
|
||||
lhs: self_expr.to_ref(),
|
||||
name: Field::Indexed(index),
|
||||
name: Field::new(index),
|
||||
};
|
||||
|
||||
// ...but the upvar might be an `&T` or `&mut T` capture, at which
|
||||
@ -814,3 +828,15 @@ fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Cod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn field_refs<'tcx>(variant: VariantDef<'tcx>,
|
||||
fields: &'tcx [hir::Field])
|
||||
-> Vec<FieldExprRef<'tcx>>
|
||||
{
|
||||
fields.iter()
|
||||
.map(|field| FieldExprRef {
|
||||
name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
|
||||
expr: field.expr.to_ref(),
|
||||
})
|
||||
.collect()
|
||||
}
|
149
src/librustc_mir/hair/cx/mod.rs
Normal file
149
src/librustc_mir/hair/cx/mod.rs
Normal file
@ -0,0 +1,149 @@
|
||||
// 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 module contains the code to convert from the wacky tcx data
|
||||
* structures into the hair. The `builder` is generally ignorant of
|
||||
* the tcx etc, and instead goes through the `Cx` for most of its
|
||||
* work.
|
||||
*/
|
||||
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::infer::InferCtxt;
|
||||
use rustc::middle::subst::{Subst, Substs};
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cx<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Cx<'a,'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Cx<'a, 'tcx> {
|
||||
Cx {
|
||||
tcx: infcx.tcx,
|
||||
infcx: infcx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::pattern::PatNode;
|
||||
|
||||
impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
||||
/// Normalizes `ast` into the appropriate `mirror` type.
|
||||
pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
|
||||
ast.make_mirror(self)
|
||||
}
|
||||
|
||||
pub fn unit_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.mk_nil()
|
||||
}
|
||||
|
||||
pub fn usize_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
||||
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Uint(value as u64) }
|
||||
}
|
||||
|
||||
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.bool
|
||||
}
|
||||
|
||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(true) }
|
||||
}
|
||||
|
||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(false) }
|
||||
}
|
||||
|
||||
pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
|
||||
self.cmp_method_ref(eq_def_id, "eq", ty)
|
||||
}
|
||||
|
||||
pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let ord_def_id = self.tcx.lang_items.ord_trait().unwrap();
|
||||
self.cmp_method_ref(ord_def_id, "le", ty)
|
||||
}
|
||||
|
||||
pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
|
||||
adt_def.variants.len()
|
||||
}
|
||||
|
||||
pub fn all_fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field> {
|
||||
(0..adt_def.variants[variant_index].fields.len())
|
||||
.map(Field::new)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if self.infcx.type_moves_by_default(ty, span) {
|
||||
// FIXME(#21859) we should do an add'l check here to determine if
|
||||
// any dtor will execute, but the relevant fn
|
||||
// (`type_needs_drop`) is currently factored into
|
||||
// `librustc_trans`, so we can't easily do so.
|
||||
true
|
||||
} else {
|
||||
// if type implements Copy, cannot require drop
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_bug(&mut self, span: Span, message: &str) -> ! {
|
||||
self.tcx.sess.span_bug(span, message)
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn cmp_method_ref(&mut self,
|
||||
trait_def_id: DefId,
|
||||
method_name: &str,
|
||||
arg_ty: Ty<'tcx>)
|
||||
-> ItemRef<'tcx> {
|
||||
let method_name = token::intern(method_name);
|
||||
let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty);
|
||||
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
|
||||
match *trait_item {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
|
||||
if method.name == method_name {
|
||||
let method_ty = self.tcx.lookup_item_type(method.def_id);
|
||||
let method_ty = method_ty.ty.subst(self.tcx, &substs);
|
||||
return ItemRef {
|
||||
ty: method_ty,
|
||||
def_id: method.def_id,
|
||||
substs: self.tcx.mk_substs(substs),
|
||||
};
|
||||
}
|
||||
}
|
||||
ty::ImplOrTraitItem::ConstTraitItem(..) |
|
||||
ty::ImplOrTraitItem::TypeTraitItem(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx.sess.bug(&format!("found no method `{}` in `{:?}`", method_name, trait_def_id));
|
||||
}
|
||||
}
|
||||
|
||||
mod block;
|
||||
mod expr;
|
||||
mod pattern;
|
||||
mod to_ref;
|
@ -9,12 +9,11 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hair::*;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use repr::*;
|
||||
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use std::rc::Rc;
|
||||
use tcx::Cx;
|
||||
use tcx::to_ref::ToRef;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::def;
|
||||
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
|
||||
@ -223,7 +222,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
|
||||
subpatterns.iter()
|
||||
.enumerate()
|
||||
.map(|(i, subpattern)| FieldPatternRef {
|
||||
field: Field::Indexed(i),
|
||||
field: Field::new(i),
|
||||
pattern: self.pat_ref(subpattern),
|
||||
})
|
||||
.collect();
|
||||
@ -273,7 +272,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
|
||||
.flat_map(|v| v.iter())
|
||||
.enumerate()
|
||||
.map(|(i, field)| FieldPatternRef {
|
||||
field: Field::Indexed(i),
|
||||
field: Field::new(i),
|
||||
pattern: self.pat_ref(field),
|
||||
})
|
||||
.collect();
|
||||
@ -281,13 +280,35 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
|
||||
}
|
||||
|
||||
hir::PatStruct(_, ref fields, _) => {
|
||||
let pat_ty = cx.tcx.node_id_to_type(self.pat.id);
|
||||
let adt_def = match pat_ty.sty {
|
||||
ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def,
|
||||
_ => {
|
||||
cx.tcx.sess.span_bug(
|
||||
self.pat.span,
|
||||
"struct pattern not applied to struct or enum");
|
||||
}
|
||||
};
|
||||
|
||||
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
|
||||
let variant_def = adt_def.variant_of_def(def);
|
||||
|
||||
let subpatterns =
|
||||
fields.iter()
|
||||
.map(|field| FieldPatternRef {
|
||||
field: Field::Named(field.node.name),
|
||||
pattern: self.pat_ref(&field.node.pat),
|
||||
.map(|field| {
|
||||
let index = variant_def.index_of_field_named(field.node.name);
|
||||
let index = index.unwrap_or_else(|| {
|
||||
cx.tcx.sess.span_bug(
|
||||
self.pat.span,
|
||||
&format!("no field with name {:?}", field.node.name));
|
||||
});
|
||||
FieldPatternRef {
|
||||
field: Field::new(index),
|
||||
pattern: self.pat_ref(&field.node.pat),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.variant_or_leaf(cx, subpatterns)
|
||||
}
|
||||
|
@ -9,9 +9,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
use tcx::pattern::PatNode;
|
||||
use hair::cx::pattern::PatNode;
|
||||
use rustc_front::hir;
|
||||
use syntax::ptr::P;
|
||||
|
||||
@ -79,14 +78,3 @@ impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec<T>
|
||||
self.iter().map(|expr| expr.to_ref()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef for &'tcx hir::Field {
|
||||
type Output = FieldExprRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> FieldExprRef<'tcx> {
|
||||
FieldExprRef {
|
||||
name: Field::Named(self.name.node),
|
||||
expr: self.expr.to_ref(),
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,9 @@ use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
|
||||
use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use tcx::{Cx, PatNode};
|
||||
use self::cx::{Cx, PatNode};
|
||||
|
||||
pub mod cx;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ItemRef<'tcx> {
|
||||
@ -41,7 +43,6 @@ pub struct Block<'tcx> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StmtRef<'tcx> {
|
||||
Hair(&'tcx hir::Stmt),
|
||||
Mirror(Box<Stmt<'tcx>>),
|
||||
}
|
||||
|
||||
@ -392,9 +393,8 @@ impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
|
||||
impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
|
||||
type Output = Stmt<'tcx>;
|
||||
|
||||
fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> {
|
||||
fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Stmt<'tcx> {
|
||||
match self {
|
||||
StmtRef::Hair(h) => h.make_mirror(hir),
|
||||
StmtRef::Mirror(m) => *m,
|
||||
}
|
||||
}
|
@ -31,7 +31,9 @@ extern crate syntax;
|
||||
|
||||
pub mod build;
|
||||
pub mod mir_map;
|
||||
pub mod hair;
|
||||
mod hair;
|
||||
pub mod repr;
|
||||
mod graphviz;
|
||||
mod tcx;
|
||||
pub mod tcx;
|
||||
pub mod visit;
|
||||
|
||||
|
@ -23,8 +23,8 @@ extern crate rustc_front;
|
||||
use build;
|
||||
use dot;
|
||||
use repr::Mir;
|
||||
use hair::cx::{PatNode, Cx};
|
||||
use std::fs::File;
|
||||
use tcx::{PatNode, Cx};
|
||||
|
||||
use self::rustc::middle::infer;
|
||||
use self::rustc::middle::region::CodeExtentData;
|
||||
@ -189,26 +189,42 @@ impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_mir<'a, 'tcx: 'a>(cx: Cx<'a, 'tcx>,
|
||||
implicit_arg_tys: Vec<Ty<'tcx>>,
|
||||
fn_id: ast::NodeId,
|
||||
span: Span,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block)
|
||||
-> Result<Mir<'tcx>, ErrorReported> {
|
||||
let arguments = decl.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let ty = cx.tcx().node_id_to_type(arg.id);
|
||||
(ty, PatNode::irrefutable(&arg.pat))
|
||||
})
|
||||
.collect();
|
||||
fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
|
||||
implicit_arg_tys: Vec<Ty<'tcx>>,
|
||||
fn_id: ast::NodeId,
|
||||
span: Span,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block)
|
||||
-> Result<Mir<'tcx>, ErrorReported> {
|
||||
// fetch the fully liberated fn signature (that is, all bound
|
||||
// types/lifetimes replaced)
|
||||
let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
|
||||
Some(f) => f.clone(),
|
||||
None => {
|
||||
cx.tcx().sess.span_bug(span,
|
||||
&format!("no liberated fn sig for {:?}", fn_id));
|
||||
}
|
||||
};
|
||||
|
||||
let parameter_scope = cx.tcx().region_maps.lookup_code_extent(CodeExtentData::ParameterScope {
|
||||
fn_id: fn_id,
|
||||
body_id: body.id,
|
||||
});
|
||||
Ok(build::construct(cx, span, implicit_arg_tys, arguments, parameter_scope, body))
|
||||
let arguments =
|
||||
decl.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
(fn_sig.inputs[index], PatNode::irrefutable(&arg.pat))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let parameter_scope =
|
||||
cx.tcx().region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
|
||||
Ok(build::construct(cx,
|
||||
span,
|
||||
implicit_arg_tys,
|
||||
arguments,
|
||||
parameter_scope,
|
||||
fn_sig.output,
|
||||
body))
|
||||
}
|
||||
|
||||
fn closure_self_ty<'a, 'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
@ -12,7 +12,7 @@ use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
|
||||
use rustc::middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||
use rustc_back::slice;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc_front::hir::InlineAsm;
|
||||
@ -25,6 +25,8 @@ use std::u32;
|
||||
pub struct Mir<'tcx> {
|
||||
pub basic_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
|
||||
pub return_ty: FnOutput<'tcx>,
|
||||
|
||||
// for every node id
|
||||
pub extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>,
|
||||
|
||||
@ -245,6 +247,7 @@ pub enum Terminator<'tcx> {
|
||||
/// lvalue evaluates to some enum; jump depending on the branch
|
||||
Switch {
|
||||
discr: Lvalue<'tcx>,
|
||||
adt_def: AdtDef<'tcx>,
|
||||
targets: Vec<BasicBlock>,
|
||||
},
|
||||
|
||||
@ -277,7 +280,7 @@ impl<'tcx> Terminator<'tcx> {
|
||||
Goto { target: ref b } => slice::ref_slice(b),
|
||||
Panic { target: ref b } => slice::ref_slice(b),
|
||||
If { cond: _, targets: ref b } => b,
|
||||
Switch { discr: _, targets: ref b } => b,
|
||||
Switch { discr: _, adt_def: _, targets: ref b } => b,
|
||||
Diverge => &[],
|
||||
Return => &[],
|
||||
Call { data: _, targets: ref b } => b,
|
||||
@ -291,10 +294,10 @@ pub struct CallData<'tcx> {
|
||||
pub destination: Lvalue<'tcx>,
|
||||
|
||||
/// the fn being called
|
||||
pub func: Lvalue<'tcx>,
|
||||
pub func: Operand<'tcx>,
|
||||
|
||||
/// the arguments
|
||||
pub args: Vec<Lvalue<'tcx>>,
|
||||
pub args: Vec<Operand<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> BasicBlockData<'tcx> {
|
||||
@ -316,7 +319,7 @@ impl<'tcx> Debug for Terminator<'tcx> {
|
||||
write!(fmt, "panic -> {:?}", target),
|
||||
If { cond: ref lv, ref targets } =>
|
||||
write!(fmt, "if({:?}) -> {:?}", lv, targets),
|
||||
Switch { discr: ref lv, ref targets } =>
|
||||
Switch { discr: ref lv, adt_def: _, ref targets } =>
|
||||
write!(fmt, "switch({:?}) -> {:?}", lv, targets),
|
||||
Diverge =>
|
||||
write!(fmt, "diverge"),
|
||||
@ -353,8 +356,8 @@ pub enum StatementKind<'tcx> {
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DropKind {
|
||||
Shallow,
|
||||
Deep,
|
||||
Free, // free a partially constructed box, should go away eventually
|
||||
Deep
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Statement<'tcx> {
|
||||
@ -362,7 +365,7 @@ impl<'tcx> Debug for Statement<'tcx> {
|
||||
use self::StatementKind::*;
|
||||
match self.kind {
|
||||
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
|
||||
Drop(DropKind::Shallow, ref lv) => write!(fmt, "shallow_drop {:?}", lv),
|
||||
Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv),
|
||||
Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv),
|
||||
}
|
||||
}
|
||||
@ -441,10 +444,19 @@ pub type LvalueProjection<'tcx> =
|
||||
pub type LvalueElem<'tcx> =
|
||||
ProjectionElem<'tcx,Operand<'tcx>>;
|
||||
|
||||
/// Index into the list of fields found in a `VariantDef`
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Field {
|
||||
Named(Name),
|
||||
Indexed(usize),
|
||||
pub struct Field(u32);
|
||||
|
||||
impl Field {
|
||||
pub fn new(value: usize) -> Field {
|
||||
assert!(value < (u32::MAX) as usize);
|
||||
Field(value as u32)
|
||||
}
|
||||
|
||||
pub fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lvalue<'tcx> {
|
||||
@ -489,10 +501,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
||||
write!(fmt,"({:?} as {:?})", data.base, variant_index),
|
||||
ProjectionElem::Deref =>
|
||||
write!(fmt,"(*{:?})", data.base),
|
||||
ProjectionElem::Field(Field::Named(name)) =>
|
||||
write!(fmt,"{:?}.{:?}", data.base, name),
|
||||
ProjectionElem::Field(Field::Indexed(index)) =>
|
||||
write!(fmt,"{:?}.{:?}", data.base, index),
|
||||
ProjectionElem::Field(field) =>
|
||||
write!(fmt,"{:?}.{:?}", data.base, field.index()),
|
||||
ProjectionElem::Index(ref index) =>
|
||||
write!(fmt,"{:?}[{:?}]", data.base, index),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
|
||||
|
@ -9,150 +9,117 @@
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* This module contains the code to convert from the wacky tcx data
|
||||
* structures into the hair. The `builder` is generally ignorant of
|
||||
* the tcx etc, and instead goes through the `Cx` for most of its
|
||||
* work.
|
||||
* Methods for the various MIR types. These are intended for use after
|
||||
* building is complete.
|
||||
*/
|
||||
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::ty::{self, AdtDef, Ty};
|
||||
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::infer::InferCtxt;
|
||||
use rustc::middle::subst::{Subst, Substs};
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::{self, special_idents};
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LvalueTy<'tcx> {
|
||||
/// Normal type.
|
||||
Ty { ty: Ty<'tcx> },
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cx<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
/// Downcast to a particular variant of an enum.
|
||||
Downcast { adt_def: AdtDef<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
variant_index: usize },
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Cx<'a,'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Cx<'a, 'tcx> {
|
||||
Cx {
|
||||
tcx: infcx.tcx,
|
||||
infcx: infcx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::pattern::PatNode;
|
||||
|
||||
impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
||||
/// Normalizes `ast` into the appropriate `mirror` type.
|
||||
pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
|
||||
ast.make_mirror(self)
|
||||
impl<'tcx> LvalueTy<'tcx> {
|
||||
pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
|
||||
LvalueTy::Ty { ty: ty }
|
||||
}
|
||||
|
||||
pub fn unit_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.mk_nil()
|
||||
}
|
||||
|
||||
pub fn usize_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
||||
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Uint(value as u64) }
|
||||
}
|
||||
|
||||
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.bool
|
||||
}
|
||||
|
||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(true) }
|
||||
}
|
||||
|
||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(false) }
|
||||
}
|
||||
|
||||
pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
|
||||
self.cmp_method_ref(eq_def_id, "eq", ty)
|
||||
}
|
||||
|
||||
pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let ord_def_id = self.tcx.lang_items.ord_trait().unwrap();
|
||||
self.cmp_method_ref(ord_def_id, "le", ty)
|
||||
}
|
||||
|
||||
pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
|
||||
adt_def.variants.len()
|
||||
}
|
||||
|
||||
pub fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field> {
|
||||
adt_def.variants[variant_index]
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, field)| {
|
||||
if field.name == special_idents::unnamed_field.name {
|
||||
Field::Indexed(index)
|
||||
} else {
|
||||
Field::Named(field.name)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if self.infcx.type_moves_by_default(ty, span) {
|
||||
// FIXME(#21859) we should do an add'l check here to determine if
|
||||
// any dtor will execute, but the relevant fn
|
||||
// (`type_needs_drop`) is currently factored into
|
||||
// `librustc_trans`, so we can't easily do so.
|
||||
true
|
||||
} else {
|
||||
// if type implements Copy, cannot require drop
|
||||
false
|
||||
pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
LvalueTy::Ty { ty } =>
|
||||
ty,
|
||||
LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
|
||||
tcx.mk_enum(adt_def, substs),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_bug(&mut self, span: Span, message: &str) -> ! {
|
||||
self.tcx.sess.span_bug(span, message)
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn cmp_method_ref(&mut self,
|
||||
trait_def_id: DefId,
|
||||
method_name: &str,
|
||||
arg_ty: Ty<'tcx>)
|
||||
-> ItemRef<'tcx> {
|
||||
let method_name = token::intern(method_name);
|
||||
let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty);
|
||||
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
|
||||
match *trait_item {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
|
||||
if method.name == method_name {
|
||||
let method_ty = self.tcx.lookup_item_type(method.def_id);
|
||||
let method_ty = method_ty.ty.subst(self.tcx, &substs);
|
||||
return ItemRef {
|
||||
ty: method_ty,
|
||||
def_id: method.def_id,
|
||||
substs: self.tcx.mk_substs(substs),
|
||||
};
|
||||
pub fn projection_ty(self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
elem: &LvalueElem<'tcx>)
|
||||
-> LvalueTy<'tcx>
|
||||
{
|
||||
match *elem {
|
||||
ProjectionElem::Deref =>
|
||||
LvalueTy::Ty {
|
||||
ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
|
||||
.unwrap()
|
||||
.ty
|
||||
},
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
|
||||
LvalueTy::Ty {
|
||||
ty: self.to_ty(tcx).builtin_index().unwrap()
|
||||
},
|
||||
ProjectionElem::Downcast(adt_def1, index) =>
|
||||
match self.to_ty(tcx).sty {
|
||||
ty::TyEnum(adt_def, substs) => {
|
||||
assert!(index < adt_def.variants.len());
|
||||
assert_eq!(adt_def, adt_def1);
|
||||
LvalueTy::Downcast { adt_def: adt_def,
|
||||
substs: substs,
|
||||
variant_index: index }
|
||||
}
|
||||
}
|
||||
ty::ImplOrTraitItem::ConstTraitItem(..) |
|
||||
ty::ImplOrTraitItem::TypeTraitItem(..) => {}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(field) => {
|
||||
let field_ty = match self {
|
||||
LvalueTy::Ty { ty } => match ty.sty {
|
||||
ty::TyStruct(adt_def, substs) =>
|
||||
adt_def.struct_variant().fields[field.index()].ty(tcx, substs),
|
||||
ty::TyTuple(ref tys) =>
|
||||
tys[field.index()],
|
||||
_ =>
|
||||
tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)),
|
||||
},
|
||||
LvalueTy::Downcast { adt_def, substs, variant_index } =>
|
||||
adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs),
|
||||
};
|
||||
LvalueTy::Ty { ty: field_ty }
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx.sess.bug(&format!("found no method `{}` in `{:?}`", method_name, trait_def_id));
|
||||
}
|
||||
}
|
||||
|
||||
mod block;
|
||||
mod expr;
|
||||
mod pattern;
|
||||
mod to_ref;
|
||||
impl<'tcx> Mir<'tcx> {
|
||||
pub fn operand_ty(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
operand: &Operand<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
match *operand {
|
||||
Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx),
|
||||
Operand::Constant(ref c) => c.ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lvalue_ty(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
lvalue: &Lvalue<'tcx>)
|
||||
-> LvalueTy<'tcx>
|
||||
{
|
||||
match *lvalue {
|
||||
Lvalue::Var(index) =>
|
||||
LvalueTy::Ty { ty: self.var_decls[index as usize].ty },
|
||||
Lvalue::Temp(index) =>
|
||||
LvalueTy::Ty { ty: self.temp_decls[index as usize].ty },
|
||||
Lvalue::Arg(index) =>
|
||||
LvalueTy::Ty { ty: self.arg_decls[index as usize].ty },
|
||||
Lvalue::Static(def_id) =>
|
||||
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
|
||||
Lvalue::ReturnPointer =>
|
||||
LvalueTy::Ty { ty: self.return_ty.unwrap() },
|
||||
Lvalue::Projection(ref proj) =>
|
||||
self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
239
src/librustc_mir/visit.rs
Normal file
239
src/librustc_mir/visit.rs
Normal file
@ -0,0 +1,239 @@
|
||||
// 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 rustc::middle::ty::Region;
|
||||
use repr::*;
|
||||
|
||||
pub trait Visitor<'tcx> {
|
||||
// Override these, and call `self.super_xxx` to revert back to the
|
||||
// default behavior.
|
||||
|
||||
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
self.super_mir(mir);
|
||||
}
|
||||
|
||||
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
|
||||
self.super_basic_block_data(block, data);
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
|
||||
self.super_statement(block, statement);
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
|
||||
self.super_assign(block, lvalue, rvalue);
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
|
||||
self.super_terminator(block, terminator);
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
|
||||
self.super_rvalue(rvalue);
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
self.super_operand(operand);
|
||||
}
|
||||
|
||||
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
|
||||
self.super_lvalue(lvalue, context);
|
||||
}
|
||||
|
||||
fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
|
||||
self.super_branch(source, target);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>) {
|
||||
self.super_constant(constant);
|
||||
}
|
||||
|
||||
// The `super_xxx` methods comprise the default behavior and are
|
||||
// not meant to be overidden.
|
||||
|
||||
fn super_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
for block in mir.all_basic_blocks() {
|
||||
let data = mir.basic_block_data(block);
|
||||
self.visit_basic_block_data(block, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
|
||||
for statement in &data.statements {
|
||||
self.visit_statement(block, statement);
|
||||
}
|
||||
self.visit_terminator(block, &data.terminator);
|
||||
}
|
||||
|
||||
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(ref lvalue, ref rvalue) => {
|
||||
self.visit_assign(block, lvalue, rvalue);
|
||||
}
|
||||
StatementKind::Drop(_, ref lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Drop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Store);
|
||||
self.visit_rvalue(rvalue);
|
||||
}
|
||||
|
||||
fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
|
||||
match *terminator {
|
||||
Terminator::Goto { target } |
|
||||
Terminator::Panic { target } => {
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
|
||||
Terminator::If { ref cond, ref targets } => {
|
||||
self.visit_operand(cond);
|
||||
for &target in &targets[..] {
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
}
|
||||
|
||||
Terminator::Switch { ref discr, adt_def: _, ref targets } => {
|
||||
self.visit_lvalue(discr, LvalueContext::Inspect);
|
||||
for &target in targets {
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
}
|
||||
|
||||
Terminator::Diverge |
|
||||
Terminator::Return => {
|
||||
}
|
||||
|
||||
Terminator::Call { ref data, ref targets } => {
|
||||
self.visit_lvalue(&data.destination, LvalueContext::Store);
|
||||
self.visit_operand(&data.func);
|
||||
for arg in &data.args {
|
||||
self.visit_operand(arg);
|
||||
}
|
||||
for &target in &targets[..] {
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref operand) => {
|
||||
self.visit_operand(operand);
|
||||
}
|
||||
|
||||
Rvalue::Repeat(ref value, ref len) => {
|
||||
self.visit_operand(value);
|
||||
self.visit_operand(len);
|
||||
}
|
||||
|
||||
Rvalue::Ref(r, bk, ref path) => {
|
||||
self.visit_lvalue(path, LvalueContext::Borrow {
|
||||
region: r,
|
||||
kind: bk
|
||||
});
|
||||
}
|
||||
|
||||
Rvalue::Len(ref path) => {
|
||||
self.visit_lvalue(path, LvalueContext::Inspect);
|
||||
}
|
||||
|
||||
Rvalue::Cast(_, ref operand, _) => {
|
||||
self.visit_operand(operand);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_, ref lhs, ref rhs) => {
|
||||
self.visit_operand(lhs);
|
||||
self.visit_operand(rhs);
|
||||
}
|
||||
|
||||
Rvalue::UnaryOp(_, ref op) => {
|
||||
self.visit_operand(op);
|
||||
}
|
||||
|
||||
Rvalue::Box(_) => {
|
||||
}
|
||||
|
||||
Rvalue::Aggregate(_, ref operands) => {
|
||||
for operand in operands {
|
||||
self.visit_operand(operand);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Slice { ref input, from_start, from_end } => {
|
||||
self.visit_lvalue(input, LvalueContext::Slice {
|
||||
from_start: from_start,
|
||||
from_end: from_end,
|
||||
});
|
||||
}
|
||||
|
||||
Rvalue::InlineAsm(_) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Consume(ref lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Consume);
|
||||
}
|
||||
Operand::Constant(ref constant) => {
|
||||
self.visit_constant(constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) {
|
||||
match *lvalue {
|
||||
Lvalue::Var(_) |
|
||||
Lvalue::Temp(_) |
|
||||
Lvalue::Arg(_) |
|
||||
Lvalue::Static(_) |
|
||||
Lvalue::ReturnPointer => {
|
||||
}
|
||||
Lvalue::Projection(ref proj) => {
|
||||
self.visit_lvalue(&proj.base, LvalueContext::Projection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
|
||||
}
|
||||
|
||||
fn super_constant(&mut self, _constant: &Constant<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LvalueContext {
|
||||
// Appears as LHS of an assignment or as dest of a call
|
||||
Store,
|
||||
|
||||
// Being dropped
|
||||
Drop,
|
||||
|
||||
// Being inspected in some way, like loading a len
|
||||
Inspect,
|
||||
|
||||
// Being borrowed
|
||||
Borrow { region: Region, kind: BorrowKind },
|
||||
|
||||
// Being sliced -- this should be same as being borrowed, probably
|
||||
Slice { from_start: usize, from_end: usize },
|
||||
|
||||
// Used as base for another lvalue, e.g. `x` in `x.y`
|
||||
Projection,
|
||||
|
||||
// Consumed as part of an operand
|
||||
Consume,
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
#![feature(quote)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unicode)]
|
||||
#![feature(vec_push_all)]
|
||||
@ -50,8 +51,10 @@ extern crate graphviz;
|
||||
extern crate libc;
|
||||
extern crate rustc;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_front;
|
||||
extern crate rustc_llvm as llvm;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_platform_intrinsics as intrinsics;
|
||||
extern crate serialize;
|
||||
|
||||
|
@ -303,7 +303,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> {
|
||||
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
|
||||
}
|
||||
Variant(disr_val, ref repr, _, _) => {
|
||||
adt::trans_case(bcx, &**repr, disr_val)
|
||||
SingleResult(Result::new(bcx, adt::trans_case(bcx, &**repr, disr_val)))
|
||||
}
|
||||
SliceLengthEqual(length, _) => {
|
||||
SingleResult(Result::new(bcx, C_uint(ccx, length)))
|
||||
|
@ -945,15 +945,13 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
|
||||
///
|
||||
/// This should ideally be less tightly tied to `_match`.
|
||||
pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
|
||||
-> _match::OptResult<'blk, 'tcx> {
|
||||
-> ValueRef {
|
||||
match *r {
|
||||
CEnum(ity, _, _) => {
|
||||
_match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
||||
discr as u64, true)))
|
||||
C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true)
|
||||
}
|
||||
General(ity, _, _) => {
|
||||
_match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
||||
discr as u64, true)))
|
||||
C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true)
|
||||
}
|
||||
Univariant(..) => {
|
||||
bcx.ccx().sess().bug("no cases for univariants or structs")
|
||||
@ -961,7 +959,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
|
||||
RawNullablePointer { .. } |
|
||||
StructWrappedNullablePointer { .. } => {
|
||||
assert!(discr == 0 || discr == 1);
|
||||
_match::SingleResult(Result::new(bcx, C_bool(bcx.ccx(), discr != 0)))
|
||||
C_bool(bcx.ccx(), discr != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ use middle::pat_util::simple_name;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty, HasTypeFlags};
|
||||
use rustc::front::map as hir_map;
|
||||
use rustc_mir::mir_map::MirMap;
|
||||
use session::config::{self, NoDebugInfo, FullDebugInfo};
|
||||
use session::Session;
|
||||
use trans::_match;
|
||||
@ -74,6 +75,7 @@ use trans::intrinsic;
|
||||
use trans::machine;
|
||||
use trans::machine::{llsize_of, llsize_of_real};
|
||||
use trans::meth;
|
||||
use trans::mir;
|
||||
use trans::monomorphize;
|
||||
use trans::tvec;
|
||||
use trans::type_::Type;
|
||||
@ -497,13 +499,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
|
||||
&format!("enum-iter-variant-{}",
|
||||
&variant.disr_val.to_string())
|
||||
);
|
||||
match adt::trans_case(cx, &*repr, variant.disr_val) {
|
||||
_match::SingleResult(r) => {
|
||||
AddCase(llswitch, r.val, variant_cx.llbb)
|
||||
}
|
||||
_ => ccx.sess().unimpl("value from adt::trans_case \
|
||||
in iter_structural_ty")
|
||||
}
|
||||
let case_val = adt::trans_case(cx, &*repr, variant.disr_val);
|
||||
AddCase(llswitch, case_val, variant_cx.llbb);
|
||||
let variant_cx =
|
||||
iter_variant(variant_cx,
|
||||
&*repr,
|
||||
@ -1235,7 +1232,10 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
false
|
||||
};
|
||||
|
||||
let mir = ccx.mir_map().get(&id);
|
||||
|
||||
let mut fcx = FunctionContext {
|
||||
mir: mir,
|
||||
llfn: llfndecl,
|
||||
llenv: None,
|
||||
llretslotptr: Cell::new(None),
|
||||
@ -1575,7 +1575,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
llfndecl: ValueRef,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
fn_ast_id: ast::NodeId,
|
||||
_attributes: &[ast::Attribute],
|
||||
attributes: &[ast::Attribute],
|
||||
output_type: ty::FnOutput<'tcx>,
|
||||
abi: Abi,
|
||||
closure_env: closure::ClosureEnv<'b>) {
|
||||
@ -1604,6 +1604,12 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
&arena);
|
||||
let mut bcx = init_function(&fcx, false, output_type);
|
||||
|
||||
if attributes.iter().any(|item| item.check_name("rustc_mir")) {
|
||||
mir::trans_mir(bcx);
|
||||
fcx.cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
// cleanup scope for the incoming arguments
|
||||
let fn_cleanup_debug_loc =
|
||||
debuginfo::get_cleanup_debug_loc_for_ast_node(ccx, fn_ast_id, body.span, true);
|
||||
@ -2737,7 +2743,10 @@ pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet {
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslation {
|
||||
pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
mir_map: &MirMap<'tcx>,
|
||||
analysis: ty::CrateAnalysis)
|
||||
-> CrateTranslation {
|
||||
let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
|
||||
let krate = tcx.map.krate();
|
||||
|
||||
@ -2779,6 +2788,7 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
|
||||
let shared_ccx = SharedCrateContext::new(&link_meta.crate_name,
|
||||
codegen_units,
|
||||
tcx,
|
||||
&mir_map,
|
||||
export_map,
|
||||
Sha256::new(),
|
||||
link_meta.clone(),
|
||||
|
@ -16,7 +16,7 @@ pub use self::ExprOrMethodCall::*;
|
||||
|
||||
use session::Session;
|
||||
use llvm;
|
||||
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef};
|
||||
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
|
||||
use llvm::{True, False, Bool};
|
||||
use middle::cfg;
|
||||
use middle::def;
|
||||
@ -40,6 +40,7 @@ use middle::traits;
|
||||
use middle::ty::{self, HasTypeFlags, Ty};
|
||||
use middle::ty::fold::{TypeFolder, TypeFoldable};
|
||||
use rustc_front::hir;
|
||||
use rustc_mir::repr::Mir;
|
||||
use util::nodemap::{FnvHashMap, NodeMap};
|
||||
|
||||
use arena::TypedArena;
|
||||
@ -328,6 +329,11 @@ impl<'tcx> DropFlagHintsMap<'tcx> {
|
||||
// Function context. Every LLVM function we create will have one of
|
||||
// these.
|
||||
pub struct FunctionContext<'a, 'tcx: 'a> {
|
||||
// The MIR for this function. At present, this is optional because
|
||||
// we only have MIR available for things that are local to the
|
||||
// crate.
|
||||
pub mir: Option<&'a Mir<'tcx>>,
|
||||
|
||||
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
|
||||
// address of the first instruction in the sequence of
|
||||
// instructions for this function that will go in the .text
|
||||
@ -407,6 +413,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
||||
pub fn mir(&self) -> &'a Mir<'tcx> {
|
||||
self.mir.unwrap()
|
||||
}
|
||||
|
||||
pub fn arg_offset(&self) -> usize {
|
||||
self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 }
|
||||
}
|
||||
@ -644,6 +654,10 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
|
||||
}
|
||||
pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() }
|
||||
|
||||
pub fn mir(&self) -> &'blk Mir<'tcx> {
|
||||
self.fcx.mir()
|
||||
}
|
||||
|
||||
pub fn name(&self, name: ast::Name) -> String {
|
||||
name.to_string()
|
||||
}
|
||||
@ -729,6 +743,12 @@ pub fn C_floating(s: &str, t: Type) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn C_floating_f64(f: f64, t: Type) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMConstReal(t.to_ref(), f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn C_nil(ccx: &CrateContext) -> ValueRef {
|
||||
C_struct(ccx, &[], false)
|
||||
}
|
||||
@ -1132,3 +1152,65 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid))
|
||||
})
|
||||
}
|
||||
|
||||
// To avoid UB from LLVM, these two functions mask RHS with an
|
||||
// appropriate mask unconditionally (i.e. the fallback behavior for
|
||||
// all shifts). For 32- and 64-bit types, this matches the semantics
|
||||
// of Java. (See related discussion on #1877 and #10183.)
|
||||
|
||||
pub fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
lhs: ValueRef,
|
||||
rhs: ValueRef,
|
||||
binop_debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
|
||||
build::Shl(bcx, lhs, rhs, binop_debug_loc)
|
||||
}
|
||||
|
||||
pub fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
lhs_t: Ty<'tcx>,
|
||||
lhs: ValueRef,
|
||||
rhs: ValueRef,
|
||||
binop_debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
|
||||
let is_signed = lhs_t.is_signed();
|
||||
if is_signed {
|
||||
build::AShr(bcx, lhs, rhs, binop_debug_loc)
|
||||
} else {
|
||||
build::LShr(bcx, lhs, rhs, binop_debug_loc)
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
rhs: ValueRef,
|
||||
debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs_llty = val_ty(rhs);
|
||||
build::And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
|
||||
}
|
||||
|
||||
pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
llty: Type,
|
||||
mask_llty: Type,
|
||||
invert: bool) -> ValueRef {
|
||||
let kind = llty.kind();
|
||||
match kind {
|
||||
TypeKind::Integer => {
|
||||
// i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
|
||||
let val = llty.int_width() - 1;
|
||||
if invert {
|
||||
C_integral(mask_llty, !val, true)
|
||||
} else {
|
||||
C_integral(mask_llty, val, false)
|
||||
}
|
||||
},
|
||||
TypeKind::Vector => {
|
||||
let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
|
||||
build::VectorSplat(bcx, mask_llty.vector_length(), mask)
|
||||
},
|
||||
_ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ use metadata::common::LinkMeta;
|
||||
use middle::def::ExportMap;
|
||||
use middle::def_id::DefId;
|
||||
use middle::traits;
|
||||
use rustc_mir::mir_map::MirMap;
|
||||
use trans::adt;
|
||||
use trans::base;
|
||||
use trans::builder::Builder;
|
||||
@ -70,6 +71,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
|
||||
stats: Stats,
|
||||
check_overflow: bool,
|
||||
check_drop_flag_for_sanity: bool,
|
||||
mir_map: &'a MirMap<'tcx>,
|
||||
|
||||
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
|
||||
use_dll_storage_attrs: bool,
|
||||
@ -251,6 +253,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
||||
pub fn new(crate_name: &str,
|
||||
local_count: usize,
|
||||
tcx: &'b ty::ctxt<'tcx>,
|
||||
mir_map: &'b MirMap<'tcx>,
|
||||
export_map: ExportMap,
|
||||
symbol_hasher: Sha256,
|
||||
link_meta: LinkMeta,
|
||||
@ -317,6 +320,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
||||
link_meta: link_meta,
|
||||
symbol_hasher: RefCell::new(symbol_hasher),
|
||||
tcx: tcx,
|
||||
mir_map: mir_map,
|
||||
stats: Stats {
|
||||
n_glues_created: Cell::new(0),
|
||||
n_null_glues: Cell::new(0),
|
||||
@ -803,6 +807,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
pub fn use_dll_storage_attrs(&self) -> bool {
|
||||
self.shared.use_dll_storage_attrs()
|
||||
}
|
||||
|
||||
pub fn mir_map(&self) -> &'b MirMap<'tcx> {
|
||||
self.shared.mir_map
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
|
||||
|
@ -2574,29 +2574,6 @@ impl OverflowOpViaInputCheck {
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
llty: Type,
|
||||
mask_llty: Type,
|
||||
invert: bool) -> ValueRef {
|
||||
let kind = llty.kind();
|
||||
match kind {
|
||||
TypeKind::Integer => {
|
||||
// i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
|
||||
let val = llty.int_width() - 1;
|
||||
if invert {
|
||||
C_integral(mask_llty, !val, true)
|
||||
} else {
|
||||
C_integral(mask_llty, val, false)
|
||||
}
|
||||
},
|
||||
TypeKind::Vector => {
|
||||
let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
|
||||
VectorSplat(bcx, mask_llty.vector_length(), mask)
|
||||
},
|
||||
_ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an integer or vector contains a nonzero element.
|
||||
fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
value: ValueRef,
|
||||
@ -2616,44 +2593,6 @@ fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
// To avoid UB from LLVM, these two functions mask RHS with an
|
||||
// appropriate mask unconditionally (i.e. the fallback behavior for
|
||||
// all shifts). For 32- and 64-bit types, this matches the semantics
|
||||
// of Java. (See related discussion on #1877 and #10183.)
|
||||
|
||||
fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
lhs: ValueRef,
|
||||
rhs: ValueRef,
|
||||
binop_debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
|
||||
Shl(bcx, lhs, rhs, binop_debug_loc)
|
||||
}
|
||||
|
||||
fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
lhs_t: Ty<'tcx>,
|
||||
lhs: ValueRef,
|
||||
rhs: ValueRef,
|
||||
binop_debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
|
||||
// #1877, #10183: Ensure that input is always valid
|
||||
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
|
||||
let is_signed = lhs_t.is_signed();
|
||||
if is_signed {
|
||||
AShr(bcx, lhs, rhs, binop_debug_loc)
|
||||
} else {
|
||||
LShr(bcx, lhs, rhs, binop_debug_loc)
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
rhs: ValueRef,
|
||||
debug_loc: DebugLoc) -> ValueRef {
|
||||
let rhs_llty = val_ty(rhs);
|
||||
And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
|
||||
}
|
||||
|
||||
fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
|
||||
lhs_t: Ty<'tcx>, lhs: ValueRef,
|
||||
rhs: ValueRef,
|
||||
|
115
src/librustc_trans/trans/mir/analyze.rs
Normal file
115
src/librustc_trans/trans/mir/analyze.rs
Normal file
@ -0,0 +1,115 @@
|
||||
// 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.
|
||||
|
||||
//! An analysis to determine which temporaries require allocas and
|
||||
//! which do not.
|
||||
|
||||
use rustc_data_structures::fnv::FnvHashSet;
|
||||
use rustc_mir::repr as mir;
|
||||
use rustc_mir::visit::{Visitor, LvalueContext};
|
||||
use trans::common::{self, Block};
|
||||
use super::rvalue;
|
||||
|
||||
pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
|
||||
mir: &mir::Mir<'tcx>)
|
||||
-> FnvHashSet<usize> {
|
||||
let mut analyzer = TempAnalyzer::new();
|
||||
|
||||
analyzer.visit_mir(mir);
|
||||
|
||||
for (index, temp_decl) in mir.temp_decls.iter().enumerate() {
|
||||
let ty = bcx.monomorphize(&temp_decl.ty);
|
||||
debug!("temp {:?} has type {:?}", index, ty);
|
||||
if
|
||||
ty.is_scalar() ||
|
||||
ty.is_unique() ||
|
||||
(ty.is_region_ptr() && !common::type_is_fat_ptr(bcx.tcx(), ty)) ||
|
||||
ty.is_simd()
|
||||
{
|
||||
// These sorts of types are immediates that we can store
|
||||
// in an ValueRef without an alloca.
|
||||
assert!(common::type_is_immediate(bcx.ccx(), ty));
|
||||
} else {
|
||||
// These sorts of types require an alloca. Note that
|
||||
// type_is_immediate() may *still* be true, particularly
|
||||
// for newtypes, but we currently force some types
|
||||
// (e.g. structs) into an alloca unconditionally, just so
|
||||
// that we don't have to deal with having two pathways
|
||||
// (gep vs extractvalue etc).
|
||||
analyzer.mark_as_lvalue(index);
|
||||
}
|
||||
}
|
||||
|
||||
analyzer.lvalue_temps
|
||||
}
|
||||
|
||||
struct TempAnalyzer {
|
||||
lvalue_temps: FnvHashSet<usize>,
|
||||
}
|
||||
|
||||
impl TempAnalyzer {
|
||||
fn new() -> TempAnalyzer {
|
||||
TempAnalyzer { lvalue_temps: FnvHashSet() }
|
||||
}
|
||||
|
||||
fn mark_as_lvalue(&mut self, temp: usize) {
|
||||
debug!("marking temp {} as lvalue", temp);
|
||||
self.lvalue_temps.insert(temp);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for TempAnalyzer {
|
||||
fn visit_assign(&mut self,
|
||||
block: mir::BasicBlock,
|
||||
lvalue: &mir::Lvalue<'tcx>,
|
||||
rvalue: &mir::Rvalue<'tcx>) {
|
||||
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
|
||||
|
||||
match *lvalue {
|
||||
mir::Lvalue::Temp(index) => {
|
||||
if !rvalue::rvalue_creates_operand(rvalue) {
|
||||
self.mark_as_lvalue(index as usize);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Store);
|
||||
}
|
||||
}
|
||||
|
||||
self.visit_rvalue(rvalue);
|
||||
}
|
||||
|
||||
fn visit_lvalue(&mut self,
|
||||
lvalue: &mir::Lvalue<'tcx>,
|
||||
context: LvalueContext) {
|
||||
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
|
||||
|
||||
match *lvalue {
|
||||
mir::Lvalue::Temp(index) => {
|
||||
match context {
|
||||
LvalueContext::Consume => {
|
||||
}
|
||||
LvalueContext::Store |
|
||||
LvalueContext::Drop |
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Borrow { .. } |
|
||||
LvalueContext::Slice { .. } |
|
||||
LvalueContext::Projection => {
|
||||
self.mark_as_lvalue(index as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
|
||||
self.super_lvalue(lvalue, context);
|
||||
}
|
||||
}
|
106
src/librustc_trans/trans/mir/block.rs
Normal file
106
src/librustc_trans/trans/mir/block.rs
Normal file
@ -0,0 +1,106 @@
|
||||
// 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 llvm::BasicBlockRef;
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::Block;
|
||||
use trans::debuginfo::DebugLoc;
|
||||
|
||||
use super::MirContext;
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
|
||||
debug!("trans_block({:?})", bb);
|
||||
|
||||
let mut bcx = self.bcx(bb);
|
||||
let data = self.mir.basic_block_data(bb);
|
||||
|
||||
for statement in &data.statements {
|
||||
bcx = self.trans_statement(bcx, statement);
|
||||
}
|
||||
|
||||
debug!("trans_block: terminator: {:?}", data.terminator);
|
||||
|
||||
match data.terminator {
|
||||
mir::Terminator::Goto { target } => {
|
||||
build::Br(bcx, self.llblock(target), DebugLoc::None)
|
||||
}
|
||||
|
||||
mir::Terminator::Panic { .. } => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mir::Terminator::If { ref cond, targets: [true_bb, false_bb] } => {
|
||||
let cond = self.trans_operand(bcx, cond);
|
||||
let lltrue = self.llblock(true_bb);
|
||||
let llfalse = self.llblock(false_bb);
|
||||
build::CondBr(bcx, cond.llval, lltrue, llfalse, DebugLoc::None);
|
||||
}
|
||||
|
||||
mir::Terminator::Switch { .. } => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mir::Terminator::Diverge => {
|
||||
if let Some(llpersonalityslot) = self.llpersonalityslot {
|
||||
let lp = build::Load(bcx, llpersonalityslot);
|
||||
// FIXME(lifetime) base::call_lifetime_end(bcx, self.personality);
|
||||
build::Resume(bcx, lp);
|
||||
} else {
|
||||
// This fn never encountered anything fallible, so
|
||||
// a Diverge cannot actually happen. Note that we
|
||||
// do a total hack to ensure that we visit the
|
||||
// DIVERGE block last.
|
||||
build::Unreachable(bcx);
|
||||
}
|
||||
}
|
||||
|
||||
mir::Terminator::Return => {
|
||||
let return_ty = bcx.monomorphize(&self.mir.return_ty);
|
||||
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
|
||||
}
|
||||
|
||||
mir::Terminator::Call { .. } => {
|
||||
unimplemented!()
|
||||
//let llbb = unimplemented!(); // self.make_landing_pad(panic_bb);
|
||||
//
|
||||
//let tr_dest = self.trans_lvalue(bcx, &data.destination);
|
||||
//
|
||||
//// Create the callee. This will always be a fn
|
||||
//// ptr and hence a kind of scalar.
|
||||
//let callee = self.trans_operand(bcx, &data.func);
|
||||
//
|
||||
//// Process the arguments.
|
||||
//
|
||||
//let args = unimplemented!();
|
||||
//
|
||||
//callee::trans_call_inner(bcx,
|
||||
// DebugLoc::None,
|
||||
// |bcx, _| Callee {
|
||||
// bcx: bcx,
|
||||
// data: CalleeData::Fn(callee.llval),
|
||||
// ty: callee.ty,
|
||||
// },
|
||||
// args,
|
||||
// Some(Dest::SaveIn(tr_dest.llval)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> {
|
||||
self.blocks[bb.index()]
|
||||
}
|
||||
|
||||
fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef {
|
||||
self.blocks[bb.index()].llbb
|
||||
}
|
||||
}
|
63
src/librustc_trans/trans/mir/constant.rs
Normal file
63
src/librustc_trans/trans/mir/constant.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// 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 llvm::ValueRef;
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::consts::{self, TrueConst};
|
||||
use trans::common::{self, Block};
|
||||
use trans::type_of;
|
||||
|
||||
use super::MirContext;
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_constant(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
constant: &mir::Constant<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
let ccx = bcx.ccx();
|
||||
let constant_ty = bcx.monomorphize(&constant.ty);
|
||||
let llty = type_of::type_of(ccx, constant_ty);
|
||||
match constant.literal {
|
||||
mir::Literal::Item { .. } => {
|
||||
unimplemented!()
|
||||
}
|
||||
mir::Literal::Value { ref value } => {
|
||||
match *value {
|
||||
ConstVal::Float(v) => common::C_floating_f64(v, llty),
|
||||
ConstVal::Bool(v) => common::C_bool(ccx, v),
|
||||
ConstVal::Int(v) => common::C_integral(llty, v as u64, true),
|
||||
ConstVal::Uint(v) => common::C_integral(llty, v, false),
|
||||
ConstVal::Str(ref v) => common::C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx,
|
||||
common::C_bytes(ccx, v),
|
||||
1,
|
||||
"byte_str"),
|
||||
ConstVal::Struct(id) | ConstVal::Tuple(id) => {
|
||||
let expr = bcx.tcx().map.expect_expr(id);
|
||||
let (llval, _) = match consts::const_expr(ccx,
|
||||
expr,
|
||||
bcx.fcx.param_substs,
|
||||
None,
|
||||
TrueConst::Yes) {
|
||||
Ok(v) => v,
|
||||
Err(_) => panic!("constant eval failure"),
|
||||
};
|
||||
llval
|
||||
}
|
||||
ConstVal::Function(_) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
154
src/librustc_trans/trans/mir/lvalue.rs
Normal file
154
src/librustc_trans/trans/mir/lvalue.rs
Normal file
@ -0,0 +1,154 @@
|
||||
// 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 llvm::ValueRef;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc_mir::repr as mir;
|
||||
use rustc_mir::tcx::LvalueTy;
|
||||
use trans::adt;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::{self, Block};
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::machine;
|
||||
use trans::tvec;
|
||||
|
||||
use super::{MirContext, TempRef};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LvalueRef<'tcx> {
|
||||
/// Pointer to the contents of the lvalue
|
||||
pub llval: ValueRef,
|
||||
|
||||
/// Monomorphized type of this lvalue, including variant information
|
||||
pub ty: LvalueTy<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> LvalueRef<'tcx> {
|
||||
pub fn new(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
|
||||
LvalueRef { llval: llval, ty: lvalue_ty }
|
||||
}
|
||||
|
||||
pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
name: &str)
|
||||
-> LvalueRef<'tcx>
|
||||
{
|
||||
let lltemp = base::alloc_ty(bcx, ty, name);
|
||||
LvalueRef::new(lltemp, LvalueTy::from_ty(ty))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_lvalue(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
lvalue: &mir::Lvalue<'tcx>)
|
||||
-> LvalueRef<'tcx> {
|
||||
debug!("trans_lvalue(lvalue={:?})", lvalue);
|
||||
|
||||
let fcx = bcx.fcx;
|
||||
let ccx = fcx.ccx;
|
||||
let tcx = bcx.tcx();
|
||||
match *lvalue {
|
||||
mir::Lvalue::Var(index) => self.vars[index as usize],
|
||||
mir::Lvalue::Temp(index) => match self.temps[index as usize] {
|
||||
TempRef::Lvalue(lvalue) =>
|
||||
lvalue,
|
||||
TempRef::Operand(..) =>
|
||||
tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
|
||||
},
|
||||
mir::Lvalue::Arg(index) => self.args[index as usize],
|
||||
mir::Lvalue::Static(_def_id) => unimplemented!(),
|
||||
mir::Lvalue::ReturnPointer => {
|
||||
let return_ty = bcx.monomorphize(&self.mir.return_ty);
|
||||
let llval = fcx.get_ret_slot(bcx, return_ty, "return");
|
||||
LvalueRef::new(llval, LvalueTy::from_ty(return_ty.unwrap()))
|
||||
}
|
||||
mir::Lvalue::Projection(ref projection) => {
|
||||
let tr_base = self.trans_lvalue(bcx, &projection.base);
|
||||
let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
|
||||
let llprojected = match projection.elem {
|
||||
mir::ProjectionElem::Deref => {
|
||||
let base_ty = tr_base.ty.to_ty(tcx);
|
||||
base::load_ty(bcx, tr_base.llval, base_ty)
|
||||
}
|
||||
mir::ProjectionElem::Field(ref field) => {
|
||||
let base_ty = tr_base.ty.to_ty(tcx);
|
||||
let base_repr = adt::represent_type(ccx, base_ty);
|
||||
let discr = match tr_base.ty {
|
||||
LvalueTy::Ty { .. } => 0,
|
||||
LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
|
||||
};
|
||||
let discr = discr as u64;
|
||||
adt::trans_field_ptr(bcx, &base_repr, tr_base.llval, discr, field.index())
|
||||
}
|
||||
mir::ProjectionElem::Index(ref index) => {
|
||||
let base_ty = tr_base.ty.to_ty(tcx);
|
||||
let index = self.trans_operand(bcx, index);
|
||||
let llindex = self.prepare_index(bcx, index.llval);
|
||||
let (llbase, _) = tvec::get_base_and_len(bcx, tr_base.llval, base_ty);
|
||||
build::InBoundsGEP(bcx, llbase, &[llindex])
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: false,
|
||||
min_length: _ } => {
|
||||
let base_ty = tr_base.ty.to_ty(tcx);
|
||||
let lloffset = common::C_u32(bcx.ccx(), offset);
|
||||
let llindex = self.prepare_index(bcx, lloffset);
|
||||
let (llbase, _) = tvec::get_base_and_len(bcx,
|
||||
tr_base.llval,
|
||||
base_ty);
|
||||
build::InBoundsGEP(bcx, llbase, &[llindex])
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: true,
|
||||
min_length: _ } => {
|
||||
let lloffset = common::C_u32(bcx.ccx(), offset);
|
||||
let base_ty = tr_base.ty.to_ty(tcx);
|
||||
let (llbase, lllen) = tvec::get_base_and_len(bcx,
|
||||
tr_base.llval,
|
||||
base_ty);
|
||||
let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
|
||||
let llindex = self.prepare_index(bcx, llindex);
|
||||
build::InBoundsGEP(bcx, llbase, &[llindex])
|
||||
}
|
||||
mir::ProjectionElem::Downcast(..) => {
|
||||
tr_base.llval
|
||||
}
|
||||
};
|
||||
LvalueRef {
|
||||
llval: llprojected,
|
||||
ty: projected_ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust the bitwidth of an index since LLVM is less forgiving
|
||||
/// than we are.
|
||||
///
|
||||
/// nmatsakis: is this still necessary? Not sure.
|
||||
fn prepare_index(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
llindex: ValueRef)
|
||||
-> ValueRef
|
||||
{
|
||||
let ccx = bcx.ccx();
|
||||
let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
|
||||
let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
|
||||
if index_size < int_size {
|
||||
build::ZExt(bcx, llindex, ccx.int_type())
|
||||
} else if index_size > int_size {
|
||||
build::Trunc(bcx, llindex, ccx.int_type())
|
||||
} else {
|
||||
llindex
|
||||
}
|
||||
}
|
||||
}
|
195
src/librustc_trans/trans/mir/mod.rs
Normal file
195
src/librustc_trans/trans/mir/mod.rs
Normal file
@ -0,0 +1,195 @@
|
||||
// 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 libc::c_uint;
|
||||
use llvm::{self, ValueRef};
|
||||
use rustc_mir::repr as mir;
|
||||
use rustc_mir::tcx::LvalueTy;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::{self, Block};
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::expr;
|
||||
use trans::type_of;
|
||||
|
||||
use self::lvalue::LvalueRef;
|
||||
use self::operand::OperandRef;
|
||||
|
||||
// FIXME DebugLoc is always None right now
|
||||
|
||||
/// Master context for translating MIR.
|
||||
pub struct MirContext<'bcx, 'tcx:'bcx> {
|
||||
mir: &'bcx mir::Mir<'tcx>,
|
||||
|
||||
/// When unwinding is initiated, we have to store this personality
|
||||
/// value somewhere so that we can load it and re-use it in the
|
||||
/// resume instruction. The personality is (afaik) some kind of
|
||||
/// value used for C++ unwinding, which must filter by type: we
|
||||
/// don't really care about it very much. Anyway, this value
|
||||
/// contains an alloca into which the personality is stored and
|
||||
/// then later loaded when generating the DIVERGE_BLOCK.
|
||||
llpersonalityslot: Option<ValueRef>,
|
||||
|
||||
/// A `Block` for each MIR `BasicBlock`
|
||||
blocks: Vec<Block<'bcx, 'tcx>>,
|
||||
|
||||
/// An LLVM alloca for each MIR `VarDecl`
|
||||
vars: Vec<LvalueRef<'tcx>>,
|
||||
|
||||
/// The location where each MIR `TempDecl` is stored. This is
|
||||
/// usually an `LvalueRef` representing an alloca, but not always:
|
||||
/// sometimes we can skip the alloca and just store the value
|
||||
/// directly using an `OperandRef`, which makes for tighter LLVM
|
||||
/// IR. The conditions for using an `OperandRef` are as follows:
|
||||
///
|
||||
/// - the type of the temporary must be judged "immediate" by `type_is_immediate`
|
||||
/// - the operand must never be referenced indirectly
|
||||
/// - we should not take its address using the `&` operator
|
||||
/// - nor should it appear in an lvalue path like `tmp.a`
|
||||
/// - the operand must be defined by an rvalue that can generate immediate
|
||||
/// values
|
||||
///
|
||||
/// Avoiding allocs can also be important for certain intrinsics,
|
||||
/// notably `expect`.
|
||||
temps: Vec<TempRef<'tcx>>,
|
||||
|
||||
/// The arguments to the function; as args are lvalues, these are
|
||||
/// always indirect, though we try to avoid creating an alloca
|
||||
/// when we can (and just reuse the pointer the caller provided).
|
||||
args: Vec<LvalueRef<'tcx>>,
|
||||
}
|
||||
|
||||
enum TempRef<'tcx> {
|
||||
Lvalue(LvalueRef<'tcx>),
|
||||
Operand(Option<OperandRef<'tcx>>),
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
|
||||
let fcx = bcx.fcx;
|
||||
let mir = bcx.mir();
|
||||
|
||||
let mir_blocks = bcx.mir().all_basic_blocks();
|
||||
|
||||
// Analyze the temps to determine which must be lvalues
|
||||
// FIXME
|
||||
let lvalue_temps = analyze::lvalue_temps(bcx, mir);
|
||||
|
||||
// Allocate variable and temp allocas
|
||||
let vars = mir.var_decls.iter()
|
||||
.map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
|
||||
.map(|(mty, name)| LvalueRef::alloca(bcx, mty, &name.as_str()))
|
||||
.collect();
|
||||
let temps = mir.temp_decls.iter()
|
||||
.map(|decl| bcx.monomorphize(&decl.ty))
|
||||
.enumerate()
|
||||
.map(|(i, mty)| if lvalue_temps.contains(&i) {
|
||||
TempRef::Lvalue(LvalueRef::alloca(bcx,
|
||||
mty,
|
||||
&format!("temp{:?}", i)))
|
||||
} else {
|
||||
// If this is an immediate temp, we do not create an
|
||||
// alloca in advance. Instead we wait until we see the
|
||||
// definition and update the operand there.
|
||||
TempRef::Operand(None)
|
||||
})
|
||||
.collect();
|
||||
let args = arg_value_refs(bcx, mir);
|
||||
|
||||
// Allocate a `Block` for every basic block
|
||||
let block_bcxs: Vec<Block<'bcx,'tcx>> =
|
||||
mir_blocks.iter()
|
||||
.map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None))
|
||||
.collect();
|
||||
|
||||
// Branch to the START block
|
||||
let start_bcx = block_bcxs[mir::START_BLOCK.index()];
|
||||
build::Br(bcx, start_bcx.llbb, DebugLoc::None);
|
||||
|
||||
let mut mircx = MirContext {
|
||||
mir: mir,
|
||||
llpersonalityslot: None,
|
||||
blocks: block_bcxs,
|
||||
vars: vars,
|
||||
temps: temps,
|
||||
args: args,
|
||||
};
|
||||
|
||||
// Translate the body of each block
|
||||
for &bb in &mir_blocks {
|
||||
if bb != mir::DIVERGE_BLOCK {
|
||||
mircx.trans_block(bb);
|
||||
}
|
||||
}
|
||||
|
||||
// Total hack: translate DIVERGE_BLOCK last. This is so that any
|
||||
// panics which the fn may do can initialize the
|
||||
// `llpersonalityslot` cell. We don't do this up front because the
|
||||
// LLVM type of it is (frankly) annoying to compute.
|
||||
mircx.trans_block(mir::DIVERGE_BLOCK);
|
||||
}
|
||||
|
||||
/// Produce, for each argument, a `ValueRef` pointing at the
|
||||
/// argument's value. As arguments are lvalues, these are always
|
||||
/// indirect.
|
||||
fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
|
||||
mir: &mir::Mir<'tcx>)
|
||||
-> Vec<LvalueRef<'tcx>> {
|
||||
// FIXME tupled_args? I think I'd rather that mapping is done in MIR land though
|
||||
let fcx = bcx.fcx;
|
||||
let tcx = bcx.tcx();
|
||||
let mut idx = fcx.arg_offset() as c_uint;
|
||||
mir.arg_decls
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(arg_index, arg_decl)| {
|
||||
let arg_ty = bcx.monomorphize(&arg_decl.ty);
|
||||
let llval = if type_of::arg_is_indirect(bcx.ccx(), arg_ty) {
|
||||
// Don't copy an indirect argument to an alloca, the caller
|
||||
// already put it in a temporary alloca and gave it up, unless
|
||||
// we emit extra-debug-info, which requires local allocas :(.
|
||||
// FIXME: lifetimes, debug info
|
||||
let llarg = llvm::get_param(fcx.llfn, idx);
|
||||
idx += 1;
|
||||
llarg
|
||||
} else if common::type_is_fat_ptr(tcx, arg_ty) {
|
||||
// we pass fat pointers as two words, but we want to
|
||||
// represent them internally as a pointer to two words,
|
||||
// so make an alloca to store them in.
|
||||
let lldata = llvm::get_param(fcx.llfn, idx);
|
||||
let llextra = llvm::get_param(fcx.llfn, idx + 1);
|
||||
idx += 2;
|
||||
let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
|
||||
build::Store(bcx, lldata, expr::get_dataptr(bcx, lltemp));
|
||||
build::Store(bcx, llextra, expr::get_dataptr(bcx, lltemp));
|
||||
lltemp
|
||||
} else {
|
||||
// otherwise, arg is passed by value, so make a
|
||||
// temporary and store it there
|
||||
let llarg = llvm::get_param(fcx.llfn, idx);
|
||||
idx += 1;
|
||||
let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
|
||||
build::Store(bcx, llarg, lltemp);
|
||||
lltemp
|
||||
};
|
||||
LvalueRef::new(llval, LvalueTy::from_ty(arg_ty))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
mod analyze;
|
||||
mod block;
|
||||
mod constant;
|
||||
mod lvalue;
|
||||
mod rvalue;
|
||||
mod operand;
|
||||
mod statement;
|
||||
|
110
src/librustc_trans/trans/mir/operand.rs
Normal file
110
src/librustc_trans/trans/mir/operand.rs
Normal file
@ -0,0 +1,110 @@
|
||||
// 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 llvm::ValueRef;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::Block;
|
||||
use trans::datum;
|
||||
|
||||
use super::{MirContext, TempRef};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct OperandRef<'tcx> {
|
||||
// This will be "indirect" if `appropriate_rvalue_mode` returns
|
||||
// ByRef, and otherwise ByValue.
|
||||
pub llval: ValueRef,
|
||||
|
||||
// The type of value being returned.
|
||||
pub ty: Ty<'tcx>
|
||||
}
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_operand(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
operand: &mir::Operand<'tcx>)
|
||||
-> OperandRef<'tcx>
|
||||
{
|
||||
debug!("trans_operand(operand={:?})", operand);
|
||||
|
||||
match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
// watch out for temporaries that do not have an
|
||||
// alloca; they are handled somewhat differently
|
||||
if let &mir::Lvalue::Temp(index) = lvalue {
|
||||
match self.temps[index as usize] {
|
||||
TempRef::Operand(Some(o)) => {
|
||||
return o;
|
||||
}
|
||||
TempRef::Operand(None) => {
|
||||
bcx.tcx().sess.bug(
|
||||
&format!("use of {:?} before def", lvalue));
|
||||
}
|
||||
TempRef::Lvalue(..) => {
|
||||
// use path below
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for most lvalues, to consume them we just load them
|
||||
// out from their home
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
||||
debug!("trans_operand: tr_lvalue={} @ {:?}",
|
||||
bcx.val_to_string(tr_lvalue.llval),
|
||||
ty);
|
||||
let llval = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
|
||||
datum::ByValue => build::Load(bcx, tr_lvalue.llval),
|
||||
datum::ByRef => tr_lvalue.llval,
|
||||
};
|
||||
OperandRef {
|
||||
llval: llval,
|
||||
ty: ty
|
||||
}
|
||||
}
|
||||
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
let llval = self.trans_constant(bcx, constant);
|
||||
let ty = bcx.monomorphize(&constant.ty);
|
||||
OperandRef {
|
||||
llval: llval,
|
||||
ty: ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_operand_into(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
lldest: ValueRef,
|
||||
operand: &mir::Operand<'tcx>)
|
||||
{
|
||||
debug!("trans_operand_into(lldest={}, operand={:?})",
|
||||
bcx.val_to_string(lldest),
|
||||
operand);
|
||||
|
||||
match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
let lvalue_ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
||||
debug!("trans_operand_into: tr_lvalue={} @ {:?}",
|
||||
bcx.val_to_string(tr_lvalue.llval),
|
||||
lvalue_ty);
|
||||
base::memcpy_ty(bcx, lldest, tr_lvalue.llval, lvalue_ty);
|
||||
}
|
||||
|
||||
mir::Operand::Constant(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
307
src/librustc_trans/trans/mir/rvalue.rs
Normal file
307
src/librustc_trans/trans/mir/rvalue.rs
Normal file
@ -0,0 +1,307 @@
|
||||
// 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 llvm::ValueRef;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc_front::hir;
|
||||
use rustc_mir::repr as mir;
|
||||
|
||||
use trans::asm;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::{self, Block, Result};
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::declare;
|
||||
use trans::expr;
|
||||
use trans::machine;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use trans::tvec;
|
||||
|
||||
use super::MirContext;
|
||||
use super::operand::OperandRef;
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_rvalue(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
lldest: ValueRef,
|
||||
rvalue: &mir::Rvalue<'tcx>)
|
||||
-> Block<'bcx, 'tcx>
|
||||
{
|
||||
debug!("trans_rvalue(lldest={}, rvalue={:?})",
|
||||
bcx.val_to_string(lldest),
|
||||
rvalue);
|
||||
|
||||
match *rvalue {
|
||||
mir::Rvalue::Use(ref operand) => {
|
||||
self.trans_operand_into(bcx, lldest, operand);
|
||||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::Cast(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mir::Rvalue::Repeat(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mir::Rvalue::Aggregate(_, ref operands) => {
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
// Note: perhaps this should be StructGep, but
|
||||
// note that in some cases the values here will
|
||||
// not be structs but arrays.
|
||||
let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
|
||||
self.trans_operand_into(bcx, lldest_i, operand);
|
||||
}
|
||||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::Slice { ref input, from_start, from_end } => {
|
||||
let ccx = bcx.ccx();
|
||||
let input = self.trans_lvalue(bcx, input);
|
||||
let (llbase, lllen) = tvec::get_base_and_len(bcx,
|
||||
input.llval,
|
||||
input.ty.to_ty(bcx.tcx()));
|
||||
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
|
||||
let adj = common::C_uint(ccx, from_start + from_end);
|
||||
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
|
||||
let lladdrdest = expr::get_dataptr(bcx, lldest);
|
||||
build::Store(bcx, llbase1, lladdrdest);
|
||||
let llmetadest = expr::get_meta(bcx, lldest);
|
||||
build::Store(bcx, lllen1, llmetadest);
|
||||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::InlineAsm(inline_asm) => {
|
||||
asm::trans_inline_asm(bcx, inline_asm)
|
||||
}
|
||||
|
||||
_ => {
|
||||
assert!(rvalue_creates_operand(rvalue));
|
||||
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
|
||||
build::Store(bcx, temp.llval, lldest);
|
||||
bcx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_rvalue_operand(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
rvalue: &mir::Rvalue<'tcx>)
|
||||
-> (Block<'bcx, 'tcx>, OperandRef<'tcx>)
|
||||
{
|
||||
assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
|
||||
|
||||
match *rvalue {
|
||||
mir::Rvalue::Use(ref operand) => {
|
||||
let operand = self.trans_operand(bcx, operand);
|
||||
(bcx, operand)
|
||||
}
|
||||
|
||||
mir::Rvalue::Cast(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mir::Rvalue::Ref(_, _, ref lvalue) => {
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
|
||||
// Note: lvalues are indirect, so storing the `llval` into the
|
||||
// destination effectively creates a reference.
|
||||
(bcx, OperandRef {
|
||||
llval: tr_lvalue.llval,
|
||||
ty: tr_lvalue.ty.to_ty(bcx.tcx()),
|
||||
})
|
||||
}
|
||||
|
||||
mir::Rvalue::Len(ref lvalue) => {
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
let (_, lllen) = tvec::get_base_and_len(bcx,
|
||||
tr_lvalue.llval,
|
||||
tr_lvalue.ty.to_ty(bcx.tcx()));
|
||||
(bcx, OperandRef {
|
||||
llval: lllen,
|
||||
ty: bcx.tcx().types.usize,
|
||||
})
|
||||
}
|
||||
|
||||
mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
||||
let lhs = self.trans_operand(bcx, lhs);
|
||||
let rhs = self.trans_operand(bcx, rhs);
|
||||
let is_float = lhs.ty.is_fp();
|
||||
let is_signed = lhs.ty.is_signed();
|
||||
let binop_debug_loc = DebugLoc::None;
|
||||
let llval = match op {
|
||||
mir::BinOp::Add => if is_float {
|
||||
build::FAdd(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else {
|
||||
build::Add(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
},
|
||||
mir::BinOp::Sub => if is_float {
|
||||
build::FSub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else {
|
||||
build::Sub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
},
|
||||
mir::BinOp::Mul => if is_float {
|
||||
build::FMul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else {
|
||||
build::Mul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
},
|
||||
mir::BinOp::Div => if is_float {
|
||||
build::FDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else if is_signed {
|
||||
build::SDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else {
|
||||
build::UDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
},
|
||||
mir::BinOp::Rem => if is_float {
|
||||
// LLVM currently always lowers the `frem` instructions appropriate
|
||||
// library calls typically found in libm. Notably f64 gets wired up
|
||||
// to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
|
||||
// us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
|
||||
// instead just an inline function in a header that goes up to a
|
||||
// f64, uses `fmod`, and then comes back down to a f32.
|
||||
//
|
||||
// Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
|
||||
// still unconditionally lower frem instructions over 32-bit floats
|
||||
// to a call to `fmodf`. To work around this we special case MSVC
|
||||
// 32-bit float rem instructions and instead do the call out to
|
||||
// `fmod` ourselves.
|
||||
//
|
||||
// Note that this is currently duplicated with src/libcore/ops.rs
|
||||
// which does the same thing, and it would be nice to perhaps unify
|
||||
// these two implementations one day! Also note that we call `fmod`
|
||||
// for both 32 and 64-bit floats because if we emit any FRem
|
||||
// instruction at all then LLVM is capable of optimizing it into a
|
||||
// 32-bit FRem (which we're trying to avoid).
|
||||
let tcx = bcx.tcx();
|
||||
let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
|
||||
tcx.sess.target.target.arch == "x86";
|
||||
if use_fmod {
|
||||
let f64t = Type::f64(bcx.ccx());
|
||||
let fty = Type::func(&[f64t, f64t], &f64t);
|
||||
let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
|
||||
tcx.types.f64);
|
||||
if lhs.ty == tcx.types.f32 {
|
||||
let lllhs = build::FPExt(bcx, lhs.llval, f64t);
|
||||
let llrhs = build::FPExt(bcx, rhs.llval, f64t);
|
||||
let llres = build::Call(bcx, llfn, &[lllhs, llrhs],
|
||||
None, binop_debug_loc);
|
||||
build::FPTrunc(bcx, llres, Type::f32(bcx.ccx()))
|
||||
} else {
|
||||
build::Call(bcx, llfn, &[lhs.llval, rhs.llval],
|
||||
None, binop_debug_loc)
|
||||
}
|
||||
} else {
|
||||
build::FRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
}
|
||||
} else if is_signed {
|
||||
build::SRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
} else {
|
||||
build::URem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
|
||||
},
|
||||
mir::BinOp::BitOr => build::Or(bcx, lhs.llval, rhs.llval, binop_debug_loc),
|
||||
mir::BinOp::BitAnd => build::And(bcx, lhs.llval, rhs.llval, binop_debug_loc),
|
||||
mir::BinOp::BitXor => build::Xor(bcx, lhs.llval, rhs.llval, binop_debug_loc),
|
||||
mir::BinOp::Shl => common::build_unchecked_lshift(bcx,
|
||||
lhs.llval,
|
||||
rhs.llval,
|
||||
binop_debug_loc),
|
||||
mir::BinOp::Shr => common::build_unchecked_rshift(bcx,
|
||||
lhs.ty,
|
||||
lhs.llval,
|
||||
rhs.llval,
|
||||
binop_debug_loc),
|
||||
mir::BinOp::Eq => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiEq, binop_debug_loc),
|
||||
mir::BinOp::Lt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiLt, binop_debug_loc),
|
||||
mir::BinOp::Le => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiLe, binop_debug_loc),
|
||||
mir::BinOp::Ne => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiNe, binop_debug_loc),
|
||||
mir::BinOp::Ge => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiGe, binop_debug_loc),
|
||||
mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
|
||||
hir::BiGt, binop_debug_loc),
|
||||
};
|
||||
(bcx, OperandRef {
|
||||
llval: llval,
|
||||
ty: lhs.ty,
|
||||
})
|
||||
}
|
||||
|
||||
mir::Rvalue::UnaryOp(op, ref operand) => {
|
||||
let operand = self.trans_operand(bcx, operand);
|
||||
let is_float = operand.ty.is_fp();
|
||||
let debug_loc = DebugLoc::None;
|
||||
let llval = match op {
|
||||
mir::UnOp::Not => build::Not(bcx, operand.llval, debug_loc),
|
||||
mir::UnOp::Neg => if is_float {
|
||||
build::FNeg(bcx, operand.llval, debug_loc)
|
||||
} else {
|
||||
build::Neg(bcx, operand.llval, debug_loc)
|
||||
}
|
||||
};
|
||||
(bcx, OperandRef {
|
||||
llval: llval,
|
||||
ty: operand.ty,
|
||||
})
|
||||
}
|
||||
|
||||
mir::Rvalue::Box(content_ty) => {
|
||||
let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
|
||||
let llty = type_of::type_of(bcx.ccx(), content_ty);
|
||||
let llsize = machine::llsize_of(bcx.ccx(), llty);
|
||||
let align = type_of::align_of(bcx.ccx(), content_ty);
|
||||
let llalign = common::C_uint(bcx.ccx(), align);
|
||||
let llty_ptr = llty.ptr_to();
|
||||
let box_ty = bcx.tcx().mk_box(content_ty);
|
||||
let Result { bcx, val: llval } = base::malloc_raw_dyn(bcx,
|
||||
llty_ptr,
|
||||
box_ty,
|
||||
llsize,
|
||||
llalign,
|
||||
DebugLoc::None);
|
||||
(bcx, OperandRef {
|
||||
llval: llval,
|
||||
ty: box_ty,
|
||||
})
|
||||
}
|
||||
|
||||
mir::Rvalue::Repeat(..) |
|
||||
mir::Rvalue::Aggregate(..) |
|
||||
mir::Rvalue::Slice { .. } |
|
||||
mir::Rvalue::InlineAsm(..) => {
|
||||
bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
|
||||
match *rvalue {
|
||||
mir::Rvalue::Use(..) | // (*)
|
||||
mir::Rvalue::Ref(..) |
|
||||
mir::Rvalue::Len(..) |
|
||||
mir::Rvalue::Cast(..) | // (*)
|
||||
mir::Rvalue::BinaryOp(..) |
|
||||
mir::Rvalue::UnaryOp(..) |
|
||||
mir::Rvalue::Box(..) =>
|
||||
true,
|
||||
mir::Rvalue::Repeat(..) |
|
||||
mir::Rvalue::Aggregate(..) |
|
||||
mir::Rvalue::Slice { .. } |
|
||||
mir::Rvalue::InlineAsm(..) =>
|
||||
false,
|
||||
}
|
||||
|
||||
// (*) this is only true if the type is suitable
|
||||
}
|
70
src/librustc_trans/trans/mir/statement.rs
Normal file
70
src/librustc_trans/trans/mir/statement.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// 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 rustc::middle::ty::LvaluePreference;
|
||||
use rustc_mir::repr as mir;
|
||||
use trans::common::Block;
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::glue;
|
||||
|
||||
use super::MirContext;
|
||||
use super::TempRef;
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_statement(&mut self,
|
||||
bcx: Block<'bcx, 'tcx>,
|
||||
statement: &mir::Statement<'tcx>)
|
||||
-> Block<'bcx, 'tcx> {
|
||||
debug!("trans_statement(statement={:?})", statement);
|
||||
|
||||
match statement.kind {
|
||||
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
|
||||
match *lvalue {
|
||||
mir::Lvalue::Temp(index) => {
|
||||
let index = index as usize;
|
||||
match self.temps[index as usize] {
|
||||
TempRef::Lvalue(tr_dest) => {
|
||||
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
|
||||
}
|
||||
TempRef::Operand(None) => {
|
||||
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
|
||||
self.temps[index] = TempRef::Operand(Some(operand));
|
||||
bcx
|
||||
}
|
||||
TempRef::Operand(Some(_)) => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
statement.span,
|
||||
&format!("operand {:?} already assigned", rvalue));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tr_dest = self.trans_lvalue(bcx, lvalue);
|
||||
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => {
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
||||
glue::drop_ty(bcx, tr_lvalue.llval, ty, DebugLoc::None)
|
||||
}
|
||||
|
||||
mir::StatementKind::Drop(mir::DropKind::Free, ref lvalue) => {
|
||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
||||
let content_ty = ty.builtin_deref(true, LvaluePreference::NoPreference);
|
||||
let content_ty = content_ty.unwrap().ty;
|
||||
glue::trans_exchange_free_ty(bcx, tr_lvalue.llval, content_ty, DebugLoc::None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ mod llrepr;
|
||||
mod machine;
|
||||
mod _match;
|
||||
mod meth;
|
||||
mod mir;
|
||||
mod monomorphize;
|
||||
mod tvec;
|
||||
mod type_;
|
||||
|
@ -164,11 +164,6 @@ pub struct Inherited<'a, 'tcx: 'a> {
|
||||
|
||||
tables: &'a RefCell<ty::Tables<'tcx>>,
|
||||
|
||||
// A mapping from each fn's id to its signature, with all bound
|
||||
// regions replaced with free ones. Unlike the other tables, this
|
||||
// one is never copied into the tcx: it is only used by regionck.
|
||||
fn_sig_map: RefCell<NodeMap<Vec<Ty<'tcx>>>>,
|
||||
|
||||
// When we process a call like `c()` where `c` is a closure type,
|
||||
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
|
||||
// `FnOnce` closure. In that case, we defer full resolution of the
|
||||
@ -314,7 +309,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), true),
|
||||
locals: RefCell::new(NodeMap()),
|
||||
tables: tables,
|
||||
fn_sig_map: RefCell::new(NodeMap()),
|
||||
deferred_call_resolutions: RefCell::new(DefIdMap()),
|
||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||
}
|
||||
@ -620,22 +614,13 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
|
||||
ccx: ccx
|
||||
};
|
||||
|
||||
// Remember return type so that regionck can access it later.
|
||||
let mut fn_sig_tys: Vec<Ty> =
|
||||
arg_tys.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if let ty::FnConverging(ret_ty) = ret_ty {
|
||||
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
|
||||
fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments
|
||||
}
|
||||
|
||||
debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
|
||||
fn_id,
|
||||
fn_sig_tys);
|
||||
debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
|
||||
|
||||
inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys);
|
||||
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
|
||||
|
||||
{
|
||||
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
|
||||
|
@ -284,19 +284,32 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
||||
// When we enter a function, we can derive
|
||||
debug!("visit_fn_body(id={})", id);
|
||||
|
||||
let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
|
||||
let fn_sig = match fn_sig_map.get(&id) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
self.tcx().sess.bug(
|
||||
&format!("No fn-sig entry for id={}", id));
|
||||
let fn_sig = {
|
||||
let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs;
|
||||
match fn_sig_map.get(&id) {
|
||||
Some(f) => f.clone(),
|
||||
None => {
|
||||
self.tcx().sess.bug(
|
||||
&format!("No fn-sig entry for id={}", id));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let old_region_bounds_pairs_len = self.region_bound_pairs.len();
|
||||
|
||||
// Collect the types from which we create inferred bounds.
|
||||
// For the return type, if diverging, substitute `bool` just
|
||||
// because it will have no effect.
|
||||
//
|
||||
// FIXME(#25759) return types should not be implied bounds
|
||||
let fn_sig_tys: Vec<_> =
|
||||
fn_sig.inputs.iter()
|
||||
.cloned()
|
||||
.chain(Some(fn_sig.output.unwrap_or(self.tcx().types.bool)))
|
||||
.collect();
|
||||
|
||||
let old_body_id = self.set_body_id(body.id);
|
||||
self.relate_free_regions(&fn_sig[..], body.id, span);
|
||||
self.relate_free_regions(&fn_sig_tys[..], body.id, span);
|
||||
link_fn_args(self,
|
||||
self.tcx().region_maps.node_extent(body.id),
|
||||
&fn_decl.inputs[..]);
|
||||
|
@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
|
||||
wbcx.visit_expr(e);
|
||||
wbcx.visit_upvar_borrow_map();
|
||||
wbcx.visit_closures();
|
||||
wbcx.visit_liberated_fn_sigs();
|
||||
}
|
||||
|
||||
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
|
||||
@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
|
||||
}
|
||||
wbcx.visit_upvar_borrow_map();
|
||||
wbcx.visit_closures();
|
||||
wbcx.visit_liberated_fn_sigs();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -361,6 +363,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_liberated_fn_sigs(&self) {
|
||||
for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
|
||||
let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
|
||||
self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
|
||||
t.fold_with(&mut Resolver::new(self.fcx, reason))
|
||||
}
|
||||
@ -376,6 +385,7 @@ enum ResolveReason {
|
||||
ResolvingPattern(Span),
|
||||
ResolvingUpvar(ty::UpvarId),
|
||||
ResolvingClosure(DefId),
|
||||
ResolvingFnSig(ast::NodeId),
|
||||
}
|
||||
|
||||
impl ResolveReason {
|
||||
@ -387,6 +397,9 @@ impl ResolveReason {
|
||||
ResolvingUpvar(upvar_id) => {
|
||||
tcx.expr_span(upvar_id.closure_expr_id)
|
||||
}
|
||||
ResolvingFnSig(id) => {
|
||||
tcx.map.span(id)
|
||||
}
|
||||
ResolvingClosure(did) => {
|
||||
if let Some(node_id) = tcx.map.as_local_node_id(did) {
|
||||
tcx.expr_span(node_id)
|
||||
@ -463,6 +476,16 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
span_err!(self.tcx.sess, span, E0196,
|
||||
"cannot determine a type for this closure")
|
||||
}
|
||||
|
||||
ResolvingFnSig(id) => {
|
||||
// any failures here should also fail when
|
||||
// resolving the patterns, closure types, or
|
||||
// something else.
|
||||
let span = self.reason.span(self.tcx);
|
||||
self.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!("cannot resolve some aspect of fn sig for {:?}", id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
&arenas,
|
||||
&name,
|
||||
resolve::MakeGlobMap::No,
|
||||
|tcx, analysis| {
|
||||
|tcx, _, analysis| {
|
||||
let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
|
||||
|
||||
// Convert from a NodeId set to a DefId set since we don't always have easy access
|
||||
|
@ -229,9 +229,9 @@ fn compile_program(input: &str, sysroot: PathBuf)
|
||||
let ast_map = driver::make_map(&sess, &mut hir_forest);
|
||||
|
||||
driver::phase_3_run_analysis_passes(
|
||||
&sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, analysis| {
|
||||
&sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| {
|
||||
|
||||
let trans = driver::phase_4_translate_to_llvm(tcx, analysis);
|
||||
let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis);
|
||||
|
||||
let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
|
||||
|
||||
|
24
src/test/run-pass/mir_trans_spike1.rs
Normal file
24
src/test/run-pass/mir_trans_spike1.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// A simple spike test for MIR version of trans.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn sum(x: i32, y: i32) -> i32 {
|
||||
x + y
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = sum(22, 44);
|
||||
assert_eq!(x, 66);
|
||||
println!("sum()={:?}", x);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user