about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-10-21 17:42:25 -0400
committerNiko Matsakis <niko@alum.mit.edu>2015-11-03 04:35:00 -0500
commit02017b30ebebfaeb64a5a86a885773f38057beba (patch)
treebc8d306b34f78fb084780c8adcf5fe8b37dbf2f0
parent877b93add2a0d7cc603fa3146a3b9b0af0215e9d (diff)
downloadrust-02017b30ebebfaeb64a5a86a885773f38057beba.tar.gz
rust-02017b30ebebfaeb64a5a86a885773f38057beba.zip
New trans codepath that builds fn body from MIR instead.
-rw-r--r--src/librustc_trans/trans/common.rs6
-rw-r--r--src/librustc_trans/trans/mir/block.rs106
-rw-r--r--src/librustc_trans/trans/mir/constant.rs63
-rw-r--r--src/librustc_trans/trans/mir/lvalue.rs149
-rw-r--r--src/librustc_trans/trans/mir/mod.rs162
-rw-r--r--src/librustc_trans/trans/mir/operand.rs90
-rw-r--r--src/librustc_trans/trans/mir/rvalue.rs238
-rw-r--r--src/librustc_trans/trans/mir/statement.rs48
-rw-r--r--src/librustc_trans/trans/mod.rs1
-rw-r--r--src/test/run-pass/mir_trans_spike1.rs24
10 files changed, 887 insertions, 0 deletions
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index b5f192b9727..8d6ba53dd22 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -743,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)
 }
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
new file mode 100644
index 00000000000..c9f4123c171
--- /dev/null
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -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
+    }
+}
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
new file mode 100644
index 00000000000..1b61001834a
--- /dev/null
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -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!()
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs
new file mode 100644
index 00000000000..282c6a7e6de
--- /dev/null
+++ b/src/librustc_trans/trans/mir/lvalue.rs
@@ -0,0 +1,149 @@
+// 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;
+
+#[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) => self.temps[index as usize],
+            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
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs
new file mode 100644
index 00000000000..6ed839d1a44
--- /dev/null
+++ b/src/librustc_trans/trans/mir/mod.rs
@@ -0,0 +1,162 @@
+// 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 std::cell::Cell;
+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;
+
+// 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>>,
+
+    /// An LLVM alloca for each MIR `TempDecl`
+    temps: Vec<LvalueRef<'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>>,
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+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();
+
+    // 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)| LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i)))
+                              .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 two 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 block;
+mod constant;
+mod lvalue;
+mod rvalue;
+mod operand;
+mod statement;
+
diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs
new file mode 100644
index 00000000000..786b84ae807
--- /dev/null
+++ b/src/librustc_trans/trans/mir/operand.rs
@@ -0,0 +1,90 @@
+// 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;
+
+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) => {
+                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!()
+            }
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs
new file mode 100644
index 00000000000..416aa061276
--- /dev/null
+++ b/src/librustc_trans/trans/mir/rvalue.rs
@@ -0,0 +1,238 @@
+// 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 back::abi;
+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::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::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.
+                build::Store(bcx, tr_lvalue.llval, lldest);
+                bcx
+            }
+
+            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()));
+                build::Store(bcx, lllen, lldest);
+                bcx
+            }
+
+            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 on 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),
+                };
+                build::Store(bcx, llval, lldest);
+                bcx
+            }
+
+            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)
+                    }
+                };
+                build::Store(bcx, llval, lldest);
+                bcx
+            }
+
+            mir::Rvalue::Box(content_ty) => {
+                let content_ty: Ty<'tcx> = 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);
+                build::Store(bcx, llval, lldest);
+                bcx
+            }
+
+            mir::Rvalue::Aggregate(_, ref operands) => {
+                for (i, operand) in operands.iter().enumerate() {
+                    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);
+                build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
+                build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
+                bcx
+            }
+
+            mir::Rvalue::InlineAsm(inline_asm) => {
+                asm::trans_inline_asm(bcx, inline_asm)
+            }
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs
new file mode 100644
index 00000000000..17a20fb817c
--- /dev/null
+++ b/src/librustc_trans/trans/mir/statement.rs
@@ -0,0 +1,48 @@
+// 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;
+
+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) => {
+                let tr_dest = self.trans_lvalue(bcx, lvalue);
+                self.trans_rvalue(bcx, tr_dest.llval, rvalue);
+                bcx
+            }
+
+            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)
+            }
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs
index 04854501312..fa37b005539 100644
--- a/src/librustc_trans/trans/mod.rs
+++ b/src/librustc_trans/trans/mod.rs
@@ -52,6 +52,7 @@ mod llrepr;
 mod machine;
 mod _match;
 mod meth;
+mod mir;
 mod monomorphize;
 mod tvec;
 mod type_;
diff --git a/src/test/run-pass/mir_trans_spike1.rs b/src/test/run-pass/mir_trans_spike1.rs
new file mode 100644
index 00000000000..9a06ab78e73
--- /dev/null
+++ b/src/test/run-pass/mir_trans_spike1.rs
@@ -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);
+}