1
Fork 0

collapse sizeof, alignof into metrics, pass along an instance if avail

This commit is contained in:
Niko Matsakis 2012-01-05 12:05:22 -08:00
parent 4f52e5a5ec
commit 7db640e63d
3 changed files with 78 additions and 47 deletions

View file

@ -414,14 +414,26 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
False); False);
} }
fn size_of(cx: @block_ctxt, t: ty::t) -> result { fn size_of(bcx: @block_ctxt, t: ty::t) -> result {
let {bcx, sz, align} = metrics(cx, t, none); assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
rslt(bcx, align) let {bcx, sz, align: _} = metrics(bcx, t, none);
rslt(bcx, sz)
} }
fn align_of(cx: @block_ctxt, t: ty::t) -> result { fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
let {bcx, sz, align} = metrics(cx, t, none); assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
rslt(bcx, align) alt ty::struct(ccx.tcx, t) {
ty::ty_opaque_closure. {
// Hack: the alignment of an opaque closure is always defined as the
// alignment of a pointer. This is not, however, strictly correct,
// depending on your point of view.
llalign_of(bcx, T_ptr(T_i8()));
}
_ {
let {bcx, sz: _, align} = metrics(bcx, t, none);
rslt(bcx, align)
}
}
} }
// Computes the size/alignment of the type `t`. `opt_v`, if provided, should // Computes the size/alignment of the type `t`. `opt_v`, if provided, should
@ -431,11 +443,13 @@ fn align_of(cx: @block_ctxt, t: ty::t) -> result {
// instance is required. // instance is required.
fn metrics(bcx: @block_ctxt, t: ty::t, opt_v: option<ValueRef>) fn metrics(bcx: @block_ctxt, t: ty::t, opt_v: option<ValueRef>)
-> metrics_result { -> metrics_result {
let ccx = bcx_ccx(cx); assert (option::is_some(opt_v) ||
!ty::type_has_opaque_size(bcx_tcx(bcx), t));
let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, t) { if check type_has_static_size(ccx, t) {
let sp = cx.sp; let sp = bcx.sp;
let sz = llsize_of(bcx_ccx(cx), type_of(ccx, sp, t)); let sz = llsize_of(bcx_ccx(bcx), type_of(ccx, sp, t));
let align = llalign_of(bcx_ccx(cx), type_of(ccx, sp, t)); let align = llalign_of(bcx_ccx(bcx), type_of(ccx, sp, t));
ret {bcx: bcx, sz: sz, align: align}; ret {bcx: bcx, sz: sz, align: align};
} else { } else {
ret dynamic_metrics(bcx, t, opt_v); ret dynamic_metrics(bcx, t, opt_v);
@ -552,11 +566,11 @@ type metrics_result = {
}; };
fn dynamic_metrics(bcx: @block_ctxt, fn dynamic_metrics(bcx: @block_ctxt,
elts: [ty::t], t: ty::t,
opts_v: option<ValueRef>) -> metrics_result { opt_v: option<ValueRef>) -> metrics_result {
fn compute_elements_metrics(bcx: @block_ctxt, fn c_struct_metrics(bcx: @block_ctxt,
elts: [ty::t], elts: [ty::t],
opt_v: option<ValueRef>) -> metrics_result { opt_v: option<ValueRef>) -> metrics_result {
// //
// C padding rules: // C padding rules:
// //
@ -570,40 +584,40 @@ fn dynamic_metrics(bcx: @block_ctxt,
let max_align = C_int(bcx_ccx(bcx), 1); let max_align = C_int(bcx_ccx(bcx), 1);
for e: ty::t in elts { for e: ty::t in elts {
let opt_ev = option::map(opt_v) {|v| ptr_offs(bcx, v, off) }; let opt_ev = option::map(opt_v) {|v| ptr_offs(bcx, v, off) };
let elt_align = align_of(bcx, e, opt_ev); let elt_metrics = metrics(bcx, e, opt_ev);
bcx = elt_align.bcx; bcx = elt_metrics.bcx;
let elt_size = size_of(bcx, e, opt_ev); let aligned_off = align_to(bcx, off, elt_metrics.align);
bcx = elt_size.bcx; off = Add(bcx, aligned_off, elt_metrics.sz);
let aligned_off = align_to(bcx, off, elt_align.val); max_align = umax(bcx, max_align, elt_metrics.align);
off = Add(bcx, aligned_off, elt_size.val);
max_align = umax(bcx, max_align, elt_align.val);
} }
off = align_to(bcx, off, max_align);
ret { bcx: bcx, sz: off, align: max_align }; ret { bcx: bcx, sz: off, align: max_align };
} }
alt ty::struct(bcx_tcx(bcx), t) { alt ty::struct(bcx_tcx(bcx), t) {
ty::ty_param(p, _) { ty::ty_param(p, _) {
let {bcx, value: szptr} = let ti = none::<@tydesc_info>;
field_of_tydesc(bcx, t, false, abi::tydesc_field_size); let {bcx, val: tydesc} =
let {bcx, value: aptr} = get_tydesc(bcx, t, false, tps_normal, ti).result;
field_of_tydesc(bcx, t, false, abi::tydesc_field_align); let sz = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_size]));
ret { bcx: bcx, sz: Load(szptr), align: Load(align) }; let al = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_align]));
ret { bcx: bcx, sz: sz, align: al };
} }
ty::ty_rec(flds) { ty::ty_rec(flds) {
let tys: [ty::t] = []; let tys: [ty::t] = [];
for f: ty::field in flds { tys += [f.mt.ty]; } for f: ty::field in flds { tys += [f.mt.ty]; }
ret compute_elements_metrics(bcx, tys, opt_v); ret c_struct_metrics(bcx, tys, opt_v);
} }
ty::ty_tup(elts) { ty::ty_tup(elts) {
let tys = []; let tys = [];
for tp in elts { tys += [tp]; } for tp in elts { tys += [tp]; }
ret compute_elements_metrics(bcx, tys, opt_v); ret c_struct_metrics(bcx, tys, opt_v);
} }
ty::ty_tag(tid, tps) { ty::ty_tag(tid, tps) {
let bcx = bcx; let bcx = bcx;
let ccx = bcx_ccx(bcx); let ccx = bcx_ccx(bcx);
// Compute max(variant sizes) and max(variant alignments).
// Compute max(variant sizes) and max(variant alignments).
let max_size: ValueRef = alloca(bcx, ccx.int_type); let max_size: ValueRef = alloca(bcx, ccx.int_type);
Store(bcx, C_int(ccx, 0), max_size); Store(bcx, C_int(ccx, 0), max_size);
let variants = ty::tag_variants(bcx_tcx(bcx), tid); let variants = ty::tag_variants(bcx_tcx(bcx), tid);
@ -616,9 +630,16 @@ fn dynamic_metrics(bcx: @block_ctxt,
let t = ty::substitute_type_params(bcx_tcx(bcx), tps, raw_ty); let t = ty::substitute_type_params(bcx_tcx(bcx), tps, raw_ty);
tys += [t]; tys += [t];
} }
let rslt = align_elements(bcx, tys, opt_v);
// Note: we do not pass in opt_v here for the value but rather
// none. The reason is that what we would want to pass in is a
// ptr to the blob data of the tag, but this is impossible until
// we know the size/alignment of the blob data. Therefore, it is
// not legal to have a tag type that contains an interior opaque
// type. Fortunately this will never happen.
let rslt = c_struct_metrics(bcx, tys, none);
bcx = rslt.bcx; bcx = rslt.bcx;
let this_size = rslt.val; let this_size = rslt.sz;
let old_max_size = Load(bcx, max_size); let old_max_size = Load(bcx, max_size);
Store(bcx, umax(bcx, this_size, old_max_size), max_size); Store(bcx, umax(bcx, this_size, old_max_size), max_size);
} }
@ -651,7 +672,7 @@ fn dynamic_metrics(bcx: @block_ctxt,
let tdptr = Load(bcx, tdptrptr); let tdptr = Load(bcx, tdptrptr);
let sz = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_size])); let sz = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_size]));
let align = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_align])); let align = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_align]));
ret { bcx: bcx, sz: sz, align: sz }; ret { bcx: bcx, sz: sz, align: align };
} }
} }
} }
@ -661,7 +682,7 @@ fn dynamic_metrics(bcx: @block_ctxt,
// return type, use bump_ptr(). // return type, use bump_ptr().
fn ptr_offs(bcx: @block_ctxt, base: ValueRef, sz: ValueRef) -> ValueRef { fn ptr_offs(bcx: @block_ctxt, base: ValueRef, sz: ValueRef) -> ValueRef {
let raw = PointerCast(bcx, base, T_ptr(T_i8())); let raw = PointerCast(bcx, base, T_ptr(T_i8()));
GEP(bcx, raw, [sz]); GEP(bcx, raw, [sz])
} }
// Increment a pointer by a given amount and then cast it to be a pointer // Increment a pointer by a given amount and then cast it to be a pointer
@ -760,7 +781,7 @@ fn GEP_tup_like(bcx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
let args = []; let args = [];
for typ: ty::t in s.prefix { args += [typ]; } for typ: ty::t in s.prefix { args += [typ]; }
let prefix_ty = ty::mk_tup(bcx_tcx(bcx), args); let prefix_ty = ty::mk_tup(bcx_tcx(bcx), args);
let {bcx, val: prefix_sz} = size_of(bcx, prefix_ty); let {bcx, sz: prefix_sz, align: _} = metrics(bcx, prefix_ty, some(base));
let {bcx, val: align} = align_of(bcx, s.target); let {bcx, val: align} = align_of(bcx, s.target);
let sz = align_to(bcx, prefix_sz, align); let sz = align_to(bcx, prefix_sz, align);
ret rslt(bcx, bump_ptr(bcx, s.target, base, sz)); ret rslt(bcx, bump_ptr(bcx, s.target, base, sz));
@ -898,7 +919,6 @@ fn field_of_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool, field: int) ->
GEPi(tydesc.bcx, tydesc.val, [0, field])); GEPi(tydesc.bcx, tydesc.val, [0, field]));
} }
// Given a type containing ty params, build a vector containing a ValueRef for // Given a type containing ty params, build a vector containing a ValueRef for
// each of the ty params it uses (from the current frame) and a vector of the // each of the ty params it uses (from the current frame) and a vector of the
// indices of the ty params present in the type. This is used solely for // indices of the ty params present in the type. This is used solely for
@ -2003,21 +2023,21 @@ fn call_bzero(cx: @block_ctxt, dst: ValueRef, n_bytes: ValueRef,
Call(cx, memset, [dst_ptr, C_u8(0u), size, align, volatile])); Call(cx, memset, [dst_ptr, C_u8(0u), size, align, volatile]));
} }
fn memmove_ty(cx: @block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) -> fn memmove_ty(bcx: @block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) ->
@block_ctxt { @block_ctxt {
let ccx = bcx_ccx(cx); let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, t) { if check type_has_static_size(ccx, t) {
if ty::type_is_structural(bcx_tcx(cx), t) { if ty::type_is_structural(bcx_tcx(bcx), t) {
let sp = cx.sp; let sp = bcx.sp;
let llsz = llsize_of(ccx, type_of(ccx, sp, t)); let llsz = llsize_of(ccx, type_of(ccx, sp, t));
ret call_memmove(cx, dst, src, llsz).bcx; ret call_memmove(bcx, dst, src, llsz).bcx;
} }
Store(cx, Load(cx, src), dst); Store(bcx, Load(bcx, src), dst);
ret cx; ret bcx;
} }
let llsz = size_of(cx, t); let {bcx, sz: llsz, align: _} = metrics(bcx, t, some(src));
ret call_memmove(llsz.bcx, dst, src, llsz.val).bcx; ret call_memmove(bcx, dst, src, llsz).bcx;
} }
tag copy_action { INIT; DROP_EXISTING; } tag copy_action { INIT; DROP_EXISTING; }

View file

@ -5,6 +5,7 @@ import trans_build::*;
import trans::{ import trans::{
trans_shared_malloc, trans_shared_malloc,
type_of_inner, type_of_inner,
metrics,
size_of, size_of,
node_id_type, node_id_type,
INIT, INIT,
@ -39,7 +40,7 @@ fn alloc_uniq(cx: @block_ctxt, uniq_ty: ty::t)
} }
fn alloc_uniq_(bcx: @block_ctxt, uniq_ty: ty::t, opt_v: option<ValueRef>) fn alloc_uniq_(bcx: @block_ctxt, uniq_ty: ty::t, opt_v: option<ValueRef>)
: type_is_unique_box(cx, uniq_ty) -> result { : type_is_unique_box(bcx, uniq_ty) -> result {
let contents_ty = content_ty(bcx, uniq_ty); let contents_ty = content_ty(bcx, uniq_ty);
let {bcx, sz: llsz, align: _} = metrics(bcx, contents_ty, opt_v); let {bcx, sz: llsz, align: _} = metrics(bcx, contents_ty, opt_v);
let ccx = bcx_ccx(bcx); let ccx = bcx_ccx(bcx);
@ -83,7 +84,7 @@ fn duplicate(bcx: @block_ctxt, v: ValueRef, t: ty::t)
: type_is_unique_box(bcx, t) -> result { : type_is_unique_box(bcx, t) -> result {
let content_ty = content_ty(bcx, t); let content_ty = content_ty(bcx, t);
let {bcx, val: llptr} = alloc_uniq_(bcx, t, v); let {bcx, val: llptr} = alloc_uniq_(bcx, t, some(v));
let src = load_if_immediate(bcx, v, content_ty); let src = load_if_immediate(bcx, v, content_ty);
let dst = llptr; let dst = llptr;

View file

@ -149,6 +149,7 @@ export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind;
export type_err; export type_err;
export type_err_to_str; export type_err_to_str;
export type_has_dynamic_size; export type_has_dynamic_size;
export type_has_opaque_size;
export type_needs_drop; export type_needs_drop;
export type_is_bool; export type_is_bool;
export type_is_bot; export type_is_bot;
@ -1140,6 +1141,15 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
} }
} }
pure fn type_has_opaque_size(cx: ctxt, ty: t) -> bool unchecked {
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
alt sty {
ty_opaque_closure. { true}
_ { false }
}
})
}
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked { pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
/* type_structurally_contains can't be declared pure /* type_structurally_contains can't be declared pure