]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/tvec.rs
Autoderef in librustc_trans
[rust.git] / src / librustc_trans / trans / tvec.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 #![allow(non_camel_case_types)]
12
13 use llvm;
14 use llvm::ValueRef;
15 use trans::base::*;
16 use trans::base;
17 use trans::build::*;
18 use trans::cleanup;
19 use trans::cleanup::CleanupMethods;
20 use trans::common::*;
21 use trans::consts;
22 use trans::datum::*;
23 use trans::debuginfo::DebugLoc;
24 use trans::expr::{Dest, Ignore, SaveIn};
25 use trans::expr;
26 use trans::machine::llsize_of_alloc;
27 use trans::type_::Type;
28 use trans::type_of;
29 use middle::ty::{self, Ty};
30
31 use rustc_front::hir;
32
33 use syntax::ast;
34 use syntax::parse::token::InternedString;
35
36 #[derive(Copy, Clone)]
37 struct VecTypes<'tcx> {
38     unit_ty: Ty<'tcx>,
39     llunit_ty: Type
40 }
41
42 impl<'tcx> VecTypes<'tcx> {
43     pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
44         format!("VecTypes {{unit_ty={}, llunit_ty={}}}",
45                 self.unit_ty,
46                 ccx.tn().type_to_string(self.llunit_ty))
47     }
48 }
49
50 pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
51                                       expr: &hir::Expr,
52                                       dest: expr::Dest)
53                                       -> Block<'blk, 'tcx> {
54     //!
55     //
56     // [...] allocates a fixed-size array and moves it around "by value".
57     // In this case, it means that the caller has already given us a location
58     // to store the array of the suitable size, so all we have to do is
59     // generate the content.
60
61     debug!("trans_fixed_vstore(expr={:?}, dest={})",
62            expr, dest.to_string(bcx.ccx()));
63
64     let vt = vec_types_from_expr(bcx, expr);
65
66     return match dest {
67         Ignore => write_content(bcx, &vt, expr, expr, dest),
68         SaveIn(lldest) => {
69             // lldest will have type *[T x N], but we want the type *T,
70             // so use GEP to convert:
71             let lldest = StructGEP(bcx, lldest, 0);
72             write_content(bcx, &vt, expr, expr, SaveIn(lldest))
73         }
74     };
75 }
76
77 /// &[...] allocates memory on the stack and writes the values into it, returning the vector (the
78 /// caller must make the reference).  "..." is similar except that the memory can be statically
79 /// allocated and we return a reference (strings are always by-ref).
80 pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
81                                    slice_expr: &hir::Expr,
82                                    content_expr: &hir::Expr)
83                                    -> DatumBlock<'blk, 'tcx, Expr> {
84     let fcx = bcx.fcx;
85     let ccx = fcx.ccx;
86     let mut bcx = bcx;
87
88     debug!("trans_slice_vec(slice_expr={:?})",
89            slice_expr);
90
91     let vec_ty = node_id_type(bcx, slice_expr.id);
92
93     // Handle the "..." case (returns a slice since strings are always unsized):
94     if let hir::ExprLit(ref lit) = content_expr.node {
95         if let ast::LitKind::Str(ref s, _) = lit.node {
96             let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
97             bcx = trans_lit_str(bcx,
98                                 content_expr,
99                                 s.clone(),
100                                 SaveIn(scratch.val));
101             return DatumBlock::new(bcx, scratch.to_expr_datum());
102         }
103     }
104
105     // Handle the &[...] case:
106     let vt = vec_types_from_expr(bcx, content_expr);
107     let count = elements_required(bcx, content_expr);
108     debug!("    vt={}, count={}", vt.to_string(ccx), count);
109
110     let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count);
111
112     // Always create an alloca even if zero-sized, to preserve
113     // the non-null invariant of the inner slice ptr
114     let llfixed;
115     // Issue 30018: ensure state is initialized as dropped if necessary.
116     if fcx.type_needs_drop(vt.unit_ty) {
117         llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, "");
118     } else {
119         let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop");
120         llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, "");
121         call_lifetime_start(bcx, llfixed);
122     };
123
124     if count > 0 {
125         // Arrange for the backing array to be cleaned up.
126         let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
127         fcx.schedule_lifetime_end(cleanup_scope, llfixed);
128         fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None);
129
130         // Generate the content into the backing array.
131         // llfixed has type *[T x N], but we want the type *T,
132         // so use GEP to convert
133         bcx = write_content(bcx, &vt, slice_expr, content_expr,
134                             SaveIn(StructGEP(bcx, llfixed, 0)));
135     };
136
137     immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
138 }
139
140 /// Literal strings translate to slices into static memory.  This is different from
141 /// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
142 pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
143                                  lit_expr: &hir::Expr,
144                                  str_lit: InternedString,
145                                  dest: Dest)
146                                  -> Block<'blk, 'tcx> {
147     debug!("trans_lit_str(lit_expr={:?}, dest={})",
148            lit_expr,
149            dest.to_string(bcx.ccx()));
150
151     match dest {
152         Ignore => bcx,
153         SaveIn(lldest) => {
154             let bytes = str_lit.len();
155             let llbytes = C_uint(bcx.ccx(), bytes);
156             let llcstr = C_cstr(bcx.ccx(), str_lit, false);
157             let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
158             Store(bcx, llcstr, expr::get_dataptr(bcx, lldest));
159             Store(bcx, llbytes, expr::get_meta(bcx, lldest));
160             bcx
161         }
162     }
163 }
164
165 fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
166                              vt: &VecTypes<'tcx>,
167                              vstore_expr: &hir::Expr,
168                              content_expr: &hir::Expr,
169                              dest: Dest)
170                              -> Block<'blk, 'tcx> {
171     let _icx = push_ctxt("tvec::write_content");
172     let fcx = bcx.fcx;
173     let mut bcx = bcx;
174
175     debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
176            vt.to_string(bcx.ccx()),
177            dest.to_string(bcx.ccx()),
178            vstore_expr);
179
180     match content_expr.node {
181         hir::ExprLit(ref lit) => {
182             match lit.node {
183                 ast::LitKind::Str(ref s, _) => {
184                     match dest {
185                         Ignore => return bcx,
186                         SaveIn(lldest) => {
187                             let bytes = s.len();
188                             let llbytes = C_uint(bcx.ccx(), bytes);
189                             let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
190                             base::call_memcpy(bcx,
191                                               lldest,
192                                               llcstr,
193                                               llbytes,
194                                               1);
195                             return bcx;
196                         }
197                     }
198                 }
199                 _ => {
200                     bcx.tcx().sess.span_bug(content_expr.span,
201                                             "unexpected evec content");
202                 }
203             }
204         }
205         hir::ExprVec(ref elements) => {
206             match dest {
207                 Ignore => {
208                     for element in elements {
209                         bcx = expr::trans_into(bcx, &element, Ignore);
210                     }
211                 }
212
213                 SaveIn(lldest) => {
214                     let temp_scope = fcx.push_custom_cleanup_scope();
215                     for (i, element) in elements.iter().enumerate() {
216                         let lleltptr = GEPi(bcx, lldest, &[i]);
217                         debug!("writing index {} with lleltptr={}",
218                                i, bcx.val_to_string(lleltptr));
219                         bcx = expr::trans_into(bcx, &element,
220                                                SaveIn(lleltptr));
221                         let scope = cleanup::CustomScope(temp_scope);
222                         // Issue #30822: mark memory as dropped after running destructor
223                         fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None);
224                     }
225                     fcx.pop_custom_cleanup_scope(temp_scope);
226                 }
227             }
228             return bcx;
229         }
230         hir::ExprRepeat(ref element, ref count_expr) => {
231             match dest {
232                 Ignore => {
233                     return expr::trans_into(bcx, &element, Ignore);
234                 }
235                 SaveIn(lldest) => {
236                     match bcx.tcx().eval_repeat_count(&count_expr) {
237                         0 => expr::trans_into(bcx, &element, Ignore),
238                         1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
239                         count => {
240                             let elem = unpack_datum!(bcx, expr::trans(bcx, &element));
241                             let bcx = iter_vec_loop(bcx, lldest, vt,
242                                                     C_uint(bcx.ccx(), count),
243                                                     |set_bcx, lleltptr, _| {
244                                                         elem.shallow_copy(set_bcx, lleltptr)
245                                                     });
246                             bcx
247                         }
248                     }
249                 }
250             }
251         }
252         _ => {
253             bcx.tcx().sess.span_bug(content_expr.span,
254                                     "unexpected vec content");
255         }
256     }
257 }
258
259 fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr)
260                                    -> VecTypes<'tcx> {
261     let vec_ty = node_id_type(bcx, vec_expr.id);
262     vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx()))
263 }
264
265 fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>)
266                          -> VecTypes<'tcx> {
267     VecTypes {
268         unit_ty: unit_ty,
269         llunit_ty: type_of::type_of(bcx.ccx(), unit_ty)
270     }
271 }
272
273 fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
274     //! Figure out the number of elements we need to store this content
275
276     match content_expr.node {
277         hir::ExprLit(ref lit) => {
278             match lit.node {
279                 ast::LitKind::Str(ref s, _) => s.len(),
280                 _ => {
281                     bcx.tcx().sess.span_bug(content_expr.span,
282                                             "unexpected evec content")
283                 }
284             }
285         },
286         hir::ExprVec(ref es) => es.len(),
287         hir::ExprRepeat(_, ref count_expr) => {
288             bcx.tcx().eval_repeat_count(&count_expr)
289         }
290         _ => bcx.tcx().sess.span_bug(content_expr.span,
291                                      "unexpected vec content")
292     }
293 }
294
295 /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
296 /// which should be by ref.
297 pub fn get_fixed_base_and_len(bcx: Block,
298                               llval: ValueRef,
299                               vec_length: usize)
300                               -> (ValueRef, ValueRef) {
301     let ccx = bcx.ccx();
302
303     let base = expr::get_dataptr(bcx, llval);
304     let len = C_uint(ccx, vec_length);
305     (base, len)
306 }
307
308 /// Converts a vector into the slice pair.  The vector should be stored in `llval` which should be
309 /// by-reference.  If you have a datum, you would probably prefer to call
310 /// `Datum::get_base_and_len()` which will handle any conversions for you.
311 pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
312                                     llval: ValueRef,
313                                     vec_ty: Ty<'tcx>)
314                                     -> (ValueRef, ValueRef) {
315     let ccx = bcx.ccx();
316
317     match vec_ty.sty {
318         ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n),
319         ty::TySlice(_) | ty::TyStr => {
320             let base = Load(bcx, expr::get_dataptr(bcx, llval));
321             let len = Load(bcx, expr::get_meta(bcx, llval));
322             (base, len)
323         }
324
325         // Only used for pattern matching.
326         ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
327             let inner = if type_is_sized(bcx.tcx(), ty) {
328                 Load(bcx, llval)
329             } else {
330                 llval
331             };
332             get_base_and_len(bcx, inner, ty)
333         },
334         _ => ccx.sess().bug("unexpected type in get_base_and_len"),
335     }
336 }
337
338 fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
339                                 data_ptr: ValueRef,
340                                 vt: &VecTypes<'tcx>,
341                                 count: ValueRef,
342                                 f: F)
343                                 -> Block<'blk, 'tcx> where
344     F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
345 {
346     let _icx = push_ctxt("tvec::iter_vec_loop");
347
348     if bcx.unreachable.get() {
349         return bcx;
350     }
351
352     let fcx = bcx.fcx;
353     let loop_bcx = fcx.new_temp_block("expr_repeat");
354     let next_bcx = fcx.new_temp_block("expr_repeat: next");
355
356     Br(bcx, loop_bcx.llbb, DebugLoc::None);
357
358     let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(),
359                            &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]);
360
361     let bcx = loop_bcx;
362
363     let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
364         data_ptr
365     } else {
366         InBoundsGEP(bcx, data_ptr, &[loop_counter])
367     };
368     let bcx = f(bcx, lleltptr, vt.unit_ty);
369     let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None);
370     AddIncomingToPhi(loop_counter, plusone, bcx.llbb);
371
372     let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None);
373     CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None);
374
375     next_bcx
376 }
377
378 pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
379                                    data_ptr: ValueRef,
380                                    unit_ty: Ty<'tcx>,
381                                    len: ValueRef,
382                                    f: F)
383                                    -> Block<'blk, 'tcx> where
384     F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
385 {
386     let _icx = push_ctxt("tvec::iter_vec_raw");
387     let fcx = bcx.fcx;
388
389     let vt = vec_types(bcx, unit_ty);
390
391     if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
392         // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
393         iter_vec_loop(bcx, data_ptr, &vt, len, f)
394     } else {
395         // Calculate the last pointer address we want to handle.
396         let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
397
398         // Now perform the iteration.
399         let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
400         Br(bcx, header_bcx.llbb, DebugLoc::None);
401         let data_ptr =
402             Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
403         let not_yet_at_end =
404             ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
405         let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
406         let next_bcx = fcx.new_temp_block("iter_vec_next");
407         CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
408         let body_bcx = f(body_bcx, data_ptr, unit_ty);
409         AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
410                                                &[C_int(bcx.ccx(), 1)]),
411                          body_bcx.llbb);
412         Br(body_bcx, header_bcx.llbb, DebugLoc::None);
413         next_bcx
414     }
415 }