]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/tvec.rs
Use ast attributes every where (remove HIR attributes).
[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::LitStr(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 = base::alloc_ty(bcx, fixed_ty, "");
115     call_lifetime_start(bcx, llfixed);
116
117     if count > 0 {
118         // Arrange for the backing array to be cleaned up.
119         let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
120         fcx.schedule_lifetime_end(cleanup_scope, llfixed);
121         fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None);
122
123         // Generate the content into the backing array.
124         // llfixed has type *[T x N], but we want the type *T,
125         // so use GEP to convert
126         bcx = write_content(bcx, &vt, slice_expr, content_expr,
127                             SaveIn(StructGEP(bcx, llfixed, 0)));
128     };
129
130     immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
131 }
132
133 /// Literal strings translate to slices into static memory.  This is different from
134 /// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
135 pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
136                                  lit_expr: &hir::Expr,
137                                  str_lit: InternedString,
138                                  dest: Dest)
139                                  -> Block<'blk, 'tcx> {
140     debug!("trans_lit_str(lit_expr={:?}, dest={})",
141            lit_expr,
142            dest.to_string(bcx.ccx()));
143
144     match dest {
145         Ignore => bcx,
146         SaveIn(lldest) => {
147             let bytes = str_lit.len();
148             let llbytes = C_uint(bcx.ccx(), bytes);
149             let llcstr = C_cstr(bcx.ccx(), str_lit, false);
150             let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
151             Store(bcx, llcstr, expr::get_dataptr(bcx, lldest));
152             Store(bcx, llbytes, expr::get_meta(bcx, lldest));
153             bcx
154         }
155     }
156 }
157
158 fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
159                              vt: &VecTypes<'tcx>,
160                              vstore_expr: &hir::Expr,
161                              content_expr: &hir::Expr,
162                              dest: Dest)
163                              -> Block<'blk, 'tcx> {
164     let _icx = push_ctxt("tvec::write_content");
165     let fcx = bcx.fcx;
166     let mut bcx = bcx;
167
168     debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
169            vt.to_string(bcx.ccx()),
170            dest.to_string(bcx.ccx()),
171            vstore_expr);
172
173     match content_expr.node {
174         hir::ExprLit(ref lit) => {
175             match lit.node {
176                 ast::LitStr(ref s, _) => {
177                     match dest {
178                         Ignore => return bcx,
179                         SaveIn(lldest) => {
180                             let bytes = s.len();
181                             let llbytes = C_uint(bcx.ccx(), bytes);
182                             let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
183                             base::call_memcpy(bcx,
184                                               lldest,
185                                               llcstr,
186                                               llbytes,
187                                               1);
188                             return bcx;
189                         }
190                     }
191                 }
192                 _ => {
193                     bcx.tcx().sess.span_bug(content_expr.span,
194                                             "unexpected evec content");
195                 }
196             }
197         }
198         hir::ExprVec(ref elements) => {
199             match dest {
200                 Ignore => {
201                     for element in elements {
202                         bcx = expr::trans_into(bcx, &**element, Ignore);
203                     }
204                 }
205
206                 SaveIn(lldest) => {
207                     let temp_scope = fcx.push_custom_cleanup_scope();
208                     for (i, element) in elements.iter().enumerate() {
209                         let lleltptr = GEPi(bcx, lldest, &[i]);
210                         debug!("writing index {} with lleltptr={}",
211                                i, bcx.val_to_string(lleltptr));
212                         bcx = expr::trans_into(bcx, &**element,
213                                                SaveIn(lleltptr));
214                         let scope = cleanup::CustomScope(temp_scope);
215                         fcx.schedule_lifetime_end(scope, lleltptr);
216                         fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty, None);
217                     }
218                     fcx.pop_custom_cleanup_scope(temp_scope);
219                 }
220             }
221             return bcx;
222         }
223         hir::ExprRepeat(ref element, ref count_expr) => {
224             match dest {
225                 Ignore => {
226                     return expr::trans_into(bcx, &**element, Ignore);
227                 }
228                 SaveIn(lldest) => {
229                     match bcx.tcx().eval_repeat_count(&**count_expr) {
230                         0 => expr::trans_into(bcx, &**element, Ignore),
231                         1 => expr::trans_into(bcx, &**element, SaveIn(lldest)),
232                         count => {
233                             let elem = unpack_datum!(bcx, expr::trans(bcx, &**element));
234                             let bcx = iter_vec_loop(bcx, lldest, vt,
235                                                     C_uint(bcx.ccx(), count),
236                                                     |set_bcx, lleltptr, _| {
237                                                         elem.shallow_copy(set_bcx, lleltptr)
238                                                     });
239                             bcx
240                         }
241                     }
242                 }
243             }
244         }
245         _ => {
246             bcx.tcx().sess.span_bug(content_expr.span,
247                                     "unexpected vec content");
248         }
249     }
250 }
251
252 fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr)
253                                    -> VecTypes<'tcx> {
254     let vec_ty = node_id_type(bcx, vec_expr.id);
255     vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx()))
256 }
257
258 fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>)
259                          -> VecTypes<'tcx> {
260     VecTypes {
261         unit_ty: unit_ty,
262         llunit_ty: type_of::type_of(bcx.ccx(), unit_ty)
263     }
264 }
265
266 fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
267     //! Figure out the number of elements we need to store this content
268
269     match content_expr.node {
270         hir::ExprLit(ref lit) => {
271             match lit.node {
272                 ast::LitStr(ref s, _) => s.len(),
273                 _ => {
274                     bcx.tcx().sess.span_bug(content_expr.span,
275                                             "unexpected evec content")
276                 }
277             }
278         },
279         hir::ExprVec(ref es) => es.len(),
280         hir::ExprRepeat(_, ref count_expr) => {
281             bcx.tcx().eval_repeat_count(&**count_expr)
282         }
283         _ => bcx.tcx().sess.span_bug(content_expr.span,
284                                      "unexpected vec content")
285     }
286 }
287
288 /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
289 /// which should be by ref.
290 pub fn get_fixed_base_and_len(bcx: Block,
291                               llval: ValueRef,
292                               vec_length: usize)
293                               -> (ValueRef, ValueRef) {
294     let ccx = bcx.ccx();
295
296     let base = expr::get_dataptr(bcx, llval);
297     let len = C_uint(ccx, vec_length);
298     (base, len)
299 }
300
301 /// Converts a vector into the slice pair.  The vector should be stored in `llval` which should be
302 /// by-reference.  If you have a datum, you would probably prefer to call
303 /// `Datum::get_base_and_len()` which will handle any conversions for you.
304 pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
305                                     llval: ValueRef,
306                                     vec_ty: Ty<'tcx>)
307                                     -> (ValueRef, ValueRef) {
308     let ccx = bcx.ccx();
309
310     match vec_ty.sty {
311         ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n),
312         ty::TySlice(_) | ty::TyStr => {
313             let base = Load(bcx, expr::get_dataptr(bcx, llval));
314             let len = Load(bcx, expr::get_meta(bcx, llval));
315             (base, len)
316         }
317
318         // Only used for pattern matching.
319         ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
320             let inner = if type_is_sized(bcx.tcx(), ty) {
321                 Load(bcx, llval)
322             } else {
323                 llval
324             };
325             get_base_and_len(bcx, inner, ty)
326         },
327         _ => ccx.sess().bug("unexpected type in get_base_and_len"),
328     }
329 }
330
331 fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
332                                 data_ptr: ValueRef,
333                                 vt: &VecTypes<'tcx>,
334                                 count: ValueRef,
335                                 f: F)
336                                 -> Block<'blk, 'tcx> where
337     F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
338 {
339     let _icx = push_ctxt("tvec::iter_vec_loop");
340
341     if bcx.unreachable.get() {
342         return bcx;
343     }
344
345     let fcx = bcx.fcx;
346     let loop_bcx = fcx.new_temp_block("expr_repeat");
347     let next_bcx = fcx.new_temp_block("expr_repeat: next");
348
349     Br(bcx, loop_bcx.llbb, DebugLoc::None);
350
351     let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(),
352                            &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]);
353
354     let bcx = loop_bcx;
355
356     let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
357         data_ptr
358     } else {
359         InBoundsGEP(bcx, data_ptr, &[loop_counter])
360     };
361     let bcx = f(bcx, lleltptr, vt.unit_ty);
362     let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None);
363     AddIncomingToPhi(loop_counter, plusone, bcx.llbb);
364
365     let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None);
366     CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None);
367
368     next_bcx
369 }
370
371 pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
372                                    data_ptr: ValueRef,
373                                    unit_ty: Ty<'tcx>,
374                                    len: ValueRef,
375                                    f: F)
376                                    -> Block<'blk, 'tcx> where
377     F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
378 {
379     let _icx = push_ctxt("tvec::iter_vec_raw");
380     let fcx = bcx.fcx;
381
382     let vt = vec_types(bcx, unit_ty);
383
384     if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
385         // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
386         iter_vec_loop(bcx, data_ptr, &vt, len, f)
387     } else {
388         // Calculate the last pointer address we want to handle.
389         let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
390
391         // Now perform the iteration.
392         let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
393         Br(bcx, header_bcx.llbb, DebugLoc::None);
394         let data_ptr =
395             Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
396         let not_yet_at_end =
397             ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
398         let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
399         let next_bcx = fcx.new_temp_block("iter_vec_next");
400         CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
401         let body_bcx = f(body_bcx, data_ptr, unit_ty);
402         AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
403                                                &[C_int(bcx.ccx(), 1)]),
404                          body_bcx.llbb);
405         Br(body_bcx, header_bcx.llbb, DebugLoc::None);
406         next_bcx
407     }
408 }