]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/lvalue.rs
Unignore u128 test for stage 0,1
[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, layout, Ty, TypeFoldable};
13 use rustc::mir;
14 use rustc::mir::tcx::LvalueTy;
15 use rustc_data_structures::indexed_vec::Idx;
16 use adt;
17 use builder::Builder;
18 use common::{self, CrateContext, C_uint, C_undef};
19 use consts;
20 use machine;
21 use type_of::type_of;
22 use type_of;
23 use type_::Type;
24 use value::Value;
25 use glue;
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<'a, '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 new_sized_ty(llval: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
50         LvalueRef::new_sized(llval, LvalueTy::from_ty(ty))
51     }
52
53     pub fn new_unsized_ty(llval: ValueRef, llextra: ValueRef, ty: Ty<'tcx>) -> LvalueRef<'tcx> {
54         LvalueRef {
55             llval: llval,
56             llextra: llextra,
57             ty: LvalueTy::from_ty(ty),
58         }
59     }
60
61     pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
62         let ty = self.ty.to_ty(ccx.tcx());
63         match ty.sty {
64             ty::TyArray(_, n) => common::C_uint(ccx, n),
65             ty::TySlice(_) | ty::TyStr => {
66                 assert!(self.llextra != ptr::null_mut());
67                 self.llextra
68             }
69             _ => bug!("unexpected type `{}` in LvalueRef::len", ty)
70         }
71     }
72
73     pub fn has_extra(&self) -> bool {
74         !self.llextra.is_null()
75     }
76
77     fn struct_field_ptr(
78         self,
79         bcx: &Builder<'a, 'tcx>,
80         st: &layout::Struct,
81         fields: &Vec<Ty<'tcx>>,
82         ix: usize,
83         needs_cast: bool
84     ) -> ValueRef {
85         let fty = fields[ix];
86         let ccx = bcx.ccx;
87
88         let ptr_val = if needs_cast {
89             let fields = st.field_index_by_increasing_offset().map(|i| {
90                 type_of::in_memory_type_of(ccx, fields[i])
91             }).collect::<Vec<_>>();
92             let real_ty = Type::struct_(ccx, &fields[..], st.packed);
93             bcx.pointercast(self.llval, real_ty.ptr_to())
94         } else {
95             self.llval
96         };
97
98         // Simple case - we can just GEP the field
99         //   * First field - Always aligned properly
100         //   * Packed struct - There is no alignment padding
101         //   * Field is sized - pointer is properly aligned already
102         if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
103             bcx.ccx.shared().type_is_sized(fty) {
104                 return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
105             }
106
107         // If the type of the last field is [T] or str, then we don't need to do
108         // any adjusments
109         match fty.sty {
110             ty::TySlice(..) | ty::TyStr => {
111                 return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
112             }
113             _ => ()
114         }
115
116         // There's no metadata available, log the case and just do the GEP.
117         if !self.has_extra() {
118             debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
119                 ix, Value(ptr_val));
120             return bcx.struct_gep(ptr_val, ix);
121         }
122
123         // We need to get the pointer manually now.
124         // We do this by casting to a *i8, then offsetting it by the appropriate amount.
125         // We do this instead of, say, simply adjusting the pointer from the result of a GEP
126         // because the field may have an arbitrary alignment in the LLVM representation
127         // anyway.
128         //
129         // To demonstrate:
130         //   struct Foo<T: ?Sized> {
131         //      x: u16,
132         //      y: T
133         //   }
134         //
135         // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
136         // the `y` field has 16-bit alignment.
137
138         let meta = self.llextra;
139
140
141         let offset = st.offsets[ix].bytes();
142         let unaligned_offset = C_uint(bcx.ccx, offset);
143
144         // Get the alignment of the field
145         let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
146
147         // Bump the unaligned offset up to the appropriate alignment using the
148         // following expression:
149         //
150         //   (unaligned offset + (align - 1)) & -align
151
152         // Calculate offset
153         let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
154         let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
155         bcx.neg(align));
156
157         debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
158
159         // Cast and adjust pointer
160         let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx));
161         let byte_ptr = bcx.gep(byte_ptr, &[offset]);
162
163         // Finally, cast back to the type expected
164         let ll_fty = type_of::in_memory_type_of(bcx.ccx, fty);
165         debug!("struct_field_ptr: Field type is {:?}", ll_fty);
166         bcx.pointercast(byte_ptr, ll_fty.ptr_to())
167     }
168
169     /// Access a field, at a point when the value's case is known.
170     pub fn trans_field_ptr(self, bcx: &Builder<'a, 'tcx>, ix: usize) -> ValueRef {
171         let discr = match self.ty {
172             LvalueTy::Ty { .. } => 0,
173             LvalueTy::Downcast { variant_index, .. } => variant_index,
174         };
175         let t = self.ty.to_ty(bcx.tcx());
176         let l = bcx.ccx.layout_of(t);
177         // Note: if this ever needs to generate conditionals (e.g., if we
178         // decide to do some kind of cdr-coding-like non-unique repr
179         // someday), it will need to return a possibly-new bcx as well.
180         match *l {
181             layout::Univariant { ref variant, .. } => {
182                 assert_eq!(discr, 0);
183                 self.struct_field_ptr(bcx, &variant,
184                     &adt::compute_fields(bcx.ccx, t, 0, false), ix, false)
185             }
186             layout::Vector { count, .. } => {
187                 assert_eq!(discr, 0);
188                 assert!((ix as u64) < count);
189                 bcx.struct_gep(self.llval, ix)
190             }
191             layout::General { discr: d, ref variants, .. } => {
192                 let mut fields = adt::compute_fields(bcx.ccx, t, discr, false);
193                 fields.insert(0, d.to_ty(&bcx.tcx(), false));
194                 self.struct_field_ptr(bcx, &variants[discr], &fields, ix + 1, true)
195             }
196             layout::UntaggedUnion { .. } => {
197                 let fields = adt::compute_fields(bcx.ccx, t, 0, false);
198                 let ty = type_of::in_memory_type_of(bcx.ccx, fields[ix]);
199                 bcx.pointercast(self.llval, ty.ptr_to())
200             }
201             layout::RawNullablePointer { nndiscr, .. } |
202             layout::StructWrappedNullablePointer { nndiscr,  .. } if discr as u64 != nndiscr => {
203                 let nullfields = adt::compute_fields(bcx.ccx, t, (1-nndiscr) as usize, false);
204                 // The unit-like case might have a nonzero number of unit-like fields.
205                 // (e.d., Result of Either with (), as one side.)
206                 let ty = type_of::type_of(bcx.ccx, nullfields[ix]);
207                 assert_eq!(machine::llsize_of_alloc(bcx.ccx, ty), 0);
208                 bcx.pointercast(self.llval, ty.ptr_to())
209             }
210             layout::RawNullablePointer { nndiscr, .. } => {
211                 let nnty = adt::compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
212                 assert_eq!(ix, 0);
213                 assert_eq!(discr as u64, nndiscr);
214                 let ty = type_of::type_of(bcx.ccx, nnty);
215                 bcx.pointercast(self.llval, ty.ptr_to())
216             }
217             layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
218                 assert_eq!(discr as u64, nndiscr);
219                 self.struct_field_ptr(bcx, &nonnull,
220                     &adt::compute_fields(bcx.ccx, t, discr, false), ix, false)
221             }
222             _ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
223         }
224     }
225 }
226
227 impl<'a, 'tcx> MirContext<'a, 'tcx> {
228     pub fn trans_lvalue(&mut self,
229                         bcx: &Builder<'a, 'tcx>,
230                         lvalue: &mir::Lvalue<'tcx>)
231                         -> LvalueRef<'tcx> {
232         debug!("trans_lvalue(lvalue={:?})", lvalue);
233
234         let ccx = bcx.ccx;
235         let tcx = ccx.tcx();
236
237         if let mir::Lvalue::Local(index) = *lvalue {
238             match self.locals[index] {
239                 LocalRef::Lvalue(lvalue) => {
240                     return lvalue;
241                 }
242                 LocalRef::Operand(..) => {
243                     bug!("using operand local {:?} as lvalue", lvalue);
244                 }
245             }
246         }
247
248         let result = match *lvalue {
249             mir::Lvalue::Local(_) => bug!(), // handled above
250             mir::Lvalue::Static(def_id) => {
251                 let const_ty = self.monomorphized_lvalue_ty(lvalue);
252                 LvalueRef::new_sized(consts::get_static(ccx, def_id),
253                                      LvalueTy::from_ty(const_ty))
254             },
255             mir::Lvalue::Projection(box mir::Projection {
256                 ref base,
257                 elem: mir::ProjectionElem::Deref
258             }) => {
259                 // Load the pointer from its location.
260                 let ptr = self.trans_consume(bcx, base);
261                 let projected_ty = LvalueTy::from_ty(ptr.ty)
262                     .projection_ty(tcx, &mir::ProjectionElem::Deref);
263                 let projected_ty = self.monomorphize(&projected_ty);
264                 let (llptr, llextra) = match ptr.val {
265                     OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
266                     OperandValue::Pair(llptr, llextra) => (llptr, llextra),
267                     OperandValue::Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
268                 };
269                 LvalueRef {
270                     llval: llptr,
271                     llextra: llextra,
272                     ty: projected_ty,
273                 }
274             }
275             mir::Lvalue::Projection(ref projection) => {
276                 let tr_base = self.trans_lvalue(bcx, &projection.base);
277                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
278                 let projected_ty = self.monomorphize(&projected_ty);
279
280                 let project_index = |llindex| {
281                     let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty {
282                         // Slices already point to the array element type.
283                         bcx.inbounds_gep(tr_base.llval, &[llindex])
284                     } else {
285                         let zero = common::C_uint(bcx.ccx, 0u64);
286                         bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
287                     };
288                     element
289                 };
290
291                 let (llprojected, llextra) = match projection.elem {
292                     mir::ProjectionElem::Deref => bug!(),
293                     mir::ProjectionElem::Field(ref field, _) => {
294                         let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) {
295                             ptr::null_mut()
296                         } else {
297                             tr_base.llextra
298                         };
299                         (tr_base.trans_field_ptr(bcx, field.index()), llextra)
300                     }
301                     mir::ProjectionElem::Index(ref index) => {
302                         let index = self.trans_operand(bcx, index);
303                         (project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut())
304                     }
305                     mir::ProjectionElem::ConstantIndex { offset,
306                                                          from_end: false,
307                                                          min_length: _ } => {
308                         let lloffset = C_uint(bcx.ccx, offset);
309                         (project_index(lloffset), ptr::null_mut())
310                     }
311                     mir::ProjectionElem::ConstantIndex { offset,
312                                                          from_end: true,
313                                                          min_length: _ } => {
314                         let lloffset = C_uint(bcx.ccx, offset);
315                         let lllen = tr_base.len(bcx.ccx);
316                         let llindex = bcx.sub(lllen, lloffset);
317                         (project_index(llindex), ptr::null_mut())
318                     }
319                     mir::ProjectionElem::Subslice { from, to } => {
320                         let llindex = C_uint(bcx.ccx, from);
321                         let llbase = project_index(llindex);
322
323                         let base_ty = tr_base.ty.to_ty(bcx.tcx());
324                         match base_ty.sty {
325                             ty::TyArray(..) => {
326                                 // must cast the lvalue pointer type to the new
327                                 // array type (*[%_; new_len]).
328                                 let base_ty = self.monomorphized_lvalue_ty(lvalue);
329                                 let llbasety = type_of::type_of(bcx.ccx, base_ty).ptr_to();
330                                 let llbase = bcx.pointercast(llbase, llbasety);
331                                 (llbase, ptr::null_mut())
332                             }
333                             ty::TySlice(..) => {
334                                 assert!(tr_base.llextra != ptr::null_mut());
335                                 let lllen = bcx.sub(tr_base.llextra,
336                                                     C_uint(bcx.ccx, from+to));
337                                 (llbase, lllen)
338                             }
339                             _ => bug!("unexpected type {:?} in Subslice", base_ty)
340                         }
341                     }
342                     mir::ProjectionElem::Downcast(..) => {
343                         (tr_base.llval, tr_base.llextra)
344                     }
345                 };
346                 LvalueRef {
347                     llval: llprojected,
348                     llextra: llextra,
349                     ty: projected_ty,
350                 }
351             }
352         };
353         debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
354         result
355     }
356
357     // Perform an action using the given Lvalue.
358     // If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
359     // is created first, then used as an operand to update the Lvalue.
360     pub fn with_lvalue_ref<F, U>(&mut self, bcx: &Builder<'a, 'tcx>,
361                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
362     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
363     {
364         if let mir::Lvalue::Local(index) = *lvalue {
365             match self.locals[index] {
366                 LocalRef::Lvalue(lvalue) => f(self, lvalue),
367                 LocalRef::Operand(None) => {
368                     let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
369                     assert!(!lvalue_ty.has_erasable_regions());
370                     let lltemp = bcx.alloca_ty(lvalue_ty, "lvalue_temp");
371                     let lvalue = LvalueRef::new_sized(lltemp, LvalueTy::from_ty(lvalue_ty));
372                     let ret = f(self, lvalue);
373                     let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
374                     self.locals[index] = LocalRef::Operand(Some(op));
375                     ret
376                 }
377                 LocalRef::Operand(Some(_)) => {
378                     // See comments in LocalRef::new_operand as to why
379                     // we always have Some in a ZST LocalRef::Operand.
380                     let ty = self.monomorphized_lvalue_ty(lvalue);
381                     if common::type_is_zero_size(bcx.ccx, ty) {
382                         // Pass an undef pointer as no stores can actually occur.
383                         let llptr = C_undef(type_of(bcx.ccx, ty).ptr_to());
384                         f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
385                     } else {
386                         bug!("Lvalue local already set");
387                     }
388                 }
389             }
390         } else {
391             let lvalue = self.trans_lvalue(bcx, lvalue);
392             f(self, lvalue)
393         }
394     }
395
396     /// Adjust the bitwidth of an index since LLVM is less forgiving
397     /// than we are.
398     ///
399     /// nmatsakis: is this still necessary? Not sure.
400     fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef {
401         let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
402         let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.int_type());
403         if index_size < int_size {
404             bcx.zext(llindex, bcx.ccx.int_type())
405         } else if index_size > int_size {
406             bcx.trunc(llindex, bcx.ccx.int_type())
407         } else {
408             llindex
409         }
410     }
411
412     pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
413         let tcx = self.ccx.tcx();
414         let lvalue_ty = lvalue.ty(&self.mir, tcx);
415         self.monomorphize(&lvalue_ty.to_ty(tcx))
416     }
417 }