1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use rustc::middle::ty::{self, Ty};
13 use rustc_mir::repr as mir;
14 use rustc_mir::tcx::LvalueTy;
18 use trans::common::{self, Block};
19 use trans::debuginfo::DebugLoc;
24 use super::{MirContext, TempRef};
26 #[derive(Copy, Clone)]
27 pub struct LvalueRef<'tcx> {
28 /// Pointer to the contents of the lvalue
31 /// This lvalue's extra data if it is unsized, or null
32 pub llextra: ValueRef,
34 /// Monomorphized type of this lvalue, including variant information
35 pub ty: LvalueTy<'tcx>,
38 impl<'tcx> LvalueRef<'tcx> {
39 pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
40 LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
43 pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
48 let lltemp = base::alloc_ty(bcx, ty, name);
49 LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
53 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
54 pub fn lvalue_len(&mut self,
55 bcx: Block<'bcx, 'tcx>,
56 lvalue: LvalueRef<'tcx>)
58 match lvalue.ty.to_ty(bcx.tcx()).sty {
59 ty::TyArray(_, n) => common::C_uint(bcx.ccx(), n),
60 ty::TySlice(_) | ty::TyStr => {
61 assert!(lvalue.llextra != ptr::null_mut());
64 _ => bcx.sess().bug("unexpected type in get_base_and_len"),
68 pub fn trans_lvalue(&mut self,
69 bcx: Block<'bcx, 'tcx>,
70 lvalue: &mir::Lvalue<'tcx>)
72 debug!("trans_lvalue(lvalue={:?})", lvalue);
78 mir::Lvalue::Var(index) => self.vars[index as usize],
79 mir::Lvalue::Temp(index) => match self.temps[index as usize] {
80 TempRef::Lvalue(lvalue) =>
82 TempRef::Operand(..) =>
83 tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
85 mir::Lvalue::Arg(index) => self.args[index as usize],
86 mir::Lvalue::Static(def_id) => {
87 let const_ty = self.mir.lvalue_ty(tcx, lvalue);
89 common::get_static_val(ccx, def_id, const_ty.to_ty(tcx)),
92 mir::Lvalue::ReturnPointer => {
93 let return_ty = bcx.monomorphize(&self.mir.return_ty);
94 let llval = fcx.get_ret_slot(bcx, return_ty, "return");
95 LvalueRef::new_sized(llval, LvalueTy::from_ty(return_ty.unwrap()))
97 mir::Lvalue::Projection(ref projection) => {
98 let tr_base = self.trans_lvalue(bcx, &projection.base);
99 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
100 let (llprojected, llextra) = match projection.elem {
101 mir::ProjectionElem::Deref => {
102 let base_ty = tr_base.ty.to_ty(tcx);
103 if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
104 (base::load_ty(bcx, tr_base.llval, base_ty),
107 base::load_fat_ptr(bcx, tr_base.llval, base_ty)
110 mir::ProjectionElem::Field(ref field) => {
111 let base_ty = tr_base.ty.to_ty(tcx);
112 let base_repr = adt::represent_type(ccx, base_ty);
113 let discr = match tr_base.ty {
114 LvalueTy::Ty { .. } => 0,
115 LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
117 let discr = discr as u64;
118 (adt::trans_field_ptr(bcx, &base_repr, tr_base.llval, discr, field.index()),
119 if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
125 mir::ProjectionElem::Index(ref index) => {
126 let index = self.trans_operand(bcx, index);
127 let llindex = self.prepare_index(bcx, index.immediate());
128 (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
131 mir::ProjectionElem::ConstantIndex { offset,
134 let lloffset = common::C_u32(bcx.ccx(), offset);
135 let llindex = self.prepare_index(bcx, lloffset);
136 (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
139 mir::ProjectionElem::ConstantIndex { offset,
142 let lloffset = common::C_u32(bcx.ccx(), offset);
143 let lllen = self.lvalue_len(bcx, tr_base);
144 let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
145 let llindex = self.prepare_index(bcx, llindex);
146 (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
149 mir::ProjectionElem::Downcast(..) => {
150 (tr_base.llval, tr_base.llextra)
162 /// Adjust the bitwidth of an index since LLVM is less forgiving
165 /// nmatsakis: is this still necessary? Not sure.
166 fn prepare_index(&mut self,
167 bcx: Block<'bcx, 'tcx>,
172 let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
173 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
174 if index_size < int_size {
175 build::ZExt(bcx, llindex, ccx.int_type())
176 } else if index_size > int_size {
177 build::Trunc(bcx, llindex, ccx.int_type())