]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/lvalue.rs
1ce7b55a9c686400d077d7eb44ecd88091212427
[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::Ty;
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 use trans::tvec;
22
23 use super::{MirContext, TempRef};
24
25 #[derive(Copy, Clone)]
26 pub struct LvalueRef<'tcx> {
27     /// Pointer to the contents of the lvalue
28     pub llval: ValueRef,
29
30     /// Monomorphized type of this lvalue, including variant information
31     pub ty: LvalueTy<'tcx>,
32 }
33
34 impl<'tcx> LvalueRef<'tcx> {
35     pub fn new(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> {
36         LvalueRef { llval: llval, ty: lvalue_ty }
37     }
38
39     pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>,
40                         ty: Ty<'tcx>,
41                         name: &str)
42                         -> LvalueRef<'tcx>
43     {
44         let lltemp = base::alloc_ty(bcx, ty, name);
45         LvalueRef::new(lltemp, LvalueTy::from_ty(ty))
46     }
47 }
48
49 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
50     pub fn trans_lvalue(&mut self,
51                         bcx: Block<'bcx, 'tcx>,
52                         lvalue: &mir::Lvalue<'tcx>)
53                         -> LvalueRef<'tcx> {
54         debug!("trans_lvalue(lvalue={:?})", lvalue);
55
56         let fcx = bcx.fcx;
57         let ccx = fcx.ccx;
58         let tcx = bcx.tcx();
59         match *lvalue {
60             mir::Lvalue::Var(index) => self.vars[index as usize],
61             mir::Lvalue::Temp(index) => match self.temps[index as usize] {
62                 TempRef::Lvalue(lvalue) =>
63                     lvalue,
64                 TempRef::Operand(..) =>
65                     tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
66             },
67             mir::Lvalue::Arg(index) => self.args[index as usize],
68             mir::Lvalue::Static(_def_id) => unimplemented!(),
69             mir::Lvalue::ReturnPointer => {
70                 let return_ty = bcx.monomorphize(&self.mir.return_ty);
71                 let llval = fcx.get_ret_slot(bcx, return_ty, "return");
72                 LvalueRef::new(llval, LvalueTy::from_ty(return_ty.unwrap()))
73             }
74             mir::Lvalue::Projection(ref projection) => {
75                 let tr_base = self.trans_lvalue(bcx, &projection.base);
76                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
77                 let llprojected = match projection.elem {
78                     mir::ProjectionElem::Deref => {
79                         let base_ty = tr_base.ty.to_ty(tcx);
80                         base::load_ty(bcx, tr_base.llval, base_ty)
81                     }
82                     mir::ProjectionElem::Field(ref field) => {
83                         let base_ty = tr_base.ty.to_ty(tcx);
84                         let base_repr = adt::represent_type(ccx, base_ty);
85                         let discr = match tr_base.ty {
86                             LvalueTy::Ty { .. } => 0,
87                             LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
88                         };
89                         let discr = discr as u64;
90                         adt::trans_field_ptr(bcx, &base_repr, tr_base.llval, discr, field.index())
91                     }
92                     mir::ProjectionElem::Index(ref index) => {
93                         let base_ty = tr_base.ty.to_ty(tcx);
94                         let index = self.trans_operand(bcx, index);
95                         let llindex = self.prepare_index(bcx, index.llval);
96                         let (llbase, _) = tvec::get_base_and_len(bcx, tr_base.llval, base_ty);
97                         build::InBoundsGEP(bcx, llbase, &[llindex])
98                     }
99                     mir::ProjectionElem::ConstantIndex { offset,
100                                                          from_end: false,
101                                                          min_length: _ } => {
102                         let base_ty = tr_base.ty.to_ty(tcx);
103                         let lloffset = common::C_u32(bcx.ccx(), offset);
104                         let llindex = self.prepare_index(bcx, lloffset);
105                         let (llbase, _) = tvec::get_base_and_len(bcx,
106                                                                  tr_base.llval,
107                                                                  base_ty);
108                         build::InBoundsGEP(bcx, llbase, &[llindex])
109                     }
110                     mir::ProjectionElem::ConstantIndex { offset,
111                                                          from_end: true,
112                                                          min_length: _ } => {
113                         let lloffset = common::C_u32(bcx.ccx(), offset);
114                         let base_ty = tr_base.ty.to_ty(tcx);
115                         let (llbase, lllen) = tvec::get_base_and_len(bcx,
116                                                                      tr_base.llval,
117                                                                      base_ty);
118                         let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None);
119                         let llindex = self.prepare_index(bcx, llindex);
120                         build::InBoundsGEP(bcx, llbase, &[llindex])
121                     }
122                     mir::ProjectionElem::Downcast(..) => {
123                         tr_base.llval
124                     }
125                 };
126                 LvalueRef {
127                     llval: llprojected,
128                     ty: projected_ty,
129                 }
130             }
131         }
132     }
133
134     /// Adjust the bitwidth of an index since LLVM is less forgiving
135     /// than we are.
136     ///
137     /// nmatsakis: is this still necessary? Not sure.
138     fn prepare_index(&mut self,
139                      bcx: Block<'bcx, 'tcx>,
140                      llindex: ValueRef)
141                      -> ValueRef
142     {
143         let ccx = bcx.ccx();
144         let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
145         let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
146         if index_size < int_size {
147             build::ZExt(bcx, llindex, ccx.int_type())
148         } else if index_size > int_size {
149             build::Trunc(bcx, llindex, ccx.int_type())
150         } else {
151             llindex
152         }
153     }
154 }