2015-10-21 16:42:25 -05:00
|
|
|
|
// 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;
|
2015-12-18 04:07:06 -06:00
|
|
|
|
use rustc::middle::ty::{self, Ty, TypeFoldable};
|
2015-11-19 09:37:34 -06:00
|
|
|
|
use rustc::mir::repr as mir;
|
|
|
|
|
use rustc::mir::tcx::LvalueTy;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
use trans::adt;
|
|
|
|
|
use trans::base;
|
|
|
|
|
use trans::build;
|
|
|
|
|
use trans::common::{self, Block};
|
|
|
|
|
use trans::debuginfo::DebugLoc;
|
|
|
|
|
use trans::machine;
|
2015-12-19 08:51:52 -06:00
|
|
|
|
use trans::type_of;
|
|
|
|
|
use llvm;
|
2016-01-16 09:03:09 -06:00
|
|
|
|
use trans::Disr;
|
2015-11-10 14:05:11 -06:00
|
|
|
|
|
|
|
|
|
use std::ptr;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
2015-11-02 08:39:59 -06:00
|
|
|
|
use super::{MirContext, TempRef};
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct LvalueRef<'tcx> {
|
|
|
|
|
/// Pointer to the contents of the lvalue
|
|
|
|
|
pub llval: ValueRef,
|
|
|
|
|
|
2015-11-10 14:05:11 -06:00
|
|
|
|
/// This lvalue's extra data if it is unsized, or null
|
|
|
|
|
pub llextra: ValueRef,
|
|
|
|
|
|
2015-10-21 16:42:25 -05:00
|
|
|
|
/// Monomorphized type of this lvalue, including variant information
|
|
|
|
|
pub ty: LvalueTy<'tcx>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'tcx> LvalueRef<'tcx> {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
|
|
|
|
|
LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
|
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
|
name: &str)
|
|
|
|
|
-> LvalueRef<'tcx>
|
|
|
|
|
{
|
2015-11-16 11:41:16 -06:00
|
|
|
|
assert!(!ty.has_erasable_regions());
|
2015-10-21 16:42:25 -05:00
|
|
|
|
let lltemp = base::alloc_ty(bcx, ty, name);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
pub fn lvalue_len(&mut self,
|
2015-11-10 14:26:59 -06:00
|
|
|
|
bcx: Block<'bcx, 'tcx>,
|
|
|
|
|
lvalue: LvalueRef<'tcx>)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
-> ValueRef {
|
2015-11-10 14:26:59 -06:00
|
|
|
|
match lvalue.ty.to_ty(bcx.tcx()).sty {
|
|
|
|
|
ty::TyArray(_, n) => common::C_uint(bcx.ccx(), n),
|
|
|
|
|
ty::TySlice(_) | ty::TyStr => {
|
|
|
|
|
assert!(lvalue.llextra != ptr::null_mut());
|
|
|
|
|
lvalue.llextra
|
|
|
|
|
}
|
2016-01-30 11:32:50 -06:00
|
|
|
|
_ => bcx.sess().bug("unexpected type in lvalue_len"),
|
2015-11-10 14:26:59 -06:00
|
|
|
|
}
|
2015-11-10 14:05:11 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:42:25 -05:00
|
|
|
|
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],
|
2015-11-02 08:39:59 -06:00
|
|
|
|
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)),
|
|
|
|
|
},
|
2015-10-21 16:42:25 -05:00
|
|
|
|
mir::Lvalue::Arg(index) => self.args[index as usize],
|
2015-11-10 15:22:57 -06:00
|
|
|
|
mir::Lvalue::Static(def_id) => {
|
|
|
|
|
let const_ty = self.mir.lvalue_ty(tcx, lvalue);
|
2015-11-11 14:02:51 -06:00
|
|
|
|
LvalueRef::new_sized(
|
|
|
|
|
common::get_static_val(ccx, def_id, const_ty.to_ty(tcx)),
|
|
|
|
|
const_ty)
|
2015-11-10 15:22:57 -06:00
|
|
|
|
},
|
2015-10-21 16:42:25 -05:00
|
|
|
|
mir::Lvalue::ReturnPointer => {
|
2015-12-19 08:51:52 -06:00
|
|
|
|
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, "")
|
|
|
|
|
} 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).
|
|
|
|
|
// Ergo, we return an undef ValueRef, so we do not have to special-case every
|
|
|
|
|
// place using lvalues, and could use it the same way you use a regular
|
|
|
|
|
// ReturnPointer LValue (i.e. store into it, load from it etc).
|
|
|
|
|
let llty = type_of::type_of(bcx.ccx(), return_ty).ptr_to();
|
|
|
|
|
unsafe {
|
|
|
|
|
llvm::LLVMGetUndef(llty.to_ref())
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
LvalueRef::new_sized(llval, LvalueTy::from_ty(return_ty))
|
|
|
|
|
},
|
2015-10-21 16:42:25 -05:00
|
|
|
|
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);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let (llprojected, llextra) = match projection.elem {
|
2015-10-21 16:42:25 -05:00
|
|
|
|
mir::ProjectionElem::Deref => {
|
|
|
|
|
let base_ty = tr_base.ty.to_ty(tcx);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
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)
|
|
|
|
|
}
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
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;
|
2015-12-06 07:38:29 -06:00
|
|
|
|
let is_sized = common::type_is_sized(tcx, projected_ty.to_ty(tcx));
|
|
|
|
|
let base = if is_sized {
|
|
|
|
|
adt::MaybeSizedValue::sized(tr_base.llval)
|
|
|
|
|
} else {
|
|
|
|
|
adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
|
|
|
|
|
};
|
2016-01-16 09:03:09 -06:00
|
|
|
|
(adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index()),
|
2015-12-06 07:38:29 -06:00
|
|
|
|
if is_sized {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
ptr::null_mut()
|
|
|
|
|
} else {
|
|
|
|
|
tr_base.llextra
|
|
|
|
|
})
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
mir::ProjectionElem::Index(ref index) => {
|
|
|
|
|
let index = self.trans_operand(bcx, index);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let llindex = self.prepare_index(bcx, index.immediate());
|
2015-12-19 12:28:12 -06:00
|
|
|
|
let zero = common::C_uint(bcx.ccx(), 0u64);
|
|
|
|
|
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
|
2015-11-10 14:05:11 -06:00
|
|
|
|
ptr::null_mut())
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
mir::ProjectionElem::ConstantIndex { offset,
|
|
|
|
|
from_end: false,
|
|
|
|
|
min_length: _ } => {
|
|
|
|
|
let lloffset = common::C_u32(bcx.ccx(), offset);
|
|
|
|
|
let llindex = self.prepare_index(bcx, lloffset);
|
2015-12-19 12:28:12 -06:00
|
|
|
|
let zero = common::C_uint(bcx.ccx(), 0u64);
|
|
|
|
|
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
|
2015-11-10 14:05:11 -06:00
|
|
|
|
ptr::null_mut())
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
mir::ProjectionElem::ConstantIndex { offset,
|
|
|
|
|
from_end: true,
|
|
|
|
|
min_length: _ } => {
|
|
|
|
|
let lloffset = common::C_u32(bcx.ccx(), offset);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let lllen = self.lvalue_len(bcx, tr_base);
|
2015-10-21 16:42:25 -05:00
|
|
|
|
let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
|
|
|
|
|
let llindex = self.prepare_index(bcx, llindex);
|
2015-12-19 12:28:12 -06:00
|
|
|
|
let zero = common::C_uint(bcx.ccx(), 0u64);
|
|
|
|
|
(build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]),
|
2015-11-10 14:05:11 -06:00
|
|
|
|
ptr::null_mut())
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
mir::ProjectionElem::Downcast(..) => {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
(tr_base.llval, tr_base.llextra)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
LvalueRef {
|
|
|
|
|
llval: llprojected,
|
2015-11-10 14:05:11 -06:00
|
|
|
|
llextra: llextra,
|
2015-10-21 16:42:25 -05:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|