]> git.lizzy.rs Git - rust.git/commitdiff
Implement debug printing for tcx interner sty's.
authorHuon Wilson <dbau.pp+github@gmail.com>
Thu, 4 Dec 2014 00:04:17 +0000 (16:04 -0800)
committerHuon Wilson <dbau.pp+github@gmail.com>
Mon, 29 Dec 2014 12:55:24 +0000 (23:55 +1100)
src/librustc/middle/ty.rs
src/librustc_driver/driver.rs
src/librustc_trans/trans/base.rs

index 819defdb0caf27e0016f809c20a7b6723ec66006..dc2c7e98de52c6b9e8410db140bb558931ed8981 100644 (file)
@@ -779,6 +779,77 @@ pub struct ctxt<'tcx> {
     }
 }
 
+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>,
index 4ab5c19430b5c1e30466c2bf495e5f7b07d65e56..aa10b63990312e1943dbddb94259ed54f145e8b0 100644 (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();
 
index f49fc7f06c5014a2b5e656af9da9d5fdddcd1770..76763a861457cde4228df07fcf0c2424faeae1e9 100644 (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);
+
+    if is_allow && !print_info {
+        // we're not interested in anything here
+        return
+    }
 
-    let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
+    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