diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 819defdb0caf..dc2c7e98de52 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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>, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4ab5c19430b5..aa10b6399031 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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(); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f49fc7f06c50..76763a861457 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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