2012-09-04 13:54:36 -05:00
|
|
|
use syntax::ast;
|
|
|
|
use lib::llvm::{ValueRef, TypeRef};
|
|
|
|
use back::abi;
|
|
|
|
use syntax::codemap::span;
|
|
|
|
use shape::llsize_of;
|
|
|
|
use build::*;
|
|
|
|
use common::*;
|
|
|
|
use util::ppaux::ty_to_str;
|
2012-08-28 17:54:45 -05:00
|
|
|
use expr::{Dest, SaveIn, Ignore};
|
|
|
|
use datum::*;
|
|
|
|
use syntax::print::pprust::{expr_to_str};
|
|
|
|
use util::common::indenter;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-06-14 19:34:06 -05:00
|
|
|
// Boxed vector types are in some sense currently a "shorthand" for a box
|
|
|
|
// containing an unboxed vector. This expands a boxed vector type into such an
|
|
|
|
// expanded type. It doesn't respect mutability, but that doesn't matter at
|
|
|
|
// this point.
|
|
|
|
fn expand_boxed_vec_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
|
|
|
|
let unit_ty = ty::sequence_element_type(tcx, t);
|
|
|
|
let unboxed_vec_ty = ty::mk_mut_unboxed_vec(tcx, unit_ty);
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(t).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) => {
|
2012-06-14 19:34:06 -05:00
|
|
|
ty::mk_imm_uniq(tcx, unboxed_vec_ty)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
|
2012-06-14 19:34:06 -05:00
|
|
|
ty::mk_imm_box(tcx, unboxed_vec_ty)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => tcx.sess.bug(~"non boxed-vec type \
|
|
|
|
in tvec::expand_boxed_vec_ty")
|
2012-06-14 19:34:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::get_fill");
|
2012-08-27 14:16:37 -05:00
|
|
|
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2012-03-22 10:02:34 -05:00
|
|
|
fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
|
2012-08-27 14:16:37 -05:00
|
|
|
Store(bcx, fill, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]));
|
2012-03-22 10:02:34 -05:00
|
|
|
}
|
|
|
|
fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
|
2012-08-27 14:16:37 -05:00
|
|
|
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_alloc]))
|
2012-03-22 10:02:34 -05:00
|
|
|
}
|
2012-05-21 20:36:52 -05:00
|
|
|
|
2012-06-12 18:41:20 -05:00
|
|
|
fn get_bodyptr(bcx: block, vptr: ValueRef) -> ValueRef {
|
2012-08-28 17:54:45 -05:00
|
|
|
base::non_gc_box_cast(bcx, GEPi(bcx, vptr, [0u, abi::box_field_body]))
|
2012-05-21 20:36:52 -05:00
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn get_dataptr(bcx: block, vptr: ValueRef) -> ValueRef {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::get_dataptr");
|
2012-08-27 14:16:37 -05:00
|
|
|
GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::pointer_add");
|
2011-08-25 03:18:02 -05:00
|
|
|
let old_ty = val_ty(ptr);
|
|
|
|
let bptr = PointerCast(bcx, ptr, T_ptr(T_i8()));
|
2012-08-01 19:30:05 -05:00
|
|
|
return PointerCast(bcx, InBoundsGEP(bcx, bptr, ~[bytes]), old_ty);
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-06-14 19:34:06 -05:00
|
|
|
fn alloc_raw(bcx: block, unit_ty: ty::t,
|
2012-08-28 17:54:45 -05:00
|
|
|
fill: ValueRef, alloc: ValueRef, heap: heap) -> Result {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-06-12 16:54:02 -05:00
|
|
|
|
|
|
|
let vecbodyty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty);
|
|
|
|
let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
|
|
|
|
|
2012-07-17 12:48:19 -05:00
|
|
|
let {bcx, box, body} =
|
|
|
|
base::malloc_general_dyn(bcx, vecbodyty, heap, vecsize);
|
2012-08-27 14:16:37 -05:00
|
|
|
Store(bcx, fill, GEPi(bcx, body, [0u, abi::vec_elt_fill]));
|
|
|
|
Store(bcx, alloc, GEPi(bcx, body, [0u, abi::vec_elt_alloc]));
|
2012-08-28 17:54:45 -05:00
|
|
|
return rslt(bcx, box);
|
2011-08-29 15:30:18 -05:00
|
|
|
}
|
2012-06-14 19:34:06 -05:00
|
|
|
fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
|
2012-08-28 17:54:45 -05:00
|
|
|
fill: ValueRef, alloc: ValueRef) -> Result {
|
2012-06-14 19:34:06 -05:00
|
|
|
alloc_raw(bcx, unit_ty, fill, alloc, heap_exchange)
|
|
|
|
}
|
2011-08-29 15:30:18 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn alloc_vec(bcx: block, unit_ty: ty::t, elts: uint, heap: heap) -> Result {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-05-21 20:36:52 -05:00
|
|
|
let llunitty = type_of::type_of(ccx, unit_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
let unit_sz = llsize_of(ccx, llunitty);
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2011-10-14 22:38:24 -05:00
|
|
|
let fill = Mul(bcx, C_uint(ccx, elts), unit_sz);
|
2012-03-12 04:05:15 -05:00
|
|
|
let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
|
|
|
|
else { fill };
|
2012-08-28 17:54:45 -05:00
|
|
|
let Result {bcx: bcx, val: vptr} =
|
|
|
|
alloc_raw(bcx, unit_ty, fill, alloc, heap);
|
|
|
|
return rslt(bcx, vptr);
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2011-08-29 15:30:18 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::duplicate_uniq");
|
2012-05-21 20:36:52 -05:00
|
|
|
|
2012-06-13 12:46:33 -05:00
|
|
|
let fill = get_fill(bcx, get_bodyptr(bcx, vptr));
|
2012-02-21 07:20:18 -06:00
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2012-08-28 17:54:45 -05:00
|
|
|
let Result {bcx, val: newptr} = alloc_uniq_raw(bcx, unit_ty, fill, fill);
|
2012-06-13 12:46:33 -05:00
|
|
|
|
|
|
|
let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
|
|
|
|
let new_data_ptr = get_dataptr(bcx, get_bodyptr(bcx, newptr));
|
2012-11-16 13:26:26 -06:00
|
|
|
base::call_memcpy(bcx, new_data_ptr, data_ptr, fill);
|
2012-05-21 20:36:52 -05:00
|
|
|
|
2012-03-23 08:45:47 -05:00
|
|
|
let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
|
2012-08-28 17:54:45 -05:00
|
|
|
iter_vec_raw(bcx, new_data_ptr, vec_ty, fill, glue::take_ty)
|
2012-03-23 08:45:47 -05:00
|
|
|
} else { bcx };
|
2012-08-01 19:30:05 -05:00
|
|
|
return rslt(bcx, newptr);
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2012-06-14 19:34:06 -05:00
|
|
|
|
|
|
|
fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
|
2012-02-17 06:17:40 -06:00
|
|
|
block {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::make_drop_glue_unboxed");
|
2012-02-21 07:20:18 -06:00
|
|
|
let tcx = bcx.tcx(), unit_ty = ty::sequence_element_type(tcx, vec_ty);
|
2012-06-14 19:34:06 -05:00
|
|
|
if ty::type_needs_drop(tcx, unit_ty) {
|
2012-08-28 17:54:45 -05:00
|
|
|
iter_vec_unboxed(bcx, vptr, vec_ty, glue::drop_ty)
|
2012-06-14 19:34:06 -05:00
|
|
|
} else { bcx }
|
2011-08-22 15:30:53 -05:00
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
struct VecTypes {
|
2012-09-07 16:50:47 -05:00
|
|
|
vec_ty: ty::t,
|
|
|
|
unit_ty: ty::t,
|
|
|
|
llunit_ty: TypeRef,
|
|
|
|
llunit_size: ValueRef
|
2012-08-03 20:48:17 -05:00
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
impl VecTypes {
|
|
|
|
fn to_str(ccx: @crate_ctxt) -> ~str {
|
|
|
|
fmt!("VecTypes {vec_ty=%s, unit_ty=%s, llunit_ty=%s, llunit_size=%s}",
|
|
|
|
ty_to_str(ccx.tcx, self.vec_ty),
|
|
|
|
ty_to_str(ccx.tcx, self.unit_ty),
|
|
|
|
ty_str(ccx.tn, self.llunit_ty),
|
|
|
|
val_str(ccx.tn, self.llunit_size))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_fixed_vstore(bcx: block,
|
|
|
|
vstore_expr: @ast::expr,
|
|
|
|
content_expr: @ast::expr,
|
|
|
|
dest: expr::Dest) -> block
|
|
|
|
{
|
|
|
|
//!
|
|
|
|
//
|
2012-10-09 23:28:04 -05:00
|
|
|
// [...] allocates a fixed-size array and moves it around "by value".
|
2012-08-28 17:54:45 -05:00
|
|
|
// In this case, it means that the caller has already given us a location
|
|
|
|
// to store the array of the suitable size, so all we have to do is
|
|
|
|
// generate the content.
|
|
|
|
|
|
|
|
debug!("trans_fixed_vstore(vstore_expr=%s, dest=%?)",
|
|
|
|
bcx.expr_to_str(vstore_expr), dest.to_str(bcx.ccx()));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
let vt = vec_types_from_expr(bcx, vstore_expr);
|
|
|
|
|
|
|
|
return match dest {
|
|
|
|
Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
// lldest will have type *[T x N], but we want the type *T,
|
|
|
|
// so use GEP to convert:
|
|
|
|
let lldest = GEPi(bcx, lldest, [0, 0]);
|
|
|
|
write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_slice_vstore(bcx: block,
|
|
|
|
vstore_expr: @ast::expr,
|
|
|
|
content_expr: @ast::expr,
|
|
|
|
dest: expr::Dest) -> block
|
|
|
|
{
|
|
|
|
//!
|
|
|
|
//
|
|
|
|
// &[...] allocates memory on the stack and writes the values into it,
|
|
|
|
// returning a slice (pair of ptr, len). &"..." is similar except that
|
|
|
|
// the memory can be statically allocated.
|
|
|
|
|
2012-03-15 08:47:03 -05:00
|
|
|
let ccx = bcx.ccx();
|
2012-08-03 20:48:17 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("trans_slice_vstore(vstore_expr=%s, dest=%s)",
|
|
|
|
bcx.expr_to_str(vstore_expr), dest.to_str(ccx));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
// Handle the &"..." case:
|
|
|
|
match content_expr.node {
|
|
|
|
ast::expr_lit(@{node: ast::lit_str(s), span: _}) => {
|
|
|
|
return trans_lit_str(bcx, content_expr, s, dest);
|
2011-09-27 03:50:18 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {}
|
2011-09-27 03:50:18 -05:00
|
|
|
}
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
// Handle the &[...] case:
|
|
|
|
let vt = vec_types_from_expr(bcx, vstore_expr);
|
|
|
|
let count = elements_required(bcx, content_expr);
|
|
|
|
debug!("vt=%s, count=%?", vt.to_str(ccx), count);
|
|
|
|
|
|
|
|
// Make a fixed-length backing array and allocate it on the stack.
|
|
|
|
let llcount = C_uint(ccx, count);
|
|
|
|
let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
|
|
|
|
|
|
|
|
// Arrange for the backing array to be cleaned up.
|
|
|
|
let fixed_ty = ty::mk_evec(bcx.tcx(),
|
|
|
|
{ty: vt.unit_ty, mutbl: ast::m_mutbl},
|
|
|
|
ty::vstore_fixed(count));
|
|
|
|
let llfixed_ty = T_ptr(type_of::type_of(bcx.ccx(), fixed_ty));
|
|
|
|
let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
|
|
|
|
add_clean(bcx, llfixed_casted, fixed_ty);
|
|
|
|
|
|
|
|
// Generate the content into the backing array.
|
|
|
|
let bcx = write_content(bcx, &vt, vstore_expr,
|
|
|
|
content_expr, SaveIn(llfixed));
|
|
|
|
|
|
|
|
// Finally, create the slice pair itself.
|
|
|
|
match dest {
|
|
|
|
Ignore => {}
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
|
|
|
|
let lllen = Mul(bcx, llcount, vt.llunit_size);
|
|
|
|
Store(bcx, lllen, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
|
|
|
|
}
|
2012-08-03 20:48:17 -05:00
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_lit_str(bcx: block,
|
|
|
|
lit_expr: @ast::expr,
|
|
|
|
lit_str: @~str,
|
|
|
|
dest: Dest) -> block
|
|
|
|
{
|
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Literal strings translate to slices into static memory. This is
|
|
|
|
// different from trans_slice_vstore() above because it does need to copy
|
|
|
|
// the content anywhere.
|
|
|
|
|
|
|
|
debug!("trans_lit_str(lit_expr=%s, dest=%s)",
|
|
|
|
bcx.expr_to_str(lit_expr),
|
|
|
|
dest.to_str(bcx.ccx()));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
match dest {
|
|
|
|
Ignore => bcx,
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
let bytes = lit_str.len() + 1; // count null-terminator too
|
|
|
|
let llbytes = C_uint(bcx.ccx(), bytes);
|
|
|
|
let llcstr = C_cstr(bcx.ccx(), *lit_str);
|
|
|
|
let llcstr = llvm::LLVMConstPointerCast(llcstr, T_ptr(T_i8()));
|
|
|
|
Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
|
|
|
|
Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn trans_uniq_or_managed_vstore(bcx: block,
|
|
|
|
heap: heap,
|
|
|
|
vstore_expr: @ast::expr,
|
|
|
|
content_expr: @ast::expr) -> DatumBlock
|
|
|
|
{
|
|
|
|
//!
|
|
|
|
//
|
|
|
|
// @[...] or ~[...] (also @"..." or ~"...") allocate boxes in the
|
|
|
|
// appropriate heap and write the array elements into them.
|
|
|
|
|
|
|
|
debug!("trans_uniq_or_managed_vstore(vstore_expr=%s, heap=%?)",
|
|
|
|
bcx.expr_to_str(vstore_expr), heap);
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
let vt = vec_types_from_expr(bcx, vstore_expr);
|
|
|
|
let count = elements_required(bcx, content_expr);
|
|
|
|
|
|
|
|
let Result {bcx, val} = alloc_vec(bcx, vt.unit_ty, count, heap);
|
|
|
|
add_clean_free(bcx, val, heap);
|
|
|
|
let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
|
|
|
|
|
|
|
|
debug!("alloc_vec() returned val=%s, dataptr=%s",
|
|
|
|
bcx.val_str(val), bcx.val_str(dataptr));
|
|
|
|
|
|
|
|
let bcx = write_content(bcx, &vt, vstore_expr,
|
|
|
|
content_expr, SaveIn(dataptr));
|
|
|
|
|
|
|
|
revoke_clean(bcx, val);
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
return immediate_rvalue_bcx(bcx, val, vt.vec_ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_content(bcx: block,
|
|
|
|
vt: &VecTypes,
|
|
|
|
vstore_expr: @ast::expr,
|
|
|
|
content_expr: @ast::expr,
|
|
|
|
dest: Dest) -> block
|
|
|
|
{
|
|
|
|
let _icx = bcx.insn_ctxt("tvec::write_content");
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
debug!("write_content(vt=%s, dest=%s, vstore_expr=%?)",
|
|
|
|
vt.to_str(bcx.ccx()),
|
|
|
|
dest.to_str(bcx.ccx()),
|
|
|
|
bcx.expr_to_str(vstore_expr));
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
match content_expr.node {
|
|
|
|
ast::expr_lit(@{node: ast::lit_str(s), span: _}) => {
|
|
|
|
match dest {
|
|
|
|
Ignore => {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
let bytes = s.len() + 1; // copy null-terminator too
|
|
|
|
let llbytes = C_uint(bcx.ccx(), bytes);
|
|
|
|
let llcstr = C_cstr(bcx.ccx(), *s);
|
2012-11-16 13:26:26 -06:00
|
|
|
base::call_memcpy(bcx, lldest, llcstr, llbytes);
|
2012-08-28 17:54:45 -05:00
|
|
|
return bcx;
|
|
|
|
}
|
2012-08-03 20:48:17 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
ast::expr_vec(elements, _) => {
|
|
|
|
match dest {
|
|
|
|
Ignore => {
|
|
|
|
for elements.each |element| {
|
2012-09-19 18:55:01 -05:00
|
|
|
bcx = expr::trans_into(bcx, *element, Ignore);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
let mut temp_cleanups = ~[];
|
|
|
|
for elements.eachi |i, element| {
|
|
|
|
let lleltptr = GEPi(bcx, lldest, [i]);
|
|
|
|
debug!("writing index %? with lleltptr=%?",
|
|
|
|
i, bcx.val_str(lleltptr));
|
2012-09-21 20:43:30 -05:00
|
|
|
bcx = expr::trans_into(bcx, *element,
|
2012-08-28 17:54:45 -05:00
|
|
|
SaveIn(lleltptr));
|
|
|
|
add_clean_temp_mem(bcx, lleltptr, vt.unit_ty);
|
2012-09-26 19:33:34 -05:00
|
|
|
temp_cleanups.push(lleltptr);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(temp_cleanups) |cleanup| {
|
2012-09-18 23:41:37 -05:00
|
|
|
revoke_clean(bcx, *cleanup);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-08-03 20:48:17 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
ast::expr_repeat(element, count_expr, _) => {
|
|
|
|
match dest {
|
|
|
|
Ignore => {
|
|
|
|
return expr::trans_into(bcx, element, Ignore);
|
|
|
|
}
|
|
|
|
SaveIn(lldest) => {
|
|
|
|
let count = ty::eval_repeat_count(bcx.tcx(), count_expr,
|
|
|
|
count_expr.span);
|
|
|
|
if count == 0 {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
let tmpdatum = unpack_datum!(bcx, {
|
|
|
|
expr::trans_to_datum(bcx, element)
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut temp_cleanups = ~[];
|
|
|
|
|
|
|
|
for uint::range(0, count) |i| {
|
|
|
|
let lleltptr = GEPi(bcx, lldest, [i]);
|
|
|
|
if i < count - 1 {
|
|
|
|
// Copy all but the last one in.
|
|
|
|
bcx = tmpdatum.copy_to(bcx, INIT, lleltptr);
|
|
|
|
} else {
|
|
|
|
// Move the last one in.
|
|
|
|
bcx = tmpdatum.move_to(bcx, INIT, lleltptr);
|
|
|
|
}
|
|
|
|
add_clean_temp_mem(bcx, lleltptr, vt.unit_ty);
|
2012-09-26 19:33:34 -05:00
|
|
|
temp_cleanups.push(lleltptr);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(temp_cleanups) |cleanup| {
|
2012-09-18 23:41:37 -05:00
|
|
|
revoke_clean(bcx, *cleanup);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.span_bug(content_expr.span,
|
|
|
|
~"Unexpected evec content");
|
2012-08-03 20:48:17 -05:00
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn vec_types_from_expr(bcx: block, vec_expr: @ast::expr) -> VecTypes {
|
|
|
|
let vec_ty = node_id_type(bcx, vec_expr.id);
|
|
|
|
vec_types(bcx, vec_ty)
|
|
|
|
}
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes {
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
|
|
|
let llunit_ty = type_of::type_of(ccx, unit_ty);
|
|
|
|
let llunit_size = llsize_of(ccx, llunit_ty);
|
|
|
|
VecTypes {vec_ty: vec_ty,
|
|
|
|
unit_ty: unit_ty,
|
|
|
|
llunit_ty: llunit_ty,
|
|
|
|
llunit_size: llunit_size}
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2011-09-27 13:21:44 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn elements_required(bcx: block, content_expr: @ast::expr) -> uint {
|
|
|
|
//! Figure out the number of elements we need to store this content
|
|
|
|
|
|
|
|
match content_expr.node {
|
|
|
|
ast::expr_lit(@{node: ast::lit_str(s), span: _}) => s.len() + 1,
|
|
|
|
ast::expr_vec(es, _) => es.len(),
|
|
|
|
ast::expr_repeat(_, count_expr, _) => {
|
|
|
|
ty::eval_repeat_count(bcx.tcx(), count_expr, content_expr.span)
|
|
|
|
}
|
|
|
|
_ => bcx.tcx().sess.span_bug(content_expr.span,
|
|
|
|
~"Unexpected evec content")
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
fn get_base_and_len(bcx: block,
|
|
|
|
llval: ValueRef,
|
|
|
|
vec_ty: ty::t) -> (ValueRef, ValueRef) {
|
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Converts a vector into the slice pair. The vector should be stored in
|
|
|
|
// `llval` which should be either immediate or by-ref as appropriate for
|
|
|
|
// the vector type. If you have a datum, you would probably prefer to
|
|
|
|
// call `Datum::get_base_and_len()` which will handle any conversions for
|
|
|
|
// you.
|
2012-04-17 17:07:38 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let vt = vec_types(bcx, vec_ty);
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-09-11 18:20:31 -05:00
|
|
|
let vstore = match ty::get(vt.vec_ty).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_estr(vst) | ty::ty_evec(_, vst) => vst,
|
|
|
|
_ => ty::vstore_uniq
|
2012-04-17 17:07:38 -05:00
|
|
|
};
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match vstore {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::vstore_fixed(n) => {
|
|
|
|
let base = GEPi(bcx, llval, [0u, 0u]);
|
|
|
|
let n = if ty::type_is_str(vec_ty) { n + 1u } else { n };
|
|
|
|
let len = Mul(bcx, C_uint(ccx, n), vt.llunit_size);
|
|
|
|
(base, len)
|
|
|
|
}
|
|
|
|
ty::vstore_slice(_) => {
|
|
|
|
let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
|
|
|
|
let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
|
|
|
|
(base, len)
|
|
|
|
}
|
|
|
|
ty::vstore_uniq | ty::vstore_box => {
|
|
|
|
let body = tvec::get_bodyptr(bcx, llval);
|
|
|
|
(tvec::get_dataptr(bcx, body), tvec::get_fill(bcx, body))
|
|
|
|
}
|
2012-04-17 17:07:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
type val_and_ty_fn = fn@(block, ValueRef, ty::t) -> Result;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
type iter_vec_block = fn(block, ValueRef, ty::t) -> block;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-04-19 17:42:02 -05:00
|
|
|
fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t,
|
2012-02-17 06:17:40 -06:00
|
|
|
fill: ValueRef, f: iter_vec_block) -> block {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::iter_vec_raw");
|
2012-04-19 17:42:02 -05:00
|
|
|
|
2012-02-21 07:20:18 -06:00
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2011-08-25 03:18:02 -05:00
|
|
|
|
|
|
|
// Calculate the last pointer address we want to handle.
|
2012-10-11 18:42:40 -05:00
|
|
|
// FIXME (#3729): Optimize this when the size of the unit type is
|
2012-06-21 18:44:10 -05:00
|
|
|
// statically known to not use pointer casts, which tend to confuse
|
|
|
|
// LLVM.
|
2011-08-25 03:18:02 -05:00
|
|
|
let data_end_ptr = pointer_add(bcx, data_ptr, fill);
|
|
|
|
|
|
|
|
// Now perform the iteration.
|
2012-08-28 17:54:45 -05:00
|
|
|
let header_bcx = base::sub_block(bcx, ~"iter_vec_loop_header");
|
|
|
|
Br(bcx, header_bcx.llbb);
|
2012-06-25 22:00:46 -05:00
|
|
|
let data_ptr =
|
2012-08-28 17:54:45 -05:00
|
|
|
Phi(header_bcx, val_ty(data_ptr), ~[data_ptr], ~[bcx.llbb]);
|
2011-09-02 17:34:58 -05:00
|
|
|
let not_yet_at_end =
|
2012-08-28 17:54:45 -05:00
|
|
|
ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
|
|
|
|
let body_bcx = base::sub_block(header_bcx, ~"iter_vec_loop_body");
|
|
|
|
let next_bcx = base::sub_block(header_bcx, ~"iter_vec_next");
|
|
|
|
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
|
|
|
|
let body_bcx = f(body_bcx, data_ptr, unit_ty);
|
|
|
|
AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
|
2012-06-29 18:26:56 -05:00
|
|
|
~[C_int(bcx.ccx(), 1)]),
|
2012-08-28 17:54:45 -05:00
|
|
|
body_bcx.llbb);
|
|
|
|
Br(body_bcx, header_bcx.llbb);
|
|
|
|
return next_bcx;
|
2012-04-19 17:42:02 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t,
|
|
|
|
fill: ValueRef, f: iter_vec_block) -> block {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::iter_vec_uniq");
|
2012-06-12 18:41:20 -05:00
|
|
|
let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
|
2012-04-19 17:42:02 -05:00
|
|
|
iter_vec_raw(bcx, data_ptr, vec_ty, fill, f)
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2012-06-14 19:34:06 -05:00
|
|
|
fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t,
|
|
|
|
f: iter_vec_block) -> block {
|
2012-08-14 18:45:43 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::iter_vec_unboxed");
|
2012-06-14 19:34:06 -05:00
|
|
|
let fill = get_fill(bcx, body_ptr);
|
|
|
|
let dataptr = get_dataptr(bcx, body_ptr);
|
2012-08-01 19:30:05 -05:00
|
|
|
return iter_vec_raw(bcx, dataptr, vec_ty, fill, f);
|
2011-08-29 09:14:24 -05:00
|
|
|
}
|
|
|
|
|
2011-08-24 06:53:34 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|