1 // Copyright 2012 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.
14 use lib::llvm::{llvm, ValueRef, TypeRef};
15 use middle::trans::base;
16 use middle::trans::base::*;
17 use middle::trans::build::*;
18 use middle::trans::callee;
19 use middle::trans::common::*;
20 use middle::trans::datum::*;
21 use middle::trans::expr::{Dest, Ignore, SaveIn};
22 use middle::trans::expr;
23 use middle::trans::glue;
24 use middle::trans::machine::{llsize_of, nonzero_llsize_of};
25 use middle::trans::type_of;
27 use util::common::indenter;
28 use util::ppaux::ty_to_str;
35 // Boxed vector types are in some sense currently a "shorthand" for a box
36 // containing an unboxed vector. This expands a boxed vector type into such an
37 // expanded type. It doesn't respect mutability, but that doesn't matter at
39 pub fn expand_boxed_vec_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
40 let unit_ty = ty::sequence_element_type(tcx, t);
41 let unboxed_vec_ty = ty::mk_mut_unboxed_vec(tcx, unit_ty);
42 match ty::get(t).sty {
43 ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) => {
44 ty::mk_imm_uniq(tcx, unboxed_vec_ty)
46 ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
47 ty::mk_imm_box(tcx, unboxed_vec_ty)
49 _ => tcx.sess.bug(~"non boxed-vec type \
50 in tvec::expand_boxed_vec_ty")
54 pub fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef {
55 let _icx = bcx.insn_ctxt("tvec::get_fill");
56 Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
58 pub fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
59 Store(bcx, fill, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]));
61 pub fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
62 Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_alloc]))
65 pub fn get_bodyptr(bcx: block, vptr: ValueRef) -> ValueRef {
66 base::non_gc_box_cast(bcx, GEPi(bcx, vptr, [0u, abi::box_field_body]))
69 pub fn get_dataptr(bcx: block, vptr: ValueRef) -> ValueRef {
70 let _icx = bcx.insn_ctxt("tvec::get_dataptr");
71 GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
74 pub fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
75 let _icx = bcx.insn_ctxt("tvec::pointer_add");
76 let old_ty = val_ty(ptr);
77 let bptr = PointerCast(bcx, ptr, T_ptr(T_i8()));
78 return PointerCast(bcx, InBoundsGEP(bcx, bptr, ~[bytes]), old_ty);
81 pub fn alloc_raw(bcx: block, unit_ty: ty::t,
82 fill: ValueRef, alloc: ValueRef, heap: heap) -> Result {
83 let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
86 let vecbodyty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty);
87 let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
89 let base::MallocResult {bcx, box: bx, body} =
90 base::malloc_general_dyn(bcx, vecbodyty, heap, vecsize);
91 Store(bcx, fill, GEPi(bcx, body, [0u, abi::vec_elt_fill]));
92 Store(bcx, alloc, GEPi(bcx, body, [0u, abi::vec_elt_alloc]));
93 base::maybe_set_managed_unique_rc(bcx, bx, heap);
97 pub fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
98 fill: ValueRef, alloc: ValueRef) -> Result {
99 alloc_raw(bcx, unit_ty, fill, alloc, base::heap_for_unique(bcx, unit_ty))
102 pub fn alloc_vec(bcx: block,
107 let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
109 let llunitty = type_of::type_of(ccx, unit_ty);
110 let unit_sz = nonzero_llsize_of(ccx, llunitty);
112 let fill = Mul(bcx, C_uint(ccx, elts), unit_sz);
113 let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
115 let Result {bcx: bcx, val: vptr} =
116 alloc_raw(bcx, unit_ty, fill, alloc, heap);
117 return rslt(bcx, vptr);
120 pub fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result {
121 let _icx = bcx.insn_ctxt("tvec::duplicate_uniq");
123 let fill = get_fill(bcx, get_bodyptr(bcx, vptr));
124 let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
125 let Result {bcx, val: newptr} = alloc_uniq_raw(bcx, unit_ty, fill, fill);
127 let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
128 let new_data_ptr = get_dataptr(bcx, get_bodyptr(bcx, newptr));
129 base::call_memcpy(bcx, new_data_ptr, data_ptr, fill);
131 let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
132 iter_vec_raw(bcx, new_data_ptr, vec_ty, fill, glue::take_ty)
134 return rslt(bcx, newptr);
137 pub fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
139 let _icx = bcx.insn_ctxt("tvec::make_drop_glue_unboxed");
140 let tcx = bcx.tcx(), unit_ty = ty::sequence_element_type(tcx, vec_ty);
141 if ty::type_needs_drop(tcx, unit_ty) {
142 iter_vec_unboxed(bcx, vptr, vec_ty, glue::drop_ty)
146 pub struct VecTypes {
150 llunit_size: ValueRef
154 fn to_str(&self, ccx: @CrateContext) -> ~str {
155 fmt!("VecTypes {vec_ty=%s, unit_ty=%s, llunit_ty=%s, llunit_size=%s}",
156 ty_to_str(ccx.tcx, self.vec_ty),
157 ty_to_str(ccx.tcx, self.unit_ty),
158 ty_str(ccx.tn, self.llunit_ty),
159 val_str(ccx.tn, self.llunit_size))
163 pub fn trans_fixed_vstore(bcx: block,
164 vstore_expr: @ast::expr,
165 content_expr: @ast::expr,
170 // [...] allocates a fixed-size array and moves it around "by value".
171 // In this case, it means that the caller has already given us a location
172 // to store the array of the suitable size, so all we have to do is
173 // generate the content.
175 debug!("trans_fixed_vstore(vstore_expr=%s, dest=%?)",
176 bcx.expr_to_str(vstore_expr), dest.to_str(bcx.ccx()));
177 let _indenter = indenter();
179 let vt = vec_types_from_expr(bcx, vstore_expr);
182 Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
184 // lldest will have type *[T x N], but we want the type *T,
185 // so use GEP to convert:
186 let lldest = GEPi(bcx, lldest, [0, 0]);
187 write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
192 pub fn trans_slice_vstore(bcx: block,
193 vstore_expr: @ast::expr,
194 content_expr: @ast::expr,
199 // &[...] allocates memory on the stack and writes the values into it,
200 // returning a slice (pair of ptr, len). &"..." is similar except that
201 // the memory can be statically allocated.
205 debug!("trans_slice_vstore(vstore_expr=%s, dest=%s)",
206 bcx.expr_to_str(vstore_expr), dest.to_str(ccx));
207 let _indenter = indenter();
209 // Handle the &"..." case:
210 match content_expr.node {
211 ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), span: _}) => {
212 return trans_lit_str(bcx, content_expr, s, dest);
217 // Handle the &[...] case:
218 let vt = vec_types_from_expr(bcx, vstore_expr);
219 let count = elements_required(bcx, content_expr);
220 debug!("vt=%s, count=%?", vt.to_str(ccx), count);
222 // Make a fixed-length backing array and allocate it on the stack.
223 let llcount = C_uint(ccx, count);
224 let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
226 // Arrange for the backing array to be cleaned up.
227 let fixed_ty = ty::mk_evec(bcx.tcx(),
228 ty::mt {ty: vt.unit_ty, mutbl: ast::m_mutbl},
229 ty::vstore_fixed(count));
230 let llfixed_ty = T_ptr(type_of::type_of(bcx.ccx(), fixed_ty));
231 let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
232 add_clean(bcx, llfixed_casted, fixed_ty);
234 // Generate the content into the backing array.
235 let bcx = write_content(bcx, &vt, vstore_expr,
236 content_expr, SaveIn(llfixed));
238 // Finally, create the slice pair itself.
242 Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
243 let lllen = Mul(bcx, llcount, vt.llunit_size);
244 Store(bcx, lllen, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
251 pub fn trans_lit_str(bcx: block,
252 lit_expr: @ast::expr,
258 // Literal strings translate to slices into static memory. This is
259 // different from trans_slice_vstore() above because it does need to copy
260 // the content anywhere.
262 debug!("trans_lit_str(lit_expr=%s, dest=%s)",
263 bcx.expr_to_str(lit_expr),
264 dest.to_str(bcx.ccx()));
265 let _indenter = indenter();
271 let bytes = str_lit.len() + 1; // count null-terminator too
272 let llbytes = C_uint(bcx.ccx(), bytes);
273 let llcstr = C_cstr(bcx.ccx(), str_lit);
274 let llcstr = llvm::LLVMConstPointerCast(llcstr,
278 GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
281 GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
289 pub fn trans_uniq_or_managed_vstore(bcx: block,
291 vstore_expr: @ast::expr,
292 content_expr: @ast::expr) -> DatumBlock {
295 // @[...] or ~[...] (also @"..." or ~"...") allocate boxes in the
296 // appropriate heap and write the array elements into them.
298 debug!("trans_uniq_or_managed_vstore(vstore_expr=%s, heap=%?)",
299 bcx.expr_to_str(vstore_expr), heap);
300 let _indenter = indenter();
305 match content_expr.node {
306 ast::expr_lit(@codemap::spanned {
307 node: ast::lit_str(s), _
309 let llptrval = C_cstr(bcx.ccx(), s);
310 let llptrval = PointerCast(bcx, llptrval, T_ptr(T_i8()));
311 let llsizeval = C_uint(bcx.ccx(), s.len());
312 let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq);
313 let lldestval = scratch_datum(bcx, typ, false);
314 let bcx = callee::trans_lang_call(
316 bcx.tcx().lang_items.strdup_uniq_fn(),
317 ~[ llptrval, llsizeval ],
318 expr::SaveIn(lldestval.to_ref_llval(bcx)));
327 heap_managed | heap_managed_unique => {}
330 let vt = vec_types_from_expr(bcx, vstore_expr);
331 let count = elements_required(bcx, content_expr);
333 let Result {bcx, val} = alloc_vec(bcx, vt.unit_ty, count, heap);
335 add_clean_free(bcx, val, heap);
336 let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
338 debug!("alloc_vec() returned val=%s, dataptr=%s",
339 bcx.val_str(val), bcx.val_str(dataptr));
341 let bcx = write_content(bcx, &vt, vstore_expr,
342 content_expr, SaveIn(dataptr));
344 revoke_clean(bcx, val);
346 return immediate_rvalue_bcx(bcx, val, vt.vec_ty);
349 pub fn write_content(bcx: block,
351 vstore_expr: @ast::expr,
352 content_expr: @ast::expr,
355 let _icx = bcx.insn_ctxt("tvec::write_content");
358 debug!("write_content(vt=%s, dest=%s, vstore_expr=%?)",
359 vt.to_str(bcx.ccx()),
360 dest.to_str(bcx.ccx()),
361 bcx.expr_to_str(vstore_expr));
362 let _indenter = indenter();
364 match content_expr.node {
365 ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
371 let bytes = s.len() + 1; // copy null-terminator too
372 let llbytes = C_uint(bcx.ccx(), bytes);
373 let llcstr = C_cstr(bcx.ccx(), s);
374 base::call_memcpy(bcx, lldest, llcstr, llbytes);
379 ast::expr_vec(ref elements, _) => {
382 for elements.each |element| {
383 bcx = expr::trans_into(bcx, *element, Ignore);
388 let mut temp_cleanups = ~[];
389 for elements.eachi |i, element| {
390 let lleltptr = GEPi(bcx, lldest, [i]);
391 debug!("writing index %? with lleltptr=%?",
392 i, bcx.val_str(lleltptr));
393 bcx = expr::trans_into(bcx, *element,
395 add_clean_temp_mem(bcx, lleltptr, vt.unit_ty);
396 temp_cleanups.push(lleltptr);
398 for vec::each(temp_cleanups) |cleanup| {
399 revoke_clean(bcx, *cleanup);
405 ast::expr_repeat(element, count_expr, _) => {
408 return expr::trans_into(bcx, element, Ignore);
411 let count = ty::eval_repeat_count(bcx.tcx(), count_expr);
416 let tmpdatum = unpack_datum!(bcx, {
417 expr::trans_to_datum(bcx, element)
420 let mut temp_cleanups = ~[];
422 for uint::range(0, count) |i| {
423 let lleltptr = GEPi(bcx, lldest, [i]);
425 // Copy all but the last one in.
426 bcx = tmpdatum.copy_to(bcx, INIT, lleltptr);
428 // Move the last one in.
429 bcx = tmpdatum.move_to(bcx, INIT, lleltptr);
431 add_clean_temp_mem(bcx, lleltptr, vt.unit_ty);
432 temp_cleanups.push(lleltptr);
435 for vec::each(temp_cleanups) |cleanup| {
436 revoke_clean(bcx, *cleanup);
444 bcx.tcx().sess.span_bug(content_expr.span,
445 ~"Unexpected evec content");
450 pub fn vec_types_from_expr(bcx: block, vec_expr: @ast::expr) -> VecTypes {
451 let vec_ty = node_id_type(bcx, vec_expr.id);
452 vec_types(bcx, vec_ty)
455 pub fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes {
457 let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
458 let llunit_ty = type_of::type_of(ccx, unit_ty);
459 let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
461 VecTypes {vec_ty: vec_ty,
463 llunit_ty: llunit_ty,
464 llunit_size: llunit_size}
467 pub fn elements_required(bcx: block, content_expr: @ast::expr) -> uint {
468 //! Figure out the number of elements we need to store this content
470 match content_expr.node {
471 ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
474 ast::expr_vec(ref es, _) => es.len(),
475 ast::expr_repeat(_, count_expr, _) => {
476 ty::eval_repeat_count(bcx.tcx(), count_expr)
478 _ => bcx.tcx().sess.span_bug(content_expr.span,
479 ~"Unexpected evec content")
483 pub fn get_base_and_len(bcx: block,
485 vec_ty: ty::t) -> (ValueRef, ValueRef) {
488 // Converts a vector into the slice pair. The vector should be stored in
489 // `llval` which should be either immediate or by-ref as appropriate for
490 // the vector type. If you have a datum, you would probably prefer to
491 // call `Datum::get_base_and_len()` which will handle any conversions for
495 let vt = vec_types(bcx, vec_ty);
497 let vstore = match ty::get(vt.vec_ty).sty {
498 ty::ty_estr(vst) | ty::ty_evec(_, vst) => vst,
503 ty::vstore_fixed(n) => {
504 let base = GEPi(bcx, llval, [0u, 0u]);
505 let n = if ty::type_is_str(vec_ty) { n + 1u } else { n };
506 let len = Mul(bcx, C_uint(ccx, n), vt.llunit_size);
509 ty::vstore_slice(_) => {
510 let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
511 let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
514 ty::vstore_uniq | ty::vstore_box => {
515 let body = get_bodyptr(bcx, llval);
516 (get_dataptr(bcx, body), get_fill(bcx, body))
521 pub type val_and_ty_fn = @fn(block, ValueRef, ty::t) -> Result;
523 pub type iter_vec_block = &'self fn(block, ValueRef, ty::t) -> block;
525 pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t,
526 fill: ValueRef, f: iter_vec_block) -> block {
527 let _icx = bcx.insn_ctxt("tvec::iter_vec_raw");
529 let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
531 // Calculate the last pointer address we want to handle.
532 // FIXME (#3729): Optimize this when the size of the unit type is
533 // statically known to not use pointer casts, which tend to confuse
535 let data_end_ptr = pointer_add(bcx, data_ptr, fill);
537 // Now perform the iteration.
538 let header_bcx = base::sub_block(bcx, ~"iter_vec_loop_header");
539 Br(bcx, header_bcx.llbb);
541 Phi(header_bcx, val_ty(data_ptr), ~[data_ptr], ~[bcx.llbb]);
543 ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
544 let body_bcx = base::sub_block(header_bcx, ~"iter_vec_loop_body");
545 let next_bcx = base::sub_block(header_bcx, ~"iter_vec_next");
546 CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
547 let body_bcx = f(body_bcx, data_ptr, unit_ty);
548 AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
549 ~[C_int(bcx.ccx(), 1)]),
551 Br(body_bcx, header_bcx.llbb);
556 pub fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t,
557 fill: ValueRef, f: iter_vec_block) -> block {
558 let _icx = bcx.insn_ctxt("tvec::iter_vec_uniq");
559 let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
560 iter_vec_raw(bcx, data_ptr, vec_ty, fill, f)
563 pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t,
564 f: iter_vec_block) -> block {
565 let _icx = bcx.insn_ctxt("tvec::iter_vec_unboxed");
566 let fill = get_fill(bcx, body_ptr);
567 let dataptr = get_dataptr(bcx, body_ptr);
568 return iter_vec_raw(bcx, dataptr, vec_ty, fill, f);
575 // indent-tabs-mode: nil
577 // buffer-file-coding-system: utf-8-unix