rust/src/rustc/middle/trans/shape.rs

777 lines
27 KiB
Rust
Raw Normal View History

2011-08-04 12:46:10 -05:00
// A "shape" is a compact encoding of a type that is used by interpreted glue.
// This substitutes for the runtime tags used by e.g. MLs.
import lib::llvm::llvm;
import lib::llvm::{True, False, ModuleRef, TypeRef, ValueRef};
import driver::session;
import driver::session::session;
import trans::base;
import middle::trans::common::*;
import back::abi;
2011-08-04 12:46:10 -05:00
import middle::ty;
2011-11-10 10:41:42 -06:00
import middle::ty::field;
2011-08-04 12:46:10 -05:00
import syntax::ast;
2012-05-23 02:38:39 -05:00
import syntax::ast_util::{dummy_sp, new_def_hash};
2011-08-04 12:46:10 -05:00
import syntax::util::interner;
import util::ppaux::ty_to_str;
import syntax::codemap::span;
2012-05-10 11:27:02 -05:00
import dvec::{dvec, extensions};
2011-08-04 12:46:10 -05:00
import std::map::hashmap;
import ty_ctxt = middle::ty::ctxt;
type nominal_id = @{did: ast::def_id, tps: [ty::t]};
fn mk_nominal_id(tcx: ty::ctxt, did: ast::def_id,
tps: [ty::t]) -> nominal_id {
let tps_norm = tps.map { |t| ty::normalize_ty(tcx, t) };
@{did: did, tps: tps_norm}
}
fn hash_nominal_id(&&ri: nominal_id) -> uint {
let mut h = 5381u;
h *= 33u;
h += ri.did.crate as uint;
h *= 33u;
h += ri.did.node as uint;
for vec::each(ri.tps) {|t|
h *= 33u;
h += ty::type_id(t);
}
ret h;
}
fn eq_nominal_id(&&mi: nominal_id, &&ni: nominal_id) -> bool {
if mi.did != ni.did {
false
} else {
vec::all2(mi.tps, ni.tps) { |m_tp, n_tp|
ty::type_id(m_tp) == ty::type_id(n_tp)
}
}
}
fn new_nominal_id_hash<T: copy>() -> hashmap<nominal_id, T> {
ret hashmap(hash_nominal_id, eq_nominal_id);
}
type enum_data = {did: ast::def_id, substs: ty::substs};
type ctxt =
2012-03-26 20:35:18 -05:00
{mut next_tag_id: u16,
pad: u16,
tag_id_to_index: hashmap<nominal_id, u16>,
tag_order: dvec<enum_data>,
resources: interner::interner<nominal_id>,
llshapetablesty: TypeRef,
llshapetables: ValueRef};
const shape_u8: u8 = 0u8;
const shape_u16: u8 = 1u8;
const shape_u32: u8 = 2u8;
const shape_u64: u8 = 3u8;
const shape_i8: u8 = 4u8;
const shape_i16: u8 = 5u8;
const shape_i32: u8 = 6u8;
const shape_i64: u8 = 7u8;
const shape_f32: u8 = 8u8;
const shape_f64: u8 = 9u8;
2012-02-08 14:06:08 -06:00
const shape_box: u8 = 10u8;
2011-09-02 09:09:41 -05:00
const shape_vec: u8 = 11u8;
const shape_enum: u8 = 12u8;
const shape_struct: u8 = 17u8;
const shape_box_fn: u8 = 18u8;
const shape_res: u8 = 20u8;
const shape_uniq: u8 = 22u8;
const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
const shape_uniq_fn: u8 = 25u8;
const shape_stack_fn: u8 = 26u8;
const shape_bare_fn: u8 = 27u8;
const shape_tydesc: u8 = 28u8;
const shape_send_tydesc: u8 = 29u8;
2012-03-08 16:05:16 -06:00
const shape_rptr: u8 = 31u8;
2012-04-09 19:32:49 -05:00
const shape_fixedvec: u8 = 32u8;
const shape_slice: u8 = 33u8;
const shape_unboxed_vec: u8 = 34u8;
2011-08-04 12:46:10 -05:00
fn mk_global(ccx: @crate_ctxt, name: str, llval: ValueRef, internal: bool) ->
ValueRef {
2011-09-02 17:34:58 -05:00
let llglobal =
str::as_c_str(name,
2011-09-02 17:34:58 -05:00
{|buf|
lib::llvm::llvm::LLVMAddGlobal(ccx.llmod,
val_ty(llval), buf)
});
2011-08-04 12:46:10 -05:00
lib::llvm::llvm::LLVMSetInitializer(llglobal, llval);
lib::llvm::llvm::LLVMSetGlobalConstant(llglobal, True);
2011-09-02 17:34:58 -05:00
if internal {
lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
}
2011-08-04 12:46:10 -05:00
ret llglobal;
}
2012-01-19 16:24:03 -06:00
// Computes a set of variants of a enum that are guaranteed to have size and
// alignment at least as large as any other variant of the enum. This is an
2011-08-04 12:46:10 -05:00
// important performance optimization.
fn round_up(size: u16, align: u8) -> u16 {
assert (align >= 1u8);
2011-08-04 12:46:10 -05:00
let alignment = align as u16;
ret size - 1u16 + alignment & !(alignment - 1u16);
2011-08-04 12:46:10 -05:00
}
type size_align = {size: u16, align: u8};
2011-08-04 12:46:10 -05:00
enum enum_kind {
tk_unit, // 1 variant, no data
tk_enum, // N variants, no data
tk_newtype, // 1 variant, data
tk_complex // N variants, no data
}
2011-08-04 12:46:10 -05:00
fn enum_kind(ccx: @crate_ctxt, did: ast::def_id) -> enum_kind {
let variants = ty::enum_variants(ccx.tcx, did);
if vec::any(*variants) {|v| vec::len(v.args) > 0u} {
if vec::len(*variants) == 1u { tk_newtype }
else { tk_complex }
} else {
if vec::len(*variants) <= 1u { tk_unit }
else { tk_enum }
2011-08-04 12:46:10 -05:00
}
}
// Returns the code corresponding to the pointer size on this architecture.
fn s_int(tcx: ty_ctxt) -> u8 {
ret alt tcx.sess.targ_cfg.arch {
session::arch_x86 { shape_i32 }
session::arch_x86_64 { shape_i64 }
session::arch_arm { shape_i32 }
};
2011-08-04 12:46:10 -05:00
}
fn s_uint(tcx: ty_ctxt) -> u8 {
ret alt tcx.sess.targ_cfg.arch {
session::arch_x86 { shape_u32 }
session::arch_x86_64 { shape_u64 }
session::arch_arm { shape_u32 }
};
2011-08-04 12:46:10 -05:00
}
fn s_float(tcx: ty_ctxt) -> u8 {
ret alt tcx.sess.targ_cfg.arch {
session::arch_x86 { shape_f64 }
session::arch_x86_64 { shape_f64 }
session::arch_arm { shape_f64 }
};
}
fn s_variant_enum_t(tcx: ty_ctxt) -> u8 {
ret s_int(tcx);
2011-08-04 12:46:10 -05:00
}
fn s_tydesc(_tcx: ty_ctxt) -> u8 {
ret shape_tydesc;
}
fn s_send_tydesc(_tcx: ty_ctxt) -> u8 {
ret shape_send_tydesc;
}
fn mk_ctxt(llmod: ModuleRef) -> ctxt {
let llshapetablesty = trans::common::T_named_struct("shapes");
let llshapetables = str::as_c_str("shapes", {|buf|
lib::llvm::llvm::LLVMAddGlobal(llmod, llshapetablesty, buf)
});
2011-08-04 12:46:10 -05:00
2012-03-26 20:35:18 -05:00
ret {mut next_tag_id: 0u16,
pad: 0u16,
tag_id_to_index: new_nominal_id_hash(),
2012-05-10 11:27:02 -05:00
tag_order: dvec(),
resources: interner::mk(hash_nominal_id, eq_nominal_id),
llshapetablesty: llshapetablesty,
llshapetables: llshapetables};
2011-08-04 12:46:10 -05:00
}
2011-09-12 05:39:38 -05:00
fn add_bool(&dest: [u8], val: bool) { dest += [if val { 1u8 } else { 0u8 }]; }
2011-08-04 12:46:10 -05:00
2011-09-12 05:39:38 -05:00
fn add_u16(&dest: [u8], val: u16) {
dest += [(val & 0xffu16) as u8, (val >> 8u16) as u8];
2011-08-04 12:46:10 -05:00
}
2011-09-12 05:39:38 -05:00
fn add_substr(&dest: [u8], src: [u8]) {
2011-08-15 18:38:23 -05:00
add_u16(dest, vec::len(src) as u16);
2011-08-04 12:46:10 -05:00
dest += src;
}
fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
alt ty::get(t).struct {
ty::ty_nil | ty::ty_bool | ty::ty_uint(ast::ty_u8) |
ty::ty_bot { [shape_u8] }
ty::ty_int(ast::ty_i) { [s_int(ccx.tcx)] }
ty::ty_float(ast::ty_f) { [s_float(ccx.tcx)] }
ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) { [s_uint(ccx.tcx)] }
ty::ty_type { [s_tydesc(ccx.tcx)] }
ty::ty_int(ast::ty_i8) { [shape_i8] }
ty::ty_uint(ast::ty_u16) { [shape_u16] }
ty::ty_int(ast::ty_i16) { [shape_i16] }
ty::ty_uint(ast::ty_u32) { [shape_u32] }
ty::ty_int(ast::ty_i32) | ty::ty_int(ast::ty_char) { [shape_i32] }
ty::ty_uint(ast::ty_u64) { [shape_u64] }
ty::ty_int(ast::ty_i64) { [shape_i64] }
ty::ty_float(ast::ty_f32) { [shape_f32] }
ty::ty_float(ast::ty_f64) { [shape_f64] }
2012-04-09 19:32:49 -05:00
ty::ty_estr(ty::vstore_uniq) |
ty::ty_str {
// FIXME: we want to emit this as a unique pointer to an unboxed vec,
// but it doesn't work at the moment, since trans doesn't put
// tydescs in string boxes...
let mut s = [shape_vec];
add_bool(s, true); // type is POD
let unit_ty = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
add_substr(s, shape_of(ccx, unit_ty));
s
}
ty::ty_enum(did, substs) {
alt enum_kind(ccx, did) {
tk_unit { [s_variant_enum_t(ccx.tcx)] }
tk_enum { [s_variant_enum_t(ccx.tcx)] }
tk_newtype | tk_complex {
let mut s = [shape_enum], id;
let nom_id = mk_nominal_id(ccx.tcx, did, substs.tps);
alt ccx.shape_cx.tag_id_to_index.find(nom_id) {
none {
2011-08-04 12:46:10 -05:00
id = ccx.shape_cx.next_tag_id;
ccx.shape_cx.tag_id_to_index.insert(nom_id, id);
ccx.shape_cx.tag_order.push({did: did, substs: substs});
2011-08-04 12:46:10 -05:00
ccx.shape_cx.next_tag_id += 1u16;
}
some(existing_id) { id = existing_id; }
}
add_u16(s, id as u16);
2011-08-04 12:46:10 -05:00
// Hack: always encode 0 tps, since the shape glue format
// hasn't changed since we started monomorphizing.
add_u16(s, 0_u16);
s
2011-08-04 12:46:10 -05:00
}
}
}
2012-04-09 19:32:49 -05:00
ty::ty_estr(ty::vstore_box) |
ty::ty_evec(_, ty::vstore_box) |
ty::ty_box(_) | ty::ty_opaque_box { [shape_box] }
ty::ty_uniq(mt) {
let mut s = [shape_uniq];
add_substr(s, shape_of(ccx, mt.ty));
s
}
2012-06-12 12:53:29 -05:00
ty::ty_unboxed_vec(mt) {
let mut s = [shape_unboxed_vec];
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
add_substr(s, shape_of(ccx, mt.ty));
s
}
2012-04-09 19:32:49 -05:00
ty::ty_evec(mt, ty::vstore_uniq) |
ty::ty_vec(mt) {
2012-06-12 12:53:29 -05:00
shape_of(ccx,
ty::mk_imm_uniq(ccx.tcx, ty::mk_unboxed_vec(ccx.tcx, mt)))
2011-08-04 12:46:10 -05:00
}
2012-04-09 19:32:49 -05:00
ty::ty_estr(ty::vstore_fixed(n)) {
let mut s = [shape_fixedvec];
2012-04-09 19:32:49 -05:00
let u8_t = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
assert (n + 1u) <= 0xffffu;
add_u16(s, (n + 1u) as u16);
add_bool(s, true);
add_substr(s, shape_of(ccx, u8_t));
2012-04-09 19:32:49 -05:00
s
}
ty::ty_evec(mt, ty::vstore_fixed(n)) {
let mut s = [shape_fixedvec];
assert n <= 0xffffu;
add_u16(s, n as u16);
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
add_substr(s, shape_of(ccx, mt.ty));
2012-04-09 19:32:49 -05:00
s
}
ty::ty_estr(ty::vstore_slice(r)) {
let mut s = [shape_slice];
let u8_t = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
add_bool(s, true); // is_pod
add_bool(s, true); // is_str
add_substr(s, shape_of(ccx, u8_t));
2012-04-09 19:32:49 -05:00
s
}
ty::ty_evec(mt, ty::vstore_slice(r)) {
let mut s = [shape_slice];
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
add_bool(s, false); // is_str
add_substr(s, shape_of(ccx, mt.ty));
2012-04-09 19:32:49 -05:00
s
}
2011-08-04 12:46:10 -05:00
ty::ty_rec(fields) {
let mut s = [shape_struct], sub = [];
for vec::each(fields) {|f|
sub += shape_of(ccx, f.mt.ty);
}
2011-08-04 12:46:10 -05:00
add_substr(s, sub);
s
2011-08-04 12:46:10 -05:00
}
ty::ty_tup(elts) {
let mut s = [shape_struct], sub = [];
for vec::each(elts) {|elt|
sub += shape_of(ccx, elt);
}
add_substr(s, sub);
s
}
ty::ty_iface(_, _) { [shape_box_fn] }
ty::ty_class(did, substs) {
// same as records, unless there's a dtor
let tps = substs.tps;
let m_dtor_did = ty::ty_dtor(ccx.tcx, did);
let mut s = if option::is_some(m_dtor_did) {
[shape_res]
}
else { [shape_struct] };
let mut sub = [];
option::iter(m_dtor_did) {|dtor_did|
let ri = @{did: dtor_did, tps: tps};
let id = interner::intern(ccx.shape_cx.resources, ri);
add_u16(s, id as u16);
// Hack: always encode 0 tps, since the shape glue format
// hasn't changed since we started monomorphizing.
add_u16(s, 0_u16);
};
for ty::class_items_as_mutable_fields(ccx.tcx, did, substs).each {|f|
sub += shape_of(ccx, f.mt.ty);
}
add_substr(s, sub);
s
}
ty::ty_rptr(_, mt) {
let mut s = [shape_rptr];
add_substr(s, shape_of(ccx, mt.ty));
s
2012-03-08 16:05:16 -06:00
}
ty::ty_res(did, raw_subt, substs) {
#debug["ty_res(%?, %?, %?)",
did,
ty_to_str(ccx.tcx, raw_subt),
substs.tps.map({|t| ty_to_str(ccx.tcx, t) })];
for substs.tps.each() {|t| assert !ty::type_has_params(t); }
let subt = ty::subst(ccx.tcx, substs, raw_subt);
let tps = substs.tps;
let ri = @{did: did, tps: tps};
2011-08-04 12:46:10 -05:00
let id = interner::intern(ccx.shape_cx.resources, ri);
let mut s = [shape_res];
2011-08-04 12:46:10 -05:00
add_u16(s, id as u16);
// Hack: always encode 0 tps, since the shape glue format
// hasn't changed since we started monomorphizing.
add_u16(s, 0_u16);
add_substr(s, shape_of(ccx, subt));
s
2011-08-04 12:46:10 -05:00
}
ty::ty_param(*) {
ccx.tcx.sess.bug("non-monomorphized type parameter");
}
ty::ty_fn({proto: ast::proto_box, _}) { [shape_box_fn] }
ty::ty_fn({proto: ast::proto_uniq, _}) { [shape_uniq_fn] }
ty::ty_fn({proto: ast::proto_block, _}) |
ty::ty_fn({proto: ast::proto_any, _}) { [shape_stack_fn] }
ty::ty_fn({proto: ast::proto_bare, _}) { [shape_bare_fn] }
ty::ty_opaque_closure_ptr(_) { [shape_opaque_closure_ptr] }
ty::ty_constr(inner_t, _) { shape_of(ccx, inner_t) }
ty::ty_var(_) | ty::ty_var_integral(_) | ty::ty_self {
ccx.sess.bug("shape_of: unexpected type struct found");
}
2011-08-04 12:46:10 -05:00
}
}
fn shape_of_variant(ccx: @crate_ctxt, v: ty::variant_info) -> [u8] {
let mut s = [];
for vec::each(v.args) {|t| s += shape_of(ccx, t); }
2011-08-04 12:46:10 -05:00
ret s;
}
fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
// Loop over all the enum variants and write their shapes into a
// data buffer. As we do this, it's possible for us to discover
// new enums, so we must do this first.
let mut data = [];
let mut offsets = [];
let mut i = 0u;
let mut enum_variants = [];
2012-05-10 11:27:02 -05:00
while i < ccx.shape_cx.tag_order.len() {
let {did, substs} = ccx.shape_cx.tag_order[i];
let variants = @ty::substd_enum_variants(ccx.tcx, did, substs);
vec::iter(*variants) {|v|
offsets += [vec::len(data) as u16];
2011-08-04 12:46:10 -05:00
let variant_shape = shape_of_variant(ccx, v);
2011-08-04 12:46:10 -05:00
add_substr(data, variant_shape);
let zname = str::bytes(v.name) + [0u8];
add_substr(data, zname);
2011-08-04 12:46:10 -05:00
}
enum_variants += [variants];
2011-08-04 12:46:10 -05:00
i += 1u;
}
// Now calculate the sizes of the header space (which contains offsets to
2012-01-19 16:24:03 -06:00
// info records for each enum) and the info space (which contains offsets
2011-08-04 12:46:10 -05:00
// to each variant shape). As we do so, build up the header.
let mut header = [];
let mut inf = [];
2011-08-04 12:46:10 -05:00
let header_sz = 2u16 * ccx.shape_cx.next_tag_id;
2011-08-15 18:38:23 -05:00
let data_sz = vec::len(data) as u16;
2011-08-04 12:46:10 -05:00
let mut inf_sz = 0u16;
for enum_variants.each { |variants|
let num_variants = vec::len(*variants) as u16;
add_u16(header, header_sz + inf_sz);
inf_sz += 2u16 * (num_variants + 2u16) + 3u16;
2011-08-04 12:46:10 -05:00
}
// Construct the info tables, which contain offsets to the shape of each
2012-01-19 16:24:03 -06:00
// variant. Also construct the largest-variant table for each enum, which
2011-08-04 12:46:10 -05:00
// contains the variants that the size-of operation needs to look at.
let mut lv_table = [];
let mut i = 0u;
for enum_variants.each { |variants|
add_u16(inf, vec::len(*variants) as u16);
2011-08-04 12:46:10 -05:00
// Construct the largest-variants table.
add_u16(inf,
header_sz + inf_sz + data_sz + (vec::len(lv_table) as u16));
2011-08-04 12:46:10 -05:00
let lv = largest_variants(ccx, variants);
2011-08-15 18:38:23 -05:00
add_u16(lv_table, vec::len(lv) as u16);
for vec::each(lv) {|v| add_u16(lv_table, v as u16); }
2011-08-04 12:46:10 -05:00
2012-01-19 16:24:03 -06:00
// Determine whether the enum has dynamic size.
assert !vec::any(*variants, {|v|
vec::any(v.args, {|t| ty::type_has_params(t)})
});
2011-08-04 12:46:10 -05:00
2012-01-19 16:24:03 -06:00
// If we can, write in the static size and alignment of the enum.
2011-08-04 12:46:10 -05:00
// Otherwise, write a placeholder.
let size_align = compute_static_enum_size(ccx, lv, variants);
// Write in the static size and alignment of the enum.
add_u16(inf, size_align.size);
inf += [size_align.align];
2011-08-04 12:46:10 -05:00
// Now write in the offset of each variant.
for vec::each(*variants) {|_v|
add_u16(inf, header_sz + inf_sz + offsets[i]);
2011-08-04 12:46:10 -05:00
i += 1u;
}
}
2011-08-15 18:38:23 -05:00
assert (i == vec::len(offsets));
assert (header_sz == vec::len(header) as u16);
assert (inf_sz == vec::len(inf) as u16);
assert (data_sz == vec::len(data) as u16);
2011-08-04 12:46:10 -05:00
header += inf;
2011-08-04 12:46:10 -05:00
header += data;
header += lv_table;
2011-09-02 17:34:58 -05:00
ret mk_global(ccx, "tag_shapes", C_bytes(header), true);
2012-06-07 15:49:01 -05:00
/* tjc: Not annotating FIXMEs in this module because of #1498 */
fn largest_variants(ccx: @crate_ctxt,
variants: @[ty::variant_info]) -> [uint] {
// Compute the minimum and maximum size and alignment for each
// variant.
//
// FIXME: We could do better here; e.g. we know that any
// variant that contains (T,T) must be as least as large as
// any variant that contains just T.
let mut ranges = [];
for vec::each(*variants) {|variant|
let mut bounded = true;
let mut min_size = 0u, min_align = 0u;
for vec::each(variant.args) {|elem_t|
if ty::type_has_params(elem_t) {
// FIXME: We could do better here; this causes us to
// conservatively assume that (int, T) has minimum size 0,
// when in fact it has minimum size sizeof(int).
bounded = false;
} else {
let llty = type_of::type_of(ccx, elem_t);
min_size += llsize_of_real(ccx, llty);
min_align += llalign_of_pref(ccx, llty);
}
}
ranges +=
[{size: {min: min_size, bounded: bounded},
align: {min: min_align, bounded: bounded}}];
}
// Initialize the candidate set to contain all variants.
let mut candidates = [mut];
for vec::each(*variants) {|_v| candidates += [mut true]; }
// Do a pairwise comparison among all variants still in the
// candidate set. Throw out any variant that we know has size
// and alignment at least as small as some other variant.
let mut i = 0u;
while i < vec::len(ranges) - 1u {
if candidates[i] {
let mut j = i + 1u;
while j < vec::len(ranges) {
if candidates[j] {
if ranges[i].size.bounded &&
ranges[i].align.bounded &&
ranges[j].size.bounded &&
ranges[j].align.bounded {
if ranges[i].size >= ranges[j].size &&
ranges[i].align >= ranges[j].align {
// Throw out j.
candidates[j] = false;
} else if ranges[j].size >= ranges[i].size &&
ranges[j].align >= ranges[j].align {
// Throw out i.
candidates[i] = false;
}
}
}
j += 1u;
}
}
i += 1u;
}
// Return the resulting set.
let mut result = [];
let mut i = 0u;
while i < vec::len(candidates) {
if candidates[i] { result += [i]; }
i += 1u;
}
ret result;
}
fn compute_static_enum_size(ccx: @crate_ctxt, largest_variants: [uint],
variants: @[ty::variant_info]) -> size_align {
let mut max_size = 0u16;
let mut max_align = 1u8;
for vec::each(largest_variants) {|vid|
// We increment a "virtual data pointer" to compute the size.
let mut lltys = [];
for vec::each(variants[vid].args) {|typ|
lltys += [type_of::type_of(ccx, typ)];
}
let llty = trans::common::T_struct(lltys);
let dp = llsize_of_real(ccx, llty) as u16;
let variant_align = llalign_of_pref(ccx, llty) as u8;
if max_size < dp { max_size = dp; }
if max_align < variant_align { max_align = variant_align; }
}
// Add space for the enum if applicable.
// FIXME (issue #792): This is wrong. If the enum starts with an
// 8 byte aligned quantity, we don't align it.
if vec::len(*variants) > 1u {
let variant_t = T_enum_discrim(ccx);
max_size += llsize_of_real(ccx, variant_t) as u16;
let align = llalign_of_pref(ccx, variant_t) as u8;
if max_align < align { max_align = align; }
}
ret {size: max_size, align: max_align};
}
2011-08-04 12:46:10 -05:00
}
fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
let mut dtors = [];
2011-08-04 12:46:10 -05:00
let len = interner::len(ccx.shape_cx.resources);
for uint::range(0u, len) {|i|
let ri = interner::get(ccx.shape_cx.resources, i);
for ri.tps.each() {|s| assert !ty::type_has_params(s); }
dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.tps)];
2011-08-04 12:46:10 -05:00
}
2011-09-02 17:34:58 -05:00
ret mk_global(ccx, "resource_shapes", C_struct(dtors), true);
2011-08-04 12:46:10 -05:00
}
fn gen_shape_tables(ccx: @crate_ctxt) {
let lltagstable = gen_enum_shapes(ccx);
2011-08-04 12:46:10 -05:00
let llresourcestable = gen_resource_shapes(ccx);
trans::common::set_struct_body(ccx.shape_cx.llshapetablesty,
[val_ty(lltagstable),
val_ty(llresourcestable)]);
2011-08-04 12:46:10 -05:00
let lltables =
C_named_struct(ccx.shape_cx.llshapetablesty,
[lltagstable, llresourcestable]);
2011-08-04 12:46:10 -05:00
lib::llvm::llvm::LLVMSetInitializer(ccx.shape_cx.llshapetables, lltables);
lib::llvm::llvm::LLVMSetGlobalConstant(ccx.shape_cx.llshapetables, True);
lib::llvm::SetLinkage(ccx.shape_cx.llshapetables,
lib::llvm::InternalLinkage);
2011-08-04 12:46:10 -05:00
}
// ______________________________________________________________________
// compute sizeof / alignof
type metrics = {
bcx: block,
sz: ValueRef,
align: ValueRef
};
type tag_metrics = {
bcx: block,
sz: ValueRef,
align: ValueRef,
payload_align: ValueRef
};
// Returns the number of bytes clobbered by a Store to this type.
fn llsize_of_store(cx: @crate_ctxt, t: TypeRef) -> uint {
ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint;
}
// Returns the number of bytes between successive elements of type T in an
// array of T. This is the "ABI" size. It includes any ABI-mandated padding.
fn llsize_of_alloc(cx: @crate_ctxt, t: TypeRef) -> uint {
ret llvm::LLVMABISizeOfType(cx.td.lltd, t) as uint;
}
// Returns, as near as we can figure, the "real" size of a type. As in, the
// bits in this number of bytes actually carry data related to the datum
// with the type. Not junk, padding, accidentally-damaged words, or
// whatever. Rounds up to the nearest byte though, so if you have a 1-bit
// value, we return 1 here, not 0. Most of rustc works in bytes.
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, t) as uint;
if nbits & 7u != 0u {
// Not an even number of bytes, spills into "next" byte.
1u + (nbits >> 3)
} else {
nbits >> 3
}
}
// Returns the "default" size of t, which is calculated by casting null to a
// *T and then doing gep(1) on it and measuring the result. Really, look in
// the LLVM sources. It does that. So this is likely similar to the ABI size
// (i.e. including alignment-padding), but goodness knows which alignment it
// winds up using. Probably the ABI one? Not recommended.
fn llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), cx.int_type,
False);
}
// Returns the preferred alignment of the given type for the current target.
// The preffered alignment may be larger than the alignment used when
// packing the type into structs. This will be used for things like
// allocations inside a stack frame, which LLVM has a free hand in.
fn llalign_of_pref(cx: @crate_ctxt, t: TypeRef) -> uint {
ret llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint;
}
2012-04-26 23:52:55 -05:00
// Returns the minimum alignment of a type required by the plattform.
// This is the alignment that will be used for struct fields, arrays,
// and similar ABI-mandated things.
2012-04-26 23:52:55 -05:00
fn llalign_of_min(cx: @crate_ctxt, t: TypeRef) -> uint {
ret llvm::LLVMABIAlignmentOfType(cx.td.lltd, t) as uint;
}
// Returns the "default" alignment of t, which is calculated by casting
// null to a record containing a single-bit followed by a t value, then
// doing gep(0,1) to get at the trailing (and presumably padded) t cell.
fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), cx.int_type,
False);
}
// Computes the static size of a enum, without using mk_tup(), which is
// bad for performance.
//
// FIXME: Migrate trans over to use this.
// Computes the size of the data part of an enum.
fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) -> uint {
if cx.enum_sizes.contains_key(t) { ret cx.enum_sizes.get(t); }
alt ty::get(t).struct {
ty::ty_enum(tid, substs) {
// Compute max(variant sizes).
let mut max_size = 0u;
let variants = ty::enum_variants(cx.tcx, tid);
for vec::each(*variants) {|variant|
let tup_ty = simplify_type(cx.tcx,
ty::mk_tup(cx.tcx, variant.args));
// Perform any type parameter substitutions.
let tup_ty = ty::subst(cx.tcx, substs, tup_ty);
// Here we possibly do a recursive call.
2012-01-19 23:15:32 -06:00
let this_size =
llsize_of_real(cx, type_of::type_of(cx, tup_ty));
if max_size < this_size { max_size = this_size; }
}
cx.enum_sizes.insert(t, max_size);
ret max_size;
}
_ { cx.sess.bug("static_size_of_enum called on non-enum"); }
}
}
// Creates a simpler, size-equivalent type. The resulting type is guaranteed
// to have (a) the same size as the type that was passed in; (b) to be non-
// recursive. This is done by replacing all boxes in a type with boxed unit
// types.
// This should reduce all pointers to some simple pointer type, to
// ensure that we don't recurse endlessly when computing the size of a
// nominal type that has pointers to itself in it.
fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
fn nilptr(tcx: ty::ctxt) -> ty::t {
ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mutbl: ast::m_imm})
}
fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t {
alt ty::get(typ).struct {
ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) | ty::ty_vec(_) |
2012-04-09 19:32:49 -05:00
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
ty::ty_ptr(_) | ty::ty_rptr(_,_) { nilptr(tcx) }
ty::ty_fn(_) { ty::mk_tup(tcx, [nilptr(tcx), nilptr(tcx)]) }
ty::ty_res(_, sub, substs) {
let sub1 = ty::subst(tcx, substs, sub);
ty::mk_tup(tcx, [ty::mk_int(tcx), simplify_type(tcx, sub1)])
}
2012-04-09 19:32:49 -05:00
ty::ty_evec(_, ty::vstore_slice(_)) |
ty::ty_estr(ty::vstore_slice(_)) {
ty::mk_tup(tcx, [nilptr(tcx), ty::mk_int(tcx)])
}
_ { typ }
}
}
ty::fold_ty(tcx, typ) {|t| simplifier(tcx, t) }
}
// Given a tag type `ty`, returns the offset of the payload.
//fn tag_payload_offs(bcx: block, tag_id: ast::def_id, tps: [ty::t])
// -> ValueRef {
// alt tag_kind(tag_id) {
// tk_unit | tk_enum | tk_newtype { C_int(bcx.ccx(), 0) }
// tk_complex {
// compute_tag_metrics(tag_id, tps)
// }
// }
//}