Skip to content

Commit

Permalink
Refactor the MIR translator to use LLVM Builder directly
Browse files Browse the repository at this point in the history
  • Loading branch information
pczarn committed Feb 8, 2016
1 parent 8b77683 commit 06266eb
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 315 deletions.
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/base.rs
Expand Up @@ -2003,7 +2003,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let mut bcx = init_function(&fcx, false, output_type);

if attributes.iter().any(|item| item.check_name("rustc_mir")) {
mir::trans_mir(bcx);
mir::trans_mir(bcx.build());
fcx.cleanup();
return;
}
Expand Down
197 changes: 105 additions & 92 deletions src/librustc_trans/trans/mir/block.rs

Large diffs are not rendered by default.

15 changes: 9 additions & 6 deletions src/librustc_trans/trans/mir/constant.rs
Expand Up @@ -14,7 +14,8 @@ use middle::subst::Substs;
use middle::ty::{Ty, TypeFoldable};
use rustc::middle::const_eval::ConstVal;
use rustc::mir::repr as mir;
use trans::common::{self, Block, C_bool, C_bytes, C_floating_f64, C_integral, C_str_slice};
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
C_str_slice};
use trans::consts;
use trans::expr;
use trans::type_of;
Expand All @@ -25,13 +26,13 @@ use super::MirContext;

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_constval(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
cv: &ConstVal,
ty: Ty<'tcx>)
-> OperandRef<'tcx>
{
let ccx = bcx.ccx();
let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx.param_substs);
let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs);
let val = if common::type_is_immediate(ccx, ty) {
OperandValue::Immediate(val)
} else if common::type_is_fat_ptr(bcx.tcx(), ty) {
Expand All @@ -52,7 +53,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {

/// Translate ConstVal into a bare LLVM ValueRef.
fn trans_constval_inner(&mut self,
bcx: common::Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
cv: &ConstVal,
ty: Ty<'tcx>,
param_substs: &'tcx Substs<'tcx>)
Expand All @@ -70,15 +71,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
ConstVal::Struct(id) | ConstVal::Tuple(id) |
ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => {
let expr = bcx.tcx().map.expect_expr(id);
expr::trans(bcx, expr).datum.val
bcx.with_block(|bcx| {
expr::trans(bcx, expr).datum.val
})
},
ConstVal::Function(did) =>
self.trans_fn_ref(bcx, ty, param_substs, did).immediate()
}
}

pub fn trans_constant(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
constant: &mir::Constant<'tcx>)
-> OperandRef<'tcx>
{
Expand Down
12 changes: 7 additions & 5 deletions src/librustc_trans/trans/mir/did.rs
Expand Up @@ -18,7 +18,7 @@ use rustc::middle::const_eval;
use rustc::middle::def_id::DefId;
use rustc::middle::traits;
use rustc::mir::repr::ItemKind;
use trans::common::{Block, fulfill_obligation};
use trans::common::{BlockAndBuilder, fulfill_obligation};
use trans::base;
use trans::closure;
use trans::expr;
Expand All @@ -32,7 +32,7 @@ use super::operand::{OperandRef, OperandValue};
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
/// Translate reference to item.
pub fn trans_item_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
ty: Ty<'tcx>,
kind: ItemKind,
substs: &'tcx Substs<'tcx>,
Expand All @@ -53,7 +53,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
.expect("def was const, but lookup_const_by_id failed");
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
let d = expr::trans(bcx, expr);
let d = bcx.with_block(|bcx| {
expr::trans(bcx, expr)
});
OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
}
}
Expand All @@ -66,7 +68,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
///
/// This is an adaptation of callee::trans_fn_ref_with_substs.
pub fn trans_fn_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
ty: Ty<'tcx>,
substs: &'tcx Substs<'tcx>,
did: DefId)
Expand Down Expand Up @@ -101,7 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
///
/// This is an adaptation of meth::trans_static_method_callee
pub fn trans_trait_method(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
ty: Ty<'tcx>,
method_id: DefId,
trait_id: DefId,
Expand Down
63 changes: 34 additions & 29 deletions src/librustc_trans/trans/mir/lvalue.rs
Expand Up @@ -14,9 +14,7 @@ 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::common::{self, BlockAndBuilder};
use trans::machine;
use trans::type_of;
use llvm;
Expand All @@ -43,20 +41,20 @@ impl<'tcx> LvalueRef<'tcx> {
LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
}

pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
pub fn alloca<'bcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
ty: Ty<'tcx>,
name: &str)
-> LvalueRef<'tcx>
{
assert!(!ty.has_erasable_regions());
let lltemp = base::alloc_ty(bcx, ty, name);
let lltemp = bcx.with_block(|bcx| base::alloc_ty(bcx, ty, name));
LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
}
}

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn lvalue_len(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
lvalue: LvalueRef<'tcx>)
-> ValueRef {
match lvalue.ty.to_ty(bcx.tcx()).sty {
Expand All @@ -70,13 +68,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}

pub fn trans_lvalue(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
lvalue: &mir::Lvalue<'tcx>)
-> LvalueRef<'tcx> {
debug!("trans_lvalue(lvalue={:?})", lvalue);

let fcx = bcx.fcx;
let ccx = fcx.ccx;
let fcx = bcx.fcx();
let ccx = bcx.ccx();
let tcx = bcx.tcx();
match *lvalue {
mir::Lvalue::Var(index) => self.vars[index as usize],
Expand All @@ -97,7 +95,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let fn_return_ty = bcx.monomorphize(&self.mir.return_ty);
let return_ty = fn_return_ty.unwrap();
let llval = if !common::return_type_is_void(bcx.ccx(), return_ty) {
fcx.get_ret_slot(bcx, fn_return_ty, "")
bcx.with_block(|bcx| {
fcx.get_ret_slot(bcx, fn_return_ty, "")
})
} else {
// This is a void return; that is, there’s no place to store the value and
// there cannot really be one (or storing into it doesn’t make sense, anyway).
Expand All @@ -117,12 +117,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let (llprojected, llextra) = match projection.elem {
mir::ProjectionElem::Deref => {
let base_ty = tr_base.ty.to_ty(tcx);
if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
(base::load_ty(bcx, tr_base.llval, base_ty),
ptr::null_mut())
} else {
base::load_fat_ptr(bcx, tr_base.llval, base_ty)
}
bcx.with_block(|bcx| {
if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
(base::load_ty(bcx, tr_base.llval, base_ty),
ptr::null_mut())
} else {
base::load_fat_ptr(bcx, tr_base.llval, base_ty)
}
})
}
mir::ProjectionElem::Field(ref field) => {
let base_ty = tr_base.ty.to_ty(tcx);
Expand All @@ -138,18 +140,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
} else {
adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
};
(adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index()),
if is_sized {
ptr::null_mut()
} else {
tr_base.llextra
})
let llprojected = bcx.with_block(|bcx| {
adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index())
});
let llextra = if is_sized {
ptr::null_mut()
} else {
tr_base.llextra
};
(llprojected, llextra)
}
mir::ProjectionElem::Index(ref index) => {
let index = self.trans_operand(bcx, index);
let llindex = self.prepare_index(bcx, index.immediate());
let zero = common::C_uint(bcx.ccx(), 0u64);
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
(bcx.inbounds_gep(tr_base.llval, &[zero, llindex]),
ptr::null_mut())
}
mir::ProjectionElem::ConstantIndex { offset,
Expand All @@ -158,18 +163,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let lloffset = common::C_u32(bcx.ccx(), offset);
let llindex = self.prepare_index(bcx, lloffset);
let zero = common::C_uint(bcx.ccx(), 0u64);
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
(bcx.inbounds_gep(tr_base.llval, &[zero, llindex]),
ptr::null_mut())
}
mir::ProjectionElem::ConstantIndex { offset,
from_end: true,
min_length: _ } => {
let lloffset = common::C_u32(bcx.ccx(), offset);
let lllen = self.lvalue_len(bcx, tr_base);
let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
let llindex = bcx.sub(lllen, lloffset);
let llindex = self.prepare_index(bcx, llindex);
let zero = common::C_uint(bcx.ccx(), 0u64);
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
(bcx.inbounds_gep(tr_base.llval, &[zero, llindex]),
ptr::null_mut())
}
mir::ProjectionElem::Downcast(..) => {
Expand All @@ -190,17 +195,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
///
/// nmatsakis: is this still necessary? Not sure.
fn prepare_index(&mut self,
bcx: Block<'bcx, 'tcx>,
bcx: &BlockAndBuilder<'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())
bcx.zext(llindex, ccx.int_type())
} else if index_size > int_size {
build::Trunc(bcx, llindex, ccx.int_type())
bcx.trunc(llindex, ccx.int_type())
} else {
llindex
}
Expand Down
43 changes: 26 additions & 17 deletions src/librustc_trans/trans/mir/mod.rs
Expand Up @@ -13,9 +13,7 @@ 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, LandingPad};
use trans::debuginfo::DebugLoc;
use trans::common::{self, Block, BlockAndBuilder, LandingPad};
use trans::expr;
use trans::type_of;

Expand Down Expand Up @@ -79,26 +77,28 @@ enum TempRef<'tcx> {

///////////////////////////////////////////////////////////////////////////

pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
let fcx = bcx.fcx;
pub fn trans_mir<'bcx, 'tcx>(bcx: BlockAndBuilder<'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);
let lvalue_temps = bcx.with_block(|bcx| {
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()))
.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,
TempRef::Lvalue(LvalueRef::alloca(&bcx,
mty,
&format!("temp{:?}", i)))
} else {
Expand All @@ -108,7 +108,7 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
TempRef::Operand(None)
})
.collect();
let args = arg_value_refs(bcx, mir);
let args = arg_value_refs(&bcx, mir);

// Allocate a `Block` for every basic block
let block_bcxs: Vec<Block<'bcx,'tcx>> =
Expand All @@ -125,7 +125,7 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {

// Branch to the START block
let start_bcx = block_bcxs[mir::START_BLOCK.index()];
build::Br(bcx, start_bcx.llbb, DebugLoc::None);
bcx.br(start_bcx.llbb);

let mut mircx = MirContext {
mir: mir,
Expand All @@ -147,11 +147,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
/// 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>,
fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'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 fcx = bcx.fcx();
let tcx = bcx.tcx();
let mut idx = fcx.arg_offset() as c_uint;
mir.arg_decls
Expand All @@ -174,17 +174,26 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
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_meta(bcx, lltemp));
let lltemp = bcx.with_block(|bcx| {
base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
});
let (dataptr, meta) = bcx.with_block(|bcx| {
(expr::get_dataptr(bcx, lltemp), expr::get_meta(bcx, lltemp))
});
bcx.store(lldata, dataptr);
bcx.store(llextra, meta);
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));
base::store_ty(bcx, llarg, lltemp, arg_ty);
let lltemp = bcx.with_block(|bcx| {
base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
});
bcx.with_block(|bcx| {
base::store_ty(bcx, llarg, lltemp, arg_ty)
});
lltemp
};
LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty))
Expand Down

0 comments on commit 06266eb

Please sign in to comment.