]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/lvalue.rs
MIR: Add pass that erases all regions right before trans
[rust.git] / src / librustc_trans / 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::middle::ty::{self, Ty, HasTypeFlags};
13 use rustc_mir::repr as mir;
14 use rustc_mir::tcx::LvalueTy;
15 use trans::adt;
16 use trans::base;
17 use trans::build;
18 use trans::common::{self, Block};
19 use trans::debuginfo::DebugLoc;
20 use trans::machine;
21
22 use std::ptr;
23
24 use super::{MirContext, TempRef};
25
26 #[derive(Copy, Clone)]
27 pub struct LvalueRef<'tcx> {
28     /// Pointer to the contents of the lvalue
29     pub llval: ValueRef,
30
31     /// This lvalue's extra data if it is unsized, or null
32     pub llextra: ValueRef,
33
34     /// Monomorphized type of this lvalue, including variant information
35     pub ty: LvalueTy<'tcx>,
36 }
37
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 }
41     }
42
43     pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
44                         ty: Ty<'tcx>,
45                         name: &str)
46                         -> LvalueRef<'tcx>
47     {
48         assert!(!ty.has_erasable_regions());
49         let lltemp = base::alloc_ty(bcx, ty, name);
50         LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
51     }
52 }
53
54 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
55     pub fn lvalue_len(&mut self,
56                       bcx: Block<'bcx, 'tcx>,
57                       lvalue: LvalueRef<'tcx>)
58                       -> ValueRef {
59         match lvalue.ty.to_ty(bcx.tcx()).sty {
60             ty::TyArray(_, n) => common::C_uint(bcx.ccx(), n),
61             ty::TySlice(_) | ty::TyStr => {
62                 assert!(lvalue.llextra != ptr::null_mut());
63                 lvalue.llextra
64             }
65             _ => bcx.sess().bug("unexpected type in get_base_and_len"),
66         }
67     }
68
69     pub fn trans_lvalue(&mut self,
70                         bcx: Block<'bcx, 'tcx>,
71                         lvalue: &mir::Lvalue<'tcx>)
72                         -> LvalueRef<'tcx> {
73         debug!("trans_lvalue(lvalue={:?})", lvalue);
74
75         let fcx = bcx.fcx;
76         let ccx = fcx.ccx;
77         let tcx = bcx.tcx();
78         match *lvalue {
79             mir::Lvalue::Var(index) => self.vars[index as usize],
80             mir::Lvalue::Temp(index) => match self.temps[index as usize] {
81                 TempRef::Lvalue(lvalue) =>
82                     lvalue,
83                 TempRef::Operand(..) =>
84                     tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
85             },
86             mir::Lvalue::Arg(index) => self.args[index as usize],
87             mir::Lvalue::Static(def_id) => {
88                 let const_ty = self.mir.lvalue_ty(tcx, lvalue);
89                 LvalueRef::new_sized(
90                     common::get_static_val(ccx, def_id, const_ty.to_ty(tcx)),
91                     const_ty)
92             },
93             mir::Lvalue::ReturnPointer => {
94                 let return_ty = bcx.monomorphize(&self.mir.return_ty);
95                 let llval = fcx.get_ret_slot(bcx, return_ty, "return");
96                 LvalueRef::new_sized(llval, LvalueTy::from_ty(return_ty.unwrap()))
97             }
98             mir::Lvalue::Projection(ref projection) => {
99                 let tr_base = self.trans_lvalue(bcx, &projection.base);
100                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
101                 let (llprojected, llextra) = match projection.elem {
102                     mir::ProjectionElem::Deref => {
103                         let base_ty = tr_base.ty.to_ty(tcx);
104                         if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
105                             (base::load_ty(bcx, tr_base.llval, base_ty),
106                              ptr::null_mut())
107                         } else {
108                             base::load_fat_ptr(bcx, tr_base.llval, base_ty)
109                         }
110                     }
111                     mir::ProjectionElem::Field(ref field) => {
112                         let base_ty = tr_base.ty.to_ty(tcx);
113                         let base_repr = adt::represent_type(ccx, base_ty);
114                         let discr = match tr_base.ty {
115                             LvalueTy::Ty { .. } => 0,
116                             LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
117                         };
118                         let discr = discr as u64;
119                         (adt::trans_field_ptr(bcx, &base_repr, tr_base.llval, discr, field.index()),
120                          if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
121                              ptr::null_mut()
122                          } else {
123                              tr_base.llextra
124                          })
125                     }
126                     mir::ProjectionElem::Index(ref index) => {
127                         let index = self.trans_operand(bcx, index);
128                         let llindex = self.prepare_index(bcx, index.immediate());
129                         (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
130                          ptr::null_mut())
131                     }
132                     mir::ProjectionElem::ConstantIndex { offset,
133                                                          from_end: false,
134                                                          min_length: _ } => {
135                         let lloffset = common::C_u32(bcx.ccx(), offset);
136                         let llindex = self.prepare_index(bcx, lloffset);
137                         (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
138                          ptr::null_mut())
139                     }
140                     mir::ProjectionElem::ConstantIndex { offset,
141                                                          from_end: true,
142                                                          min_length: _ } => {
143                         let lloffset = common::C_u32(bcx.ccx(), offset);
144                         let lllen = self.lvalue_len(bcx, tr_base);
145                         let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
146                         let llindex = self.prepare_index(bcx, llindex);
147                         (build::InBoundsGEP(bcx, tr_base.llval, &[llindex]),
148                          ptr::null_mut())
149                     }
150                     mir::ProjectionElem::Downcast(..) => {
151                         (tr_base.llval, tr_base.llextra)
152                     }
153                 };
154                 LvalueRef {
155                     llval: llprojected,
156                     llextra: llextra,
157                     ty: projected_ty,
158                 }
159             }
160         }
161     }
162
163     /// Adjust the bitwidth of an index since LLVM is less forgiving
164     /// than we are.
165     ///
166     /// nmatsakis: is this still necessary? Not sure.
167     fn prepare_index(&mut self,
168                      bcx: Block<'bcx, 'tcx>,
169                      llindex: ValueRef)
170                      -> ValueRef
171     {
172         let ccx = bcx.ccx();
173         let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
174         let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
175         if index_size < int_size {
176             build::ZExt(bcx, llindex, ccx.int_type())
177         } else if index_size > int_size {
178             build::Trunc(bcx, llindex, ccx.int_type())
179         } else {
180             llindex
181         }
182     }
183 }