]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/lvalue.rs
Changed issue number to 36105
[rust.git] / src / librustc_trans / mir / lvalue.rs
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.
4 //
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.
10
11 use llvm::ValueRef;
12 use rustc::ty::{self, Ty, TypeFoldable};
13 use rustc::mir::repr as mir;
14 use rustc::mir::tcx::LvalueTy;
15 use rustc_data_structures::indexed_vec::Idx;
16 use abi;
17 use adt;
18 use base;
19 use builder::Builder;
20 use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
21 use consts;
22 use machine;
23 use type_of::type_of;
24 use type_of;
25 use Disr;
26
27 use std::ptr;
28
29 use super::{MirContext, LocalRef};
30 use super::operand::OperandValue;
31
32 #[derive(Copy, Clone, Debug)]
33 pub struct LvalueRef<'tcx> {
34     /// Pointer to the contents of the lvalue
35     pub llval: ValueRef,
36
37     /// This lvalue's extra data if it is unsized, or null
38     pub llextra: ValueRef,
39
40     /// Monomorphized type of this lvalue, including variant information
41     pub ty: LvalueTy<'tcx>,
42 }
43
44 impl<'tcx> LvalueRef<'tcx> {
45     pub fn new_sized(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
46         LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
47     }
48
49     pub fn alloca<'bcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
50                         ty: Ty<'tcx>,
51                         name: &str)
52                         -> LvalueRef<'tcx>
53     {
54         assert!(!ty.has_erasable_regions());
55         let lltemp = bcx.with_block(|bcx| base::alloc_ty(bcx, ty, name));
56         LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
57     }
58
59     pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
60         let ty = self.ty.to_ty(ccx.tcx());
61         match ty.sty {
62             ty::TyArray(_, n) => common::C_uint(ccx, n),
63             ty::TySlice(_) | ty::TyStr => {
64                 assert!(self.llextra != ptr::null_mut());
65                 self.llextra
66             }
67             _ => bug!("unexpected type `{}` in LvalueRef::len", ty)
68         }
69     }
70 }
71
72 pub fn get_meta(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
73     b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
74 }
75
76 pub fn get_dataptr(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
77     b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
78 }
79
80 pub fn load_fat_ptr(b: &Builder, fat_ptr: ValueRef) -> (ValueRef, ValueRef) {
81     (b.load(get_dataptr(b, fat_ptr)), b.load(get_meta(b, fat_ptr)))
82 }
83
84 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
85     pub fn trans_lvalue(&mut self,
86                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
87                         lvalue: &mir::Lvalue<'tcx>)
88                         -> LvalueRef<'tcx> {
89         debug!("trans_lvalue(lvalue={:?})", lvalue);
90
91         let ccx = bcx.ccx();
92         let tcx = bcx.tcx();
93
94         if let Some(index) = self.mir.local_index(lvalue) {
95             match self.locals[index] {
96                 LocalRef::Lvalue(lvalue) => {
97                     return lvalue;
98                 }
99                 LocalRef::Operand(..) => {
100                     bug!("using operand local {:?} as lvalue", lvalue);
101                 }
102             }
103         }
104
105         let result = match *lvalue {
106             mir::Lvalue::Var(_) |
107             mir::Lvalue::Temp(_) |
108             mir::Lvalue::Arg(_) |
109             mir::Lvalue::ReturnPointer => bug!(), // handled above
110             mir::Lvalue::Static(def_id) => {
111                 let const_ty = self.monomorphized_lvalue_ty(lvalue);
112                 LvalueRef::new_sized(consts::get_static(ccx, def_id).val,
113                                      LvalueTy::from_ty(const_ty))
114             },
115             mir::Lvalue::Projection(box mir::Projection {
116                 ref base,
117                 elem: mir::ProjectionElem::Deref
118             }) => {
119                 // Load the pointer from its location.
120                 let ptr = self.trans_consume(bcx, base);
121                 let projected_ty = LvalueTy::from_ty(ptr.ty)
122                     .projection_ty(tcx, &mir::ProjectionElem::Deref);
123                 let projected_ty = bcx.monomorphize(&projected_ty);
124                 let (llptr, llextra) = match ptr.val {
125                     OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
126                     OperandValue::Pair(llptr, llextra) => (llptr, llextra),
127                     OperandValue::Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
128                 };
129                 LvalueRef {
130                     llval: llptr,
131                     llextra: llextra,
132                     ty: projected_ty,
133                 }
134             }
135             mir::Lvalue::Projection(ref projection) => {
136                 let tr_base = self.trans_lvalue(bcx, &projection.base);
137                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
138                 let projected_ty = bcx.monomorphize(&projected_ty);
139
140                 let project_index = |llindex| {
141                     let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty {
142                         // Slices already point to the array element type.
143                         bcx.inbounds_gep(tr_base.llval, &[llindex])
144                     } else {
145                         let zero = common::C_uint(bcx.ccx(), 0u64);
146                         bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
147                     };
148                     element
149                 };
150
151                 let (llprojected, llextra) = match projection.elem {
152                     mir::ProjectionElem::Deref => bug!(),
153                     mir::ProjectionElem::Field(ref field, _) => {
154                         let base_ty = tr_base.ty.to_ty(tcx);
155                         let base_repr = adt::represent_type(ccx, base_ty);
156                         let discr = match tr_base.ty {
157                             LvalueTy::Ty { .. } => 0,
158                             LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
159                         };
160                         let discr = discr as u64;
161                         let is_sized = common::type_is_sized(tcx, projected_ty.to_ty(tcx));
162                         let base = if is_sized {
163                             adt::MaybeSizedValue::sized(tr_base.llval)
164                         } else {
165                             adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
166                         };
167                         let llprojected = adt::trans_field_ptr_builder(bcx, &base_repr, base,
168                                                                        Disr(discr), field.index());
169                         let llextra = if is_sized {
170                             ptr::null_mut()
171                         } else {
172                             tr_base.llextra
173                         };
174                         (llprojected, llextra)
175                     }
176                     mir::ProjectionElem::Index(ref index) => {
177                         let index = self.trans_operand(bcx, index);
178                         (project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut())
179                     }
180                     mir::ProjectionElem::ConstantIndex { offset,
181                                                          from_end: false,
182                                                          min_length: _ } => {
183                         let lloffset = C_uint(bcx.ccx(), offset);
184                         (project_index(lloffset), ptr::null_mut())
185                     }
186                     mir::ProjectionElem::ConstantIndex { offset,
187                                                          from_end: true,
188                                                          min_length: _ } => {
189                         let lloffset = C_uint(bcx.ccx(), offset);
190                         let lllen = tr_base.len(bcx.ccx());
191                         let llindex = bcx.sub(lllen, lloffset);
192                         (project_index(llindex), ptr::null_mut())
193                     }
194                     mir::ProjectionElem::Subslice { from, to } => {
195                         let llindex = C_uint(bcx.ccx(), from);
196                         let llbase = project_index(llindex);
197
198                         let base_ty = tr_base.ty.to_ty(bcx.tcx());
199                         match base_ty.sty {
200                             ty::TyArray(..) => {
201                                 // must cast the lvalue pointer type to the new
202                                 // array type (*[%_; new_len]).
203                                 let base_ty = self.monomorphized_lvalue_ty(lvalue);
204                                 let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
205                                 let llbase = bcx.pointercast(llbase, llbasety);
206                                 (llbase, ptr::null_mut())
207                             }
208                             ty::TySlice(..) => {
209                                 assert!(tr_base.llextra != ptr::null_mut());
210                                 let lllen = bcx.sub(tr_base.llextra,
211                                                     C_uint(bcx.ccx(), from+to));
212                                 (llbase, lllen)
213                             }
214                             _ => bug!("unexpected type {:?} in Subslice", base_ty)
215                         }
216                     }
217                     mir::ProjectionElem::Downcast(..) => {
218                         (tr_base.llval, tr_base.llextra)
219                     }
220                 };
221                 LvalueRef {
222                     llval: llprojected,
223                     llextra: llextra,
224                     ty: projected_ty,
225                 }
226             }
227         };
228         debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
229         result
230     }
231
232     // Perform an action using the given Lvalue.
233     // If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
234     // is created first, then used as an operand to update the Lvalue.
235     pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
236                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
237     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
238     {
239         if let Some(index) = self.mir.local_index(lvalue) {
240             match self.locals[index] {
241                 LocalRef::Lvalue(lvalue) => f(self, lvalue),
242                 LocalRef::Operand(None) => {
243                     let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
244                     let lvalue = LvalueRef::alloca(bcx,
245                                                    lvalue_ty,
246                                                    "lvalue_temp");
247                     let ret = f(self, lvalue);
248                     let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
249                     self.locals[index] = LocalRef::Operand(Some(op));
250                     ret
251                 }
252                 LocalRef::Operand(Some(_)) => {
253                     // See comments in LocalRef::new_operand as to why
254                     // we always have Some in a ZST LocalRef::Operand.
255                     let ty = self.monomorphized_lvalue_ty(lvalue);
256                     if common::type_is_zero_size(bcx.ccx(), ty) {
257                         // Pass an undef pointer as no stores can actually occur.
258                         let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to());
259                         f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
260                     } else {
261                         bug!("Lvalue local already set");
262                     }
263                 }
264             }
265         } else {
266             let lvalue = self.trans_lvalue(bcx, lvalue);
267             f(self, lvalue)
268         }
269     }
270
271     /// Adjust the bitwidth of an index since LLVM is less forgiving
272     /// than we are.
273     ///
274     /// nmatsakis: is this still necessary? Not sure.
275     fn prepare_index(&mut self,
276                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
277                      llindex: ValueRef)
278                      -> ValueRef
279     {
280         let ccx = bcx.ccx();
281         let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
282         let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
283         if index_size < int_size {
284             bcx.zext(llindex, ccx.int_type())
285         } else if index_size > int_size {
286             bcx.trunc(llindex, ccx.int_type())
287         } else {
288             llindex
289         }
290     }
291
292     pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
293         let tcx = self.fcx.ccx.tcx();
294         let lvalue_ty = lvalue.ty(&self.mir, tcx);
295         self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
296     }
297 }