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.
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.
11 #![allow(non_camel_case_types)]
20 use trans::cleanup::CleanupMethods;
24 use trans::debuginfo::DebugLoc;
25 use trans::expr::{Dest, Ignore, SaveIn};
27 use trans::machine::llsize_of_alloc;
28 use trans::type_::Type;
30 use middle::ty::{self, Ty};
31 use util::ppaux::ty_to_string;
34 use syntax::parse::token::InternedString;
37 struct VecTypes<'tcx> {
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 ty_to_string(ccx.tcx(), self.unit_ty),
46 ccx.tn().type_to_string(self.llunit_ty))
50 pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
53 -> Block<'blk, 'tcx> {
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.
61 debug!("trans_fixed_vstore(expr={}, dest={})",
62 bcx.expr_to_string(expr), dest.to_string(bcx.ccx()));
64 let vt = vec_types_from_expr(bcx, expr);
67 Ignore => write_content(bcx, &vt, expr, expr, dest),
69 // lldest will have type *[T x N], but we want the type *T,
70 // so use GEP to convert:
71 let lldest = GEPi(bcx, lldest, &[0, 0]);
72 write_content(bcx, &vt, expr, expr, SaveIn(lldest))
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: &ast::Expr,
82 content_expr: &ast::Expr)
83 -> DatumBlock<'blk, 'tcx, Expr> {
88 debug!("trans_slice_vec(slice_expr={})",
89 bcx.expr_to_string(slice_expr));
91 let vec_ty = node_id_type(bcx, slice_expr.id);
93 // Handle the "..." case (returns a slice since strings are always unsized):
94 if let ast::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,
100 SaveIn(scratch.val));
101 return DatumBlock::new(bcx, scratch.to_expr_datum());
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);
110 let fixed_ty = ty::mk_vec(bcx.tcx(),
113 let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty);
115 // Always create an alloca even if zero-sized, to preserve
116 // the non-null invariant of the inner slice ptr
117 let llfixed = base::alloca(bcx, llfixed_ty, "");
120 // Arrange for the backing array to be cleaned up.
121 let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
122 fcx.schedule_lifetime_end(cleanup_scope, llfixed);
123 fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty);
125 // Generate the content into the backing array.
126 // llfixed has type *[T x N], but we want the type *T,
127 // so use GEP to convert
128 bcx = write_content(bcx, &vt, slice_expr, content_expr,
129 SaveIn(GEPi(bcx, llfixed, &[0, 0])));
132 immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
135 /// Literal strings translate to slices into static memory. This is different from
136 /// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
137 pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
138 lit_expr: &ast::Expr,
139 str_lit: InternedString,
141 -> Block<'blk, 'tcx> {
142 debug!("trans_lit_str(lit_expr={}, dest={})",
143 bcx.expr_to_string(lit_expr),
144 dest.to_string(bcx.ccx()));
149 let bytes = str_lit.len();
150 let llbytes = C_uint(bcx.ccx(), bytes);
151 let llcstr = C_cstr(bcx.ccx(), str_lit, false);
152 let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
153 Store(bcx, llcstr, GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
154 Store(bcx, llbytes, GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
160 fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
162 vstore_expr: &ast::Expr,
163 content_expr: &ast::Expr,
165 -> Block<'blk, 'tcx> {
166 let _icx = push_ctxt("tvec::write_content");
170 debug!("write_content(vt={}, dest={}, vstore_expr={})",
171 vt.to_string(bcx.ccx()),
172 dest.to_string(bcx.ccx()),
173 bcx.expr_to_string(vstore_expr));
175 match content_expr.node {
176 ast::ExprLit(ref lit) => {
178 ast::LitStr(ref s, _) => {
180 Ignore => return bcx,
183 let llbytes = C_uint(bcx.ccx(), bytes);
184 let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
185 base::call_memcpy(bcx,
195 bcx.tcx().sess.span_bug(content_expr.span,
196 "unexpected evec content");
200 ast::ExprVec(ref elements) => {
203 for element in elements {
204 bcx = expr::trans_into(bcx, &**element, Ignore);
209 let temp_scope = fcx.push_custom_cleanup_scope();
210 for (i, element) in elements.iter().enumerate() {
211 let lleltptr = GEPi(bcx, lldest, &[i]);
212 debug!("writing index {} with lleltptr={}",
213 i, bcx.val_to_string(lleltptr));
214 bcx = expr::trans_into(bcx, &**element,
216 let scope = cleanup::CustomScope(temp_scope);
217 fcx.schedule_lifetime_end(scope, lleltptr);
218 fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty);
220 fcx.pop_custom_cleanup_scope(temp_scope);
225 ast::ExprRepeat(ref element, ref count_expr) => {
228 return expr::trans_into(bcx, &**element, Ignore);
231 match ty::eval_repeat_count(bcx.tcx(), &**count_expr) {
232 0 => expr::trans_into(bcx, &**element, Ignore),
233 1 => expr::trans_into(bcx, &**element, SaveIn(lldest)),
235 let elem = unpack_datum!(bcx, expr::trans(bcx, &**element));
236 let bcx = iter_vec_loop(bcx, lldest, vt,
237 C_uint(bcx.ccx(), count),
238 |set_bcx, lleltptr, _| {
239 elem.shallow_copy(set_bcx, lleltptr)
248 bcx.tcx().sess.span_bug(content_expr.span,
249 "unexpected vec content");
254 fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &ast::Expr)
256 let vec_ty = node_id_type(bcx, vec_expr.id);
257 vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty))
260 fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>)
264 llunit_ty: type_of::type_of(bcx.ccx(), unit_ty)
268 fn elements_required(bcx: Block, content_expr: &ast::Expr) -> usize {
269 //! Figure out the number of elements we need to store this content
271 match content_expr.node {
272 ast::ExprLit(ref lit) => {
274 ast::LitStr(ref s, _) => s.len(),
276 bcx.tcx().sess.span_bug(content_expr.span,
277 "unexpected evec content")
281 ast::ExprVec(ref es) => es.len(),
282 ast::ExprRepeat(_, ref count_expr) => {
283 ty::eval_repeat_count(bcx.tcx(), &**count_expr)
285 _ => bcx.tcx().sess.span_bug(content_expr.span,
286 "unexpected vec content")
290 /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
291 /// which should be by ref.
292 pub fn get_fixed_base_and_len(bcx: Block,
295 -> (ValueRef, ValueRef) {
298 let base = expr::get_dataptr(bcx, llval);
299 let len = C_uint(ccx, vec_length);
303 /// Converts a vector into the slice pair. The vector should be stored in `llval` which should be
304 /// by-reference. If you have a datum, you would probably prefer to call
305 /// `Datum::get_base_and_len()` which will handle any conversions for you.
306 pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
309 -> (ValueRef, ValueRef) {
313 ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n),
314 ty::ty_vec(_, None) | ty::ty_str => {
315 let base = Load(bcx, expr::get_dataptr(bcx, llval));
316 let len = Load(bcx, expr::get_len(bcx, llval));
320 // Only used for pattern matching.
321 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
322 let inner = if type_is_sized(bcx.tcx(), ty) {
327 get_base_and_len(bcx, inner, ty)
329 _ => ccx.sess().bug("unexpected type in get_base_and_len"),
333 fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
338 -> Block<'blk, 'tcx> where
339 F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
341 let _icx = push_ctxt("tvec::iter_vec_loop");
343 if bcx.unreachable.get() {
348 let loop_bcx = fcx.new_temp_block("expr_repeat");
349 let next_bcx = fcx.new_temp_block("expr_repeat: next");
351 Br(bcx, loop_bcx.llbb, DebugLoc::None);
353 let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(),
354 &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]);
358 let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
361 InBoundsGEP(bcx, data_ptr, &[loop_counter])
363 let bcx = f(bcx, lleltptr, vt.unit_ty);
364 let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1us), DebugLoc::None);
365 AddIncomingToPhi(loop_counter, plusone, bcx.llbb);
367 let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None);
368 CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None);
373 pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
378 -> Block<'blk, 'tcx> where
379 F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
381 let _icx = push_ctxt("tvec::iter_vec_raw");
384 let vt = vec_types(bcx, unit_ty);
386 if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
387 // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
388 iter_vec_loop(bcx, data_ptr, &vt, len, f)
390 // Calculate the last pointer address we want to handle.
391 let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
393 // Now perform the iteration.
394 let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
395 Br(bcx, header_bcx.llbb, DebugLoc::None);
397 Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
399 ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
400 let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
401 let next_bcx = fcx.new_temp_block("iter_vec_next");
402 CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
403 let body_bcx = f(body_bcx, data_ptr, unit_ty);
404 AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
405 &[C_int(bcx.ccx(), 1)]),
407 Br(body_bcx, header_bcx.llbb, DebugLoc::None);