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)]
15 use lib::llvm::{llvm, ValueRef};
16 use middle::lang_items::StrDupUniqFnLangItem;
17 use middle::trans::base::*;
18 use middle::trans::base;
19 use middle::trans::build::*;
20 use middle::trans::callee;
21 use middle::trans::cleanup;
22 use middle::trans::cleanup::CleanupMethods;
23 use middle::trans::common::*;
24 use middle::trans::datum::*;
25 use middle::trans::expr::{Dest, Ignore, SaveIn};
26 use middle::trans::expr;
27 use middle::trans::glue;
28 use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
29 use middle::trans::type_::Type;
30 use middle::trans::type_of;
32 use util::ppaux::ty_to_str;
35 use syntax::parse::token::InternedString;
37 pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef {
38 let _icx = push_ctxt("tvec::get_fill");
39 Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
42 pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
43 let _icx = push_ctxt("tvec::get_dataptr");
44 GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
47 pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
48 let _icx = push_ctxt("tvec::pointer_add_byte");
49 let old_ty = val_ty(ptr);
50 let bptr = PointerCast(bcx, ptr, Type::i8p(bcx.ccx()));
51 return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
54 pub fn make_drop_glue_unboxed<'a>(
59 let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
61 if ty::type_needs_drop(tcx, unit_ty) {
62 let fill = get_fill(bcx, vptr);
63 let dataptr = get_dataptr(bcx, vptr);
64 iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty)
71 pub llunit_size: ValueRef,
72 pub llunit_alloc_size: u64
76 pub fn to_str(&self, ccx: &CrateContext) -> String {
77 format!("VecTypes {{unit_ty={}, llunit_ty={}, \
78 llunit_size={}, llunit_alloc_size={}}}",
79 ty_to_str(ccx.tcx(), self.unit_ty),
80 ccx.tn.type_to_str(self.llunit_ty),
81 ccx.tn.val_to_str(self.llunit_size),
82 self.llunit_alloc_size)
86 pub fn trans_fixed_vstore<'a>(
88 vstore_expr: &ast::Expr,
89 content_expr: &ast::Expr,
94 // [...] allocates a fixed-size array and moves it around "by value".
95 // In this case, it means that the caller has already given us a location
96 // to store the array of the suitable size, so all we have to do is
97 // generate the content.
99 debug!("trans_fixed_vstore(vstore_expr={}, dest={:?})",
100 bcx.expr_to_str(vstore_expr), dest.to_str(bcx.ccx()));
102 let vt = vec_types_from_expr(bcx, vstore_expr);
105 Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
107 // lldest will have type *[T x N], but we want the type *T,
108 // so use GEP to convert:
109 let lldest = GEPi(bcx, lldest, [0, 0]);
110 write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
115 pub fn trans_slice_vstore<'a>(
117 vstore_expr: &ast::Expr,
118 content_expr: &ast::Expr,
122 * &[...] allocates memory on the stack and writes the values into it,
123 * returning a slice (pair of ptr, len). &"..." is similar except that
124 * the memory can be statically allocated.
131 debug!("trans_slice_vstore(vstore_expr={}, dest={})",
132 bcx.expr_to_str(vstore_expr), dest.to_str(ccx));
134 // Handle the &"..." case:
135 match content_expr.node {
136 ast::ExprLit(lit) => {
138 ast::LitStr(ref s, _) => {
139 return trans_lit_str(bcx,
150 // Handle the &[...] case:
151 let vt = vec_types_from_expr(bcx, vstore_expr);
152 let count = elements_required(bcx, content_expr);
153 debug!("vt={}, count={:?}", vt.to_str(ccx), count);
155 let llcount = C_uint(ccx, count);
158 // Zero-length array: just use NULL as the data pointer
159 llfixed = C_null(vt.llunit_ty.ptr_to());
161 // Make a fixed-length backing array and allocate it on the stack.
162 llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
164 // Arrange for the backing array to be cleaned up.
165 let fixed_ty = ty::mk_vec(bcx.tcx(),
166 ty::mt {ty: vt.unit_ty,
167 mutbl: ast::MutMutable},
169 let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to();
170 let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
171 let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
172 fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty);
174 // Generate the content into the backing array.
175 bcx = write_content(bcx, &vt, vstore_expr,
176 content_expr, SaveIn(llfixed));
179 // Finally, create the slice pair itself.
183 Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
184 Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
191 pub fn trans_lit_str<'a>(
193 lit_expr: &ast::Expr,
194 str_lit: InternedString,
198 * Literal strings translate to slices into static memory. This is
199 * different from trans_slice_vstore() above because it does need to copy
200 * the content anywhere.
203 debug!("trans_lit_str(lit_expr={}, dest={})",
204 bcx.expr_to_str(lit_expr),
205 dest.to_str(bcx.ccx()));
211 let bytes = str_lit.get().len();
212 let llbytes = C_uint(bcx.ccx(), bytes);
213 let llcstr = C_cstr(bcx.ccx(), str_lit, false);
214 let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
216 GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
218 GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
226 pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
227 vstore_expr: &ast::Expr,
228 content_expr: &ast::Expr)
229 -> DatumBlock<'a, Expr> {
231 * ~[...] and "...".to_string() allocate boxes in the exchange heap and write
232 * the array elements into them.
235 debug!("trans_uniq_vstore(vstore_expr={})", bcx.expr_to_str(vstore_expr));
239 // Handle "".to_string().
240 match content_expr.node {
241 ast::ExprLit(lit) => {
243 ast::LitStr(ref s, _) => {
244 let llptrval = C_cstr(ccx, (*s).clone(), false);
245 let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx));
246 let llsizeval = C_uint(ccx, s.get().len());
247 let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx()));
248 let lldestval = rvalue_scratch_datum(bcx,
251 let alloc_fn = langcall(bcx,
254 StrDupUniqFnLangItem);
255 let bcx = callee::trans_lang_call(
258 [ llptrval, llsizeval ],
259 Some(expr::SaveIn(lldestval.val))).bcx;
260 return DatumBlock::new(bcx, lldestval).to_expr_datumblock();
268 let vec_ty = node_id_type(bcx, vstore_expr.id);
269 let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
270 let count = elements_required(bcx, content_expr);
272 let llunitty = type_of::type_of(ccx, vt.unit_ty);
273 let unit_sz = nonzero_llsize_of(ccx, llunitty);
275 let fill = Mul(bcx, C_uint(ccx, count), unit_sz);
276 let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
279 let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
281 // ~[T] is not going to be changed to support alignment, since it's obsolete.
282 let align = C_uint(ccx, 8);
283 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
284 Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
285 Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
287 // Create a temporary scope lest execution should fail while
288 // constructing the vector.
289 let temp_scope = fcx.push_custom_cleanup_scope();
291 // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder
292 let content_ty = vt.unit_ty;
293 fcx.schedule_free_value(cleanup::CustomScope(temp_scope),
294 val, cleanup::HeapExchange, content_ty);
296 let dataptr = get_dataptr(bcx, val);
298 debug!("alloc_uniq_vec() returned val={}, dataptr={}",
299 bcx.val_to_str(val), bcx.val_to_str(dataptr));
301 let bcx = write_content(bcx, &vt, vstore_expr,
302 content_expr, SaveIn(dataptr));
304 fcx.pop_custom_cleanup_scope(temp_scope);
306 immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock()
309 pub fn write_content<'a>(
312 vstore_expr: &ast::Expr,
313 content_expr: &ast::Expr,
316 let _icx = push_ctxt("tvec::write_content");
320 debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
321 vt.to_str(bcx.ccx()),
322 dest.to_str(bcx.ccx()),
323 bcx.expr_to_str(vstore_expr));
325 match content_expr.node {
326 ast::ExprLit(lit) => {
328 ast::LitStr(ref s, _) => {
330 Ignore => return bcx,
332 let bytes = s.get().len();
333 let llbytes = C_uint(bcx.ccx(), bytes);
334 let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
335 base::call_memcpy(bcx,
345 bcx.tcx().sess.span_bug(content_expr.span,
346 "unexpected evec content");
350 ast::ExprVec(ref elements) => {
353 for element in elements.iter() {
354 bcx = expr::trans_into(bcx, &**element, Ignore);
359 let temp_scope = fcx.push_custom_cleanup_scope();
360 for (i, element) in elements.iter().enumerate() {
361 let lleltptr = GEPi(bcx, lldest, [i]);
362 debug!("writing index {:?} with lleltptr={:?}",
363 i, bcx.val_to_str(lleltptr));
364 bcx = expr::trans_into(bcx, &**element,
366 fcx.schedule_drop_mem(
367 cleanup::CustomScope(temp_scope),
371 fcx.pop_custom_cleanup_scope(temp_scope);
376 ast::ExprRepeat(ref element, ref count_expr) => {
379 return expr::trans_into(bcx, &**element, Ignore);
382 let count = ty::eval_repeat_count(bcx.tcx(), &**count_expr);
387 // Some cleanup would be required in the case in which failure happens
388 // during a copy. But given that copy constructors are not overridable,
389 // this can only happen as a result of OOM. So we just skip out on the
390 // cleanup since things would *probably* be broken at that point anyways.
392 let elem = unpack_datum!(bcx, expr::trans(bcx, &**element));
393 assert!(!ty::type_moves_by_default(bcx.tcx(), elem.ty));
395 let bcx = iter_vec_loop(bcx, lldest, vt,
396 C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
397 elem.shallow_copy_and_take(set_bcx, lleltptr)
400 elem.add_clean_if_rvalue(bcx, element.id);
406 bcx.tcx().sess.span_bug(content_expr.span,
407 "unexpected vec content");
412 pub fn vec_types_from_expr(bcx: &Block, vec_expr: &ast::Expr) -> VecTypes {
413 let vec_ty = node_id_type(bcx, vec_expr.id);
414 vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty))
417 pub fn vec_types(bcx: &Block, unit_ty: ty::t) -> VecTypes {
419 let llunit_ty = type_of::type_of(ccx, unit_ty);
420 let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
421 let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
425 llunit_ty: llunit_ty,
426 llunit_size: llunit_size,
427 llunit_alloc_size: llunit_alloc_size
431 pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint {
432 //! Figure out the number of elements we need to store this content
434 match content_expr.node {
435 ast::ExprLit(lit) => {
437 ast::LitStr(ref s, _) => s.get().len(),
439 bcx.tcx().sess.span_bug(content_expr.span,
440 "unexpected evec content")
444 ast::ExprVec(ref es) => es.len(),
445 ast::ExprRepeat(_, ref count_expr) => {
446 ty::eval_repeat_count(bcx.tcx(), &**count_expr)
448 _ => bcx.tcx().sess.span_bug(content_expr.span,
449 "unexpected vec content")
453 pub fn get_fixed_base_and_byte_len(bcx: &Block,
457 -> (ValueRef, ValueRef) {
459 * Converts a fixed-length vector into the slice pair.
460 * The vector should be stored in `llval` which should be by ref.
464 let vt = vec_types(bcx, unit_ty);
466 let base = GEPi(bcx, llval, [0u, 0u]);
467 let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size);
471 pub fn get_base_and_len(bcx: &Block,
474 -> (ValueRef, ValueRef) {
476 * Converts a vector into the slice pair. The vector should be
477 * stored in `llval` which should be by-reference. If you have a
478 * datum, you would probably prefer to call
479 * `Datum::get_base_and_len()` which will handle any conversions
485 match ty::get(vec_ty).sty {
486 ty::ty_vec(_, Some(n)) => {
487 let base = GEPi(bcx, llval, [0u, 0u]);
488 (base, C_uint(ccx, n))
490 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
491 ty::ty_vec(_, None) | ty::ty_str => {
492 assert!(!type_is_immediate(bcx.ccx(), vec_ty));
493 let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
494 let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
497 _ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"),
499 ty::ty_uniq(t) => match ty::get(t).sty {
500 ty::ty_vec(_, None) | ty::ty_str => {
501 assert!(type_is_immediate(bcx.ccx(), vec_ty));
502 let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
503 let body = Load(bcx, llval);
504 (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
506 _ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"),
508 _ => ccx.sess().bug("unexpected type in get_base_and_len"),
512 pub type iter_vec_block<'r,'b> =
513 |&'b Block<'b>, ValueRef, ty::t|: 'r -> &'b Block<'b>;
515 pub fn iter_vec_loop<'r,
521 f: iter_vec_block<'r,'b>)
523 let _icx = push_ctxt("tvec::iter_vec_loop");
526 let next_bcx = fcx.new_temp_block("expr_repeat: while next");
527 let loop_bcx = fcx.new_temp_block("expr_repeat");
528 let cond_bcx = fcx.new_temp_block("expr_repeat: loop cond");
529 let body_bcx = fcx.new_temp_block("expr_repeat: body: set");
530 let inc_bcx = fcx.new_temp_block("expr_repeat: body: inc");
531 Br(bcx, loop_bcx.llbb);
535 let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
536 Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
538 Br(loop_bcx, cond_bcx.llbb);
543 let lhs = Load(cond_bcx, loop_counter);
545 let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);
547 CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb);
551 let i = Load(body_bcx, loop_counter);
552 let lleltptr = if vt.llunit_alloc_size == 0 {
555 InBoundsGEP(body_bcx, data_ptr, [i])
557 let body_bcx = f(body_bcx, lleltptr, vt.unit_ty);
559 Br(body_bcx, inc_bcx.llbb);
563 let i = Load(inc_bcx, loop_counter);
564 let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
565 Store(inc_bcx, plusone, loop_counter);
567 Br(inc_bcx, cond_bcx.llbb);
573 pub fn iter_vec_raw<'r,
579 f: iter_vec_block<'r,'b>)
581 let _icx = push_ctxt("tvec::iter_vec_raw");
584 let vt = vec_types(bcx, unit_ty);
585 if vt.llunit_alloc_size == 0 {
586 // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
587 iter_vec_loop(bcx, data_ptr, &vt, fill, f)
589 // Calculate the last pointer address we want to handle.
590 // FIXME (#3729): Optimize this when the size of the unit type is
591 // statically known to not use pointer casts, which tend to confuse
593 let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
595 // Now perform the iteration.
596 let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
597 Br(bcx, header_bcx.llbb);
599 Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
601 ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
602 let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
603 let next_bcx = fcx.new_temp_block("iter_vec_next");
604 CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
605 let body_bcx = f(body_bcx, data_ptr, vt.unit_ty);
606 AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
607 [C_int(bcx.ccx(), 1)]),
609 Br(body_bcx, header_bcx.llbb);