Implement debug printing for tcx interner sty's.

This commit is contained in:
Huon Wilson 2014-12-03 16:04:17 -08:00
parent 25fb12b8a5
commit 7cd6bf67a2
3 changed files with 117 additions and 9 deletions

View File

@ -779,6 +779,77 @@ bitflags! {
}
}
impl Copy for TypeFlags {}
macro_rules! sty_debug_print {
($ctxt: expr, $($variant: ident),*) => {{
// curious inner module to allow variant names to be used as
// variable names.
mod inner {
use middle::ty;
struct DebugStat {
total: uint,
region_infer: uint,
ty_infer: uint,
both_infer: uint,
}
pub fn go(tcx: &ty::ctxt) {
let mut total = DebugStat {
total: 0,
region_infer: 0, ty_infer: 0, both_infer: 0,
};
$(let mut $variant = total;)*
for (_, t) in tcx.interner.borrow().iter() {
let variant = match t.sty {
ty::ty_bool | ty::ty_char | ty::ty_int(..) | ty::ty_uint(..) |
ty::ty_float(..) | ty::ty_str => continue,
ty::ty_err => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
let region = t.flags.intersects(ty::HAS_RE_INFER);
let ty = t.flags.intersects(ty::HAS_TY_INFER);
variant.total += 1;
total.total += 1;
if region { total.region_infer += 1; variant.region_infer += 1 }
if ty { total.ty_infer += 1; variant.ty_infer += 1 }
if region && ty { total.both_infer += 1; variant.both_infer += 1 }
}
println!("Ty interner total ty region both");
$(println!(" {:18}: {uses:6} {usespc:4.1}%, \
{ty:4.1}% {region:5.1}% {both:4.1}%",
stringify!($variant),
uses = $variant.total,
usespc = $variant.total as f64 * 100.0 / total.total as f64,
ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
region = $variant.region_infer as f64 * 100.0 / total.total as f64,
both = $variant.both_infer as f64 * 100.0 / total.total as f64);
)*
println!(" total {uses:6} \
{ty:4.1}% {region:5.1}% {both:4.1}%",
uses = total.total,
ty = total.ty_infer as f64 * 100.0 / total.total as f64,
region = total.region_infer as f64 * 100.0 / total.total as f64,
both = total.both_infer as f64 * 100.0 / total.total as f64)
}
}
inner::go($ctxt)
}}
}
impl<'tcx> ctxt<'tcx> {
pub fn print_debug_stats(&self) {
sty_debug_print!(
self,
ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_closure, ty_trait,
ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer);
}
}
#[deriving(Show)]
pub struct TyS<'tcx> {
pub sty: sty<'tcx>,

View File

@ -82,9 +82,20 @@ pub fn compile_input(sess: Session,
let type_arena = TypedArena::new();
let analysis = phase_3_run_analysis_passes(sess, ast_map, &type_arena, id);
phase_save_analysis(&analysis.ty_cx.sess, analysis.ty_cx.map.krate(), &analysis, outdir);
if log_enabled!(::log::INFO) {
println!("Pre-trans")
analysis.ty_cx.print_debug_stats();
}
if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
let (tcx, trans) = phase_4_translate_to_llvm(analysis);
if log_enabled!(::log::INFO) {
println!("Post-trans")
tcx.print_debug_stats();
}
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();

View File

@ -2125,14 +2125,20 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) {
let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
let print_info = log_enabled!(::log::INFO);
let levels = ccx.tcx().node_lint_levels.borrow();
let lint_id = lint::LintId::of(lint::builtin::VARIANT_SIZE_DIFFERENCES);
let lvlsrc = match levels.get(&(id, lint_id)) {
None | Some(&(lint::Allow, _)) => return,
Some(&lvlsrc) => lvlsrc,
};
let lvlsrc = levels.get(&(id, lint_id));
let is_allow = lvlsrc.map_or(true, |&(lvl, _)| lvl == lint::Allow);
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
if is_allow && !print_info {
// we're not interested in anything here
return
}
let ty = ty::node_id_to_type(ccx.tcx(), id);
let avar = adt::represent_type(ccx, ty);
match *avar {
adt::General(_, ref variants, _) => {
for var in variants.iter() {
@ -2158,13 +2164,29 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span,
}
);
if print_info {
let llty = type_of::sizing_type_of(ccx, ty);
let sess = &ccx.tcx().sess;
sess.span_note(sp, &*format!("total size: {} bytes", llsize_of_real(ccx, llty)));
match *avar {
adt::General(..) => {
for (i, var) in enum_def.variants.iter().enumerate() {
ccx.tcx().sess.span_note(var.span,
&*format!("variant data: {} bytes", sizes[i]));
}
}
_ => {}
}
}
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
if largest > slargest * 3 && slargest > 0 {
if !is_allow && largest > slargest * 3 && slargest > 0 {
// Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
// pass for the latter already ran.
lint::raw_emit_lint(&ccx.tcx().sess, lint::builtin::VARIANT_SIZE_DIFFERENCES,
lvlsrc, Some(sp),
*lvlsrc.unwrap(), Some(sp),
format!("enum variant is more than three times larger \
({} bytes) than the next largest (ignoring padding)",
largest)[]);
@ -2332,8 +2354,12 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
ast::ItemMod(ref m) => {
trans_mod(&ccx.rotate(), m);
}
ast::ItemEnum(ref enum_definition, _) => {
enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
ast::ItemEnum(ref enum_definition, ref gens) => {
if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types
enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
}
}
ast::ItemConst(_, ref expr) => {
// Recurse on the expression to catch items in blocks