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