mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
New trans codepath that builds fn body from MIR instead.
This commit is contained in:
parent
877b93add2
commit
02017b30eb
@ -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)
|
||||
}
|
||||
|
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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
149
src/librustc_trans/trans/mir/lvalue.rs
Normal file
149
src/librustc_trans/trans/mir/lvalue.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
162
src/librustc_trans/trans/mir/mod.rs
Normal file
162
src/librustc_trans/trans/mir/mod.rs
Normal file
@ -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;
|
||||
|
90
src/librustc_trans/trans/mir/operand.rs
Normal file
90
src/librustc_trans/trans/mir/operand.rs
Normal file
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
238
src/librustc_trans/trans/mir/rvalue.rs
Normal file
238
src/librustc_trans/trans/mir/rvalue.rs
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
src/librustc_trans/trans/mir/statement.rs
Normal file
48
src/librustc_trans/trans/mir/statement.rs
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ mod llrepr;
|
||||
mod machine;
|
||||
mod _match;
|
||||
mod meth;
|
||||
mod mir;
|
||||
mod monomorphize;
|
||||
mod tvec;
|
||||
mod type_;
|
||||
|
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…
Reference in New Issue
Block a user