2015-10-21 17:42:25 -04: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;
|
2016-03-22 17:30:57 +02:00
|
|
|
use rustc::ty::{self, Ty, TypeFoldable};
|
2015-11-19 16:37:34 +01:00
|
|
|
use rustc::mir::repr as mir;
|
|
|
|
use rustc::mir::tcx::LvalueTy;
|
2016-06-07 17:28:36 +03:00
|
|
|
use rustc_data_structures::indexed_vec::Idx;
|
2016-03-22 19:23:36 +02:00
|
|
|
use adt;
|
|
|
|
use base;
|
2016-05-07 22:59:03 +03:00
|
|
|
use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
|
2016-03-22 19:23:36 +02:00
|
|
|
use consts;
|
|
|
|
use machine;
|
2016-05-07 22:59:03 +03:00
|
|
|
use type_of::type_of;
|
2016-03-11 12:54:59 +02:00
|
|
|
use type_of;
|
2016-03-22 19:23:36 +02:00
|
|
|
use Disr;
|
2015-11-10 22:05:11 +02:00
|
|
|
|
|
|
|
use std::ptr;
|
2015-10-21 17:42:25 -04:00
|
|
|
|
2016-06-20 23:55:14 +03:00
|
|
|
use super::{MirContext, LocalRef};
|
2016-06-09 18:14:47 +03:00
|
|
|
use super::operand::OperandValue;
|
2015-10-21 17:42:25 -04:00
|
|
|
|
2016-03-11 12:54:59 +02:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2015-10-21 17:42:25 -04:00
|
|
|
pub struct LvalueRef<'tcx> {
|
|
|
|
/// Pointer to the contents of the lvalue
|
|
|
|
pub llval: ValueRef,
|
|
|
|
|
2015-11-10 22:05:11 +02:00
|
|
|
/// This lvalue's extra data if it is unsized, or null
|
|
|
|
pub llextra: ValueRef,
|
|
|
|
|
2015-10-21 17:42:25 -04:00
|
|
|
/// Monomorphized type of this lvalue, including variant information
|
|
|
|
pub ty: LvalueTy<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> LvalueRef<'tcx> {
|
2015-11-10 22:05:11 +02: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 17:42:25 -04:00
|
|
|
}
|
|
|
|
|
2016-02-01 11:04:46 +01:00
|
|
|
pub fn alloca<'bcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
2015-10-21 17:42:25 -04:00
|
|
|
ty: Ty<'tcx>,
|
|
|
|
name: &str)
|
|
|
|
-> LvalueRef<'tcx>
|
|
|
|
{
|
2015-11-16 18:41:16 +01:00
|
|
|
assert!(!ty.has_erasable_regions());
|
2016-02-01 11:04:46 +01:00
|
|
|
let lltemp = bcx.with_block(|bcx| base::alloc_ty(bcx, ty, name));
|
2015-11-10 22:05:11 +02:00
|
|
|
LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
|
|
|
let ty = self.ty.to_ty(ccx.tcx());
|
|
|
|
match ty.sty {
|
|
|
|
ty::TyArray(_, n) => common::C_uint(ccx, n),
|
|
|
|
ty::TySlice(_) | ty::TyStr => {
|
|
|
|
assert!(self.llextra != ptr::null_mut());
|
|
|
|
self.llextra
|
|
|
|
}
|
|
|
|
_ => bug!("unexpected type `{}` in LvalueRef::len", ty)
|
|
|
|
}
|
|
|
|
}
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|
|
|
pub fn trans_lvalue(&mut self,
|
2016-02-01 11:04:46 +01:00
|
|
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
2015-10-21 17:42:25 -04:00
|
|
|
lvalue: &mir::Lvalue<'tcx>)
|
|
|
|
-> LvalueRef<'tcx> {
|
|
|
|
debug!("trans_lvalue(lvalue={:?})", lvalue);
|
|
|
|
|
2016-02-01 11:04:46 +01:00
|
|
|
let ccx = bcx.ccx();
|
2015-10-21 17:42:25 -04:00
|
|
|
let tcx = bcx.tcx();
|
2016-06-20 23:55:14 +03:00
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
if let mir::Lvalue::Local(index) = *lvalue {
|
2016-06-20 23:55:14 +03:00
|
|
|
match self.locals[index] {
|
|
|
|
LocalRef::Lvalue(lvalue) => {
|
|
|
|
return lvalue;
|
|
|
|
}
|
|
|
|
LocalRef::Operand(..) => {
|
|
|
|
bug!("using operand local {:?} as lvalue", lvalue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-11 12:54:59 +02:00
|
|
|
let result = match *lvalue {
|
2016-09-25 01:38:27 +02:00
|
|
|
mir::Lvalue::Local(_) => bug!(), // handled above
|
2015-11-10 23:22:57 +02:00
|
|
|
mir::Lvalue::Static(def_id) => {
|
2016-08-05 15:59:51 -07:00
|
|
|
let const_ty = self.monomorphized_lvalue_ty(lvalue);
|
2016-08-16 17:41:38 +03:00
|
|
|
LvalueRef::new_sized(consts::get_static(ccx, def_id),
|
2016-06-05 19:03:30 +03:00
|
|
|
LvalueTy::from_ty(const_ty))
|
2015-11-10 23:22:57 +02:00
|
|
|
},
|
2016-06-09 18:14:47 +03:00
|
|
|
mir::Lvalue::Projection(box mir::Projection {
|
|
|
|
ref base,
|
|
|
|
elem: mir::ProjectionElem::Deref
|
|
|
|
}) => {
|
|
|
|
// Load the pointer from its location.
|
|
|
|
let ptr = self.trans_consume(bcx, base);
|
|
|
|
let projected_ty = LvalueTy::from_ty(ptr.ty)
|
|
|
|
.projection_ty(tcx, &mir::ProjectionElem::Deref);
|
|
|
|
let projected_ty = bcx.monomorphize(&projected_ty);
|
|
|
|
let (llptr, llextra) = match ptr.val {
|
|
|
|
OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
|
|
|
|
OperandValue::Pair(llptr, llextra) => (llptr, llextra),
|
|
|
|
OperandValue::Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
|
|
|
|
};
|
|
|
|
LvalueRef {
|
|
|
|
llval: llptr,
|
|
|
|
llextra: llextra,
|
|
|
|
ty: projected_ty,
|
|
|
|
}
|
|
|
|
}
|
2015-10-21 17:42:25 -04: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);
|
2016-03-08 14:11:45 +02:00
|
|
|
let projected_ty = bcx.monomorphize(&projected_ty);
|
2016-03-08 14:13:56 +02:00
|
|
|
|
|
|
|
let project_index = |llindex| {
|
|
|
|
let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty {
|
|
|
|
// Slices already point to the array element type.
|
|
|
|
bcx.inbounds_gep(tr_base.llval, &[llindex])
|
|
|
|
} else {
|
|
|
|
let zero = common::C_uint(bcx.ccx(), 0u64);
|
|
|
|
bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
|
|
|
|
};
|
2016-03-11 12:54:59 +02:00
|
|
|
element
|
2016-03-08 14:13:56 +02:00
|
|
|
};
|
|
|
|
|
2015-11-10 22:05:11 +02:00
|
|
|
let (llprojected, llextra) = match projection.elem {
|
2016-06-09 18:14:47 +03:00
|
|
|
mir::ProjectionElem::Deref => bug!(),
|
2016-02-11 18:31:42 +02:00
|
|
|
mir::ProjectionElem::Field(ref field, _) => {
|
2015-10-21 17:42:25 -04:00
|
|
|
let base_ty = tr_base.ty.to_ty(tcx);
|
|
|
|
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-07 02:38:29 +13: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-08-28 20:44:19 -04:00
|
|
|
let llprojected = adt::trans_field_ptr_builder(bcx, base_ty, base,
|
2016-03-09 14:20:22 +02:00
|
|
|
Disr(discr), field.index());
|
2016-02-01 11:04:46 +01:00
|
|
|
let llextra = if is_sized {
|
|
|
|
ptr::null_mut()
|
|
|
|
} else {
|
|
|
|
tr_base.llextra
|
|
|
|
};
|
|
|
|
(llprojected, llextra)
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
mir::ProjectionElem::Index(ref index) => {
|
|
|
|
let index = self.trans_operand(bcx, index);
|
2016-03-11 12:54:59 +02:00
|
|
|
(project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut())
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
mir::ProjectionElem::ConstantIndex { offset,
|
|
|
|
from_end: false,
|
|
|
|
min_length: _ } => {
|
2016-03-10 02:03:00 +02:00
|
|
|
let lloffset = C_uint(bcx.ccx(), offset);
|
2016-03-11 12:54:59 +02:00
|
|
|
(project_index(lloffset), ptr::null_mut())
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
mir::ProjectionElem::ConstantIndex { offset,
|
|
|
|
from_end: true,
|
|
|
|
min_length: _ } => {
|
2016-03-10 02:03:00 +02:00
|
|
|
let lloffset = C_uint(bcx.ccx(), offset);
|
2016-04-21 16:15:56 +03:00
|
|
|
let lllen = tr_base.len(bcx.ccx());
|
2016-02-01 11:04:46 +01:00
|
|
|
let llindex = bcx.sub(lllen, lloffset);
|
2016-03-11 12:54:59 +02:00
|
|
|
(project_index(llindex), ptr::null_mut())
|
|
|
|
}
|
|
|
|
mir::ProjectionElem::Subslice { from, to } => {
|
|
|
|
let llindex = C_uint(bcx.ccx(), from);
|
|
|
|
let llbase = project_index(llindex);
|
|
|
|
|
|
|
|
let base_ty = tr_base.ty.to_ty(bcx.tcx());
|
|
|
|
match base_ty.sty {
|
|
|
|
ty::TyArray(..) => {
|
|
|
|
// must cast the lvalue pointer type to the new
|
|
|
|
// array type (*[%_; new_len]).
|
2016-08-05 15:59:51 -07:00
|
|
|
let base_ty = self.monomorphized_lvalue_ty(lvalue);
|
2016-03-11 12:54:59 +02:00
|
|
|
let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
|
|
|
|
let llbase = bcx.pointercast(llbase, llbasety);
|
2016-06-06 00:20:15 +03:00
|
|
|
(llbase, ptr::null_mut())
|
2016-03-11 12:54:59 +02:00
|
|
|
}
|
|
|
|
ty::TySlice(..) => {
|
|
|
|
assert!(tr_base.llextra != ptr::null_mut());
|
|
|
|
let lllen = bcx.sub(tr_base.llextra,
|
|
|
|
C_uint(bcx.ccx(), from+to));
|
|
|
|
(llbase, lllen)
|
|
|
|
}
|
|
|
|
_ => bug!("unexpected type {:?} in Subslice", base_ty)
|
|
|
|
}
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
mir::ProjectionElem::Downcast(..) => {
|
2015-11-10 22:05:11 +02:00
|
|
|
(tr_base.llval, tr_base.llextra)
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
LvalueRef {
|
|
|
|
llval: llprojected,
|
2015-11-10 22:05:11 +02:00
|
|
|
llextra: llextra,
|
2015-10-21 17:42:25 -04:00
|
|
|
ty: projected_ty,
|
|
|
|
}
|
|
|
|
}
|
2016-03-11 12:54:59 +02:00
|
|
|
};
|
|
|
|
debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
|
|
|
|
result
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
|
2016-04-04 19:21:27 +12:00
|
|
|
// Perform an action using the given Lvalue.
|
2016-06-20 23:55:14 +03:00
|
|
|
// If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
|
2016-04-04 19:21:27 +12:00
|
|
|
// is created first, then used as an operand to update the Lvalue.
|
|
|
|
pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
|
|
|
lvalue: &mir::Lvalue<'tcx>, f: F) -> U
|
|
|
|
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
|
|
|
|
{
|
2016-09-25 01:38:27 +02:00
|
|
|
if let mir::Lvalue::Local(index) = *lvalue {
|
2016-06-20 23:55:14 +03:00
|
|
|
match self.locals[index] {
|
|
|
|
LocalRef::Lvalue(lvalue) => f(self, lvalue),
|
|
|
|
LocalRef::Operand(None) => {
|
2016-08-05 15:59:51 -07:00
|
|
|
let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
|
2016-06-20 23:55:14 +03:00
|
|
|
let lvalue = LvalueRef::alloca(bcx,
|
|
|
|
lvalue_ty,
|
|
|
|
"lvalue_temp");
|
|
|
|
let ret = f(self, lvalue);
|
|
|
|
let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
|
|
|
|
self.locals[index] = LocalRef::Operand(Some(op));
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
LocalRef::Operand(Some(_)) => {
|
|
|
|
// See comments in LocalRef::new_operand as to why
|
|
|
|
// we always have Some in a ZST LocalRef::Operand.
|
2016-08-05 15:59:51 -07:00
|
|
|
let ty = self.monomorphized_lvalue_ty(lvalue);
|
2016-06-20 23:55:14 +03:00
|
|
|
if common::type_is_zero_size(bcx.ccx(), ty) {
|
|
|
|
// Pass an undef pointer as no stores can actually occur.
|
|
|
|
let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to());
|
|
|
|
f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
|
|
|
|
} else {
|
|
|
|
bug!("Lvalue local already set");
|
2016-04-04 19:21:27 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-20 23:55:14 +03:00
|
|
|
} else {
|
|
|
|
let lvalue = self.trans_lvalue(bcx, lvalue);
|
|
|
|
f(self, lvalue)
|
2016-04-04 19:21:27 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 17:42:25 -04:00
|
|
|
/// 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,
|
2016-02-01 11:04:46 +01:00
|
|
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
2015-10-21 17:42:25 -04:00
|
|
|
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 {
|
2016-02-01 11:04:46 +01:00
|
|
|
bcx.zext(llindex, ccx.int_type())
|
2015-10-21 17:42:25 -04:00
|
|
|
} else if index_size > int_size {
|
2016-02-01 11:04:46 +01:00
|
|
|
bcx.trunc(llindex, ccx.int_type())
|
2015-10-21 17:42:25 -04:00
|
|
|
} else {
|
|
|
|
llindex
|
|
|
|
}
|
|
|
|
}
|
2016-06-05 19:03:30 +03:00
|
|
|
|
2016-08-05 15:59:51 -07:00
|
|
|
pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
|
2016-06-05 19:03:30 +03:00
|
|
|
let tcx = self.fcx.ccx.tcx();
|
2016-08-05 15:59:51 -07:00
|
|
|
let lvalue_ty = lvalue.ty(&self.mir, tcx);
|
2016-06-05 19:03:30 +03:00
|
|
|
self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
|
|
|
|
}
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|