| 1 | //
 | 
|---|
| 2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
| 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
| 6 | //
 | 
|---|
| 7 | // DeclStats.cpp -- Print statistics about a translation unit's declarations.
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // Author           : Andrew Beach
 | 
|---|
| 10 | // Created On       : Fri Oct  1 14:26:00 2021
 | 
|---|
| 11 | // Last Modified By : Andrew Beach
 | 
|---|
| 12 | // Last Modified On : Wed Oct  8 11:24:00 2021
 | 
|---|
| 13 | // Update Count     : 0
 | 
|---|
| 14 | //
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #include "DeclStats.hpp"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include "AST/LinkageSpec.hpp"
 | 
|---|
| 19 | #include "AST/Pass.hpp"
 | 
|---|
| 20 | #include "AST/Print.hpp"
 | 
|---|
| 21 | #include "Common/VectorMap.hpp"
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #include <iostream>
 | 
|---|
| 24 | #include <map>
 | 
|---|
| 25 | #include <sstream>
 | 
|---|
| 26 | #include <unordered_map>
 | 
|---|
| 27 | #include <unordered_set>
 | 
|---|
| 28 | 
 | 
|---|
| 29 | // Everything but printDeclStats at the bottom is hidden.
 | 
|---|
| 30 | namespace {
 | 
|---|
| 31 | 
 | 
|---|
| 32 | template<typename T>
 | 
|---|
| 33 | void sum( T & l, const T & r ) { l += r; }
 | 
|---|
| 34 | 
 | 
|---|
| 35 | void sum( VectorMap<unsigned> & l, const VectorMap<unsigned> & r ) {
 | 
|---|
| 36 |         l.reserve( r.size() );
 | 
|---|
| 37 |         for ( unsigned i = 0 ; i < r.size() ; ++i ) {
 | 
|---|
| 38 |                 l[i] += r[i];
 | 
|---|
| 39 |         }
 | 
|---|
| 40 | }
 | 
|---|
| 41 | 
 | 
|---|
| 42 | template<typename KeyT>
 | 
|---|
| 43 | void sum( std::map<KeyT, unsigned> & l, const std::map<KeyT, unsigned> & r ) {
 | 
|---|
| 44 |         for ( const auto & entry : r ) {
 | 
|---|
| 45 |                 l[ entry.first ] += entry.second;
 | 
|---|
| 46 |         }
 | 
|---|
| 47 | }
 | 
|---|
| 48 | 
 | 
|---|
| 49 | template<typename KeyT>
 | 
|---|
| 50 | void sum( std::unordered_map<KeyT, unsigned> & l,
 | 
|---|
| 51 |                 const std::unordered_map<KeyT, unsigned> & r ) {
 | 
|---|
| 52 |         for ( const auto & entry : r ) {
 | 
|---|
| 53 |                 l[ entry.first ] += entry.second;
 | 
|---|
| 54 |         }
 | 
|---|
| 55 | }
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /// Stores statistics on a single group of arguments or return values.
 | 
|---|
| 58 | struct ArgPackStats {
 | 
|---|
| 59 |         /// Count of decls with each number of elements.
 | 
|---|
| 60 |         VectorMap<unsigned> n;
 | 
|---|
| 61 |         /// Count of decls with each number of basic type elements.
 | 
|---|
| 62 |         VectorMap<unsigned> n_basic;
 | 
|---|
| 63 |         /// Count of decls with each number of generic type elements.
 | 
|---|
| 64 |         VectorMap<unsigned> n_generic;
 | 
|---|
| 65 |         /// Count of decls with each number of polymorphic elements.
 | 
|---|
| 66 |         VectorMap<unsigned> n_poly;
 | 
|---|
| 67 |         /// Count of decls with each number of non-generic compound types.
 | 
|---|
| 68 |         VectorMap<unsigned> n_compound;
 | 
|---|
| 69 |         /// Count of decls with each percentage of basic type elements.
 | 
|---|
| 70 |         std::map<unsigned, unsigned> p_basic;
 | 
|---|
| 71 |         /// Count of decls with each percentage of generic type elements.
 | 
|---|
| 72 |         std::map<unsigned, unsigned> p_generic;
 | 
|---|
| 73 |         /// Count of decls with each percentage of polymorphic elements.
 | 
|---|
| 74 |         std::map<unsigned, unsigned> p_poly;
 | 
|---|
| 75 |         /// Count of decls with each percentage of non-generic compound type elements.
 | 
|---|
| 76 |         std::map<unsigned, unsigned> p_compound;
 | 
|---|
| 77 |         /// Count of decls with each number of distinct types in the pack.
 | 
|---|
| 78 |         VectorMap<unsigned> n_types;
 | 
|---|
| 79 |         /// Count of decls with each percentage of new types in lists.
 | 
|---|
| 80 |         /// Types used in the parameter list that recur in the return list are not considered to be new.
 | 
|---|
| 81 |         std::map<unsigned, unsigned> p_new;
 | 
|---|
| 82 | 
 | 
|---|
| 83 |         ArgPackStats& operator+=( const ArgPackStats& other ) {
 | 
|---|
| 84 |                 sum(n, other.n);
 | 
|---|
| 85 |                 sum(n_basic, other.n_basic);
 | 
|---|
| 86 |                 sum(n_generic, other.n_generic);
 | 
|---|
| 87 |                 sum(n_poly, other.n_poly);
 | 
|---|
| 88 |                 sum(n_compound, other.n_compound);
 | 
|---|
| 89 |                 sum(p_basic, other.p_basic);
 | 
|---|
| 90 |                 sum(p_generic, other.p_generic);
 | 
|---|
| 91 |                 sum(p_poly, other.p_poly);
 | 
|---|
| 92 |                 sum(p_compound, other.p_compound);
 | 
|---|
| 93 |                 sum(n_types, other.n_types);
 | 
|---|
| 94 |                 sum(p_new, other.p_new);
 | 
|---|
| 95 | 
 | 
|---|
| 96 |                 return *this;
 | 
|---|
| 97 |         }
 | 
|---|
| 98 | };
 | 
|---|
| 99 | 
 | 
|---|
| 100 | /// Collected statistics on a group of declarations.
 | 
|---|
| 101 | struct Stats {
 | 
|---|
| 102 |         /// Total number of declarations in these statistics.
 | 
|---|
| 103 |         unsigned n_decls;
 | 
|---|
| 104 |         /// Count of declarations with each number of assertion parameters.
 | 
|---|
| 105 |         VectorMap<unsigned> n_type_params;
 | 
|---|
| 106 |         /// Count of generic types with each number of type parameters.
 | 
|---|
| 107 |         VectorMap<unsigned> n_generic_params;
 | 
|---|
| 108 |         /// Count of maximum nesting depth of types.
 | 
|---|
| 109 |         VectorMap<unsigned> n_generic_nesting;
 | 
|---|
| 110 |         /// Count of declarations with each name.
 | 
|---|
| 111 |         std::unordered_map<std::string, unsigned> by_name;
 | 
|---|
| 112 |         /// Count of uses of each basic type.
 | 
|---|
| 113 |         std::unordered_map<std::string, unsigned> basic_type_names;
 | 
|---|
| 114 |         /// Count of uses of each generic type name (includes "*", "[]", "(*)", "[,]").
 | 
|---|
| 115 |         std::unordered_map<std::string, unsigned> generic_type_names;
 | 
|---|
| 116 |         /// Count of uses of each non-generic aggregate type.
 | 
|---|
| 117 |         std::unordered_map<std::string, unsigned> compound_type_names;
 | 
|---|
| 118 |         /// Count of decls using each basic type.
 | 
|---|
| 119 |         std::unordered_map<std::string, unsigned> basic_type_decls;
 | 
|---|
| 120 |         /// Count of decls using each generic type (includes "*", "[]", "(*)", "[,]").
 | 
|---|
| 121 |         std::unordered_map<std::string, unsigned> generic_type_decls;
 | 
|---|
| 122 |         /// Count of decls using each compound type.
 | 
|---|
| 123 |         std::unordered_map<std::string, unsigned> compound_type_decls;
 | 
|---|
| 124 |         /// Stats for the parameter lists.
 | 
|---|
| 125 |         ArgPackStats params;
 | 
|---|
| 126 |         /// Stats for the return lists.
 | 
|---|
| 127 |         ArgPackStats returns;
 | 
|---|
| 128 | 
 | 
|---|
| 129 |         /// Count of declarations with each number of assertions.
 | 
|---|
| 130 |         std::map<unsigned, unsigned> n_assns;
 | 
|---|
| 131 |         /// Stats for the assertions' parameters.
 | 
|---|
| 132 |         ArgPackStats assn_params;
 | 
|---|
| 133 |         /// Stats for the assertions' return types.
 | 
|---|
| 134 |         ArgPackStats assn_returns;
 | 
|---|
| 135 | 
 | 
|---|
| 136 |         Stats& operator+=( const Stats& other ) {
 | 
|---|
| 137 |                 sum( n_decls, other.n_decls );
 | 
|---|
| 138 |                 sum( n_type_params, other.n_type_params );
 | 
|---|
| 139 |                 sum( n_generic_params, other.n_generic_params );
 | 
|---|
| 140 |                 sum( n_generic_nesting, other.n_generic_nesting );
 | 
|---|
| 141 |                 sum( by_name, other.by_name );
 | 
|---|
| 142 |                 sum( basic_type_names, other.basic_type_names );
 | 
|---|
| 143 |                 sum( generic_type_names, other.generic_type_names );
 | 
|---|
| 144 |                 sum( compound_type_names, other.compound_type_names );
 | 
|---|
| 145 |                 sum( basic_type_decls, other.basic_type_decls );
 | 
|---|
| 146 |                 sum( generic_type_decls, other.generic_type_decls );
 | 
|---|
| 147 |                 sum( compound_type_decls, other.compound_type_decls );
 | 
|---|
| 148 |                 sum( params, other.params );
 | 
|---|
| 149 |                 sum( returns, other.returns );
 | 
|---|
| 150 |                 sum( n_assns, other.n_assns );
 | 
|---|
| 151 |                 sum( assn_params, other.assn_params );
 | 
|---|
| 152 |                 sum( assn_returns, other.assn_returns );
 | 
|---|
| 153 | 
 | 
|---|
| 154 |                 return *this;
 | 
|---|
| 155 |         }
 | 
|---|
| 156 | 
 | 
|---|
| 157 | };
 | 
|---|
| 158 | 
 | 
|---|
| 159 | void update_max( unsigned & max, unsigned value ) {
 | 
|---|
| 160 |         if ( max < value ) max = value;
 | 
|---|
| 161 | }
 | 
|---|
| 162 | 
 | 
|---|
| 163 | // Where all unnamed specs are counted as one named spec group.
 | 
|---|
| 164 | constexpr unsigned num_named_specs = 8;
 | 
|---|
| 165 | 
 | 
|---|
| 166 | unsigned linkage_index( ast::Linkage::Spec spec ) {
 | 
|---|
| 167 |         switch ( spec.val ) {
 | 
|---|
| 168 |         case ast::Linkage::Intrinsic.val:  return 0;
 | 
|---|
| 169 |         case ast::Linkage::C.val:          return 1;
 | 
|---|
| 170 |         case ast::Linkage::Cforall.val:    return 2;
 | 
|---|
| 171 |         case ast::Linkage::AutoGen.val:    return 3;
 | 
|---|
| 172 |         case ast::Linkage::Compiler.val:   return 4;
 | 
|---|
| 173 |         case ast::Linkage::BuiltinCFA.val: return 5;
 | 
|---|
| 174 |         case ast::Linkage::BuiltinC.val:   return 6;
 | 
|---|
| 175 |         default:                           return 7;
 | 
|---|
| 176 |         }
 | 
|---|
| 177 | }
 | 
|---|
| 178 | 
 | 
|---|
| 179 | struct DeclStats : public ast::WithShortCircuiting {
 | 
|---|
| 180 |         /// Stores separate stats per linkage.
 | 
|---|
| 181 |         Stats by_linkage[num_named_specs];
 | 
|---|
| 182 |         /// Stores manglenames already seen to avoid double-counting.
 | 
|---|
| 183 |         std::unordered_set<std::string> seen_names;
 | 
|---|
| 184 |         /// Overall stats.
 | 
|---|
| 185 |         Stats total;
 | 
|---|
| 186 |         /// Count of expressions with (depth, fanout)
 | 
|---|
| 187 |         std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
 | 
|---|
| 188 | 
 | 
|---|
| 189 |         /// Count that we have seen a named type.
 | 
|---|
| 190 |         void countType(
 | 
|---|
| 191 |                         const std::string & name, unsigned & n,
 | 
|---|
| 192 |                         std::unordered_map<std::string, unsigned> & names,
 | 
|---|
| 193 |                         std::unordered_map<std::string, unsigned> & decls,
 | 
|---|
| 194 |                         std::unordered_set<std::string> & elSeen ) {
 | 
|---|
| 195 |                 ++n;
 | 
|---|
| 196 |                 ++names[ name ];
 | 
|---|
| 197 |                 if ( elSeen.insert( name ).second ) {
 | 
|---|
| 198 |                         ++decls[ name ];
 | 
|---|
| 199 |                 }
 | 
|---|
| 200 |         }
 | 
|---|
| 201 | 
 | 
|---|
| 202 |         /// Perform type analysis on a subtype.
 | 
|---|
| 203 |         void analyzeSubtype( const ast::Type * type, Stats & stats,
 | 
|---|
| 204 |                         std::unordered_set<std::string> & elSeen, unsigned & n_poly,
 | 
|---|
| 205 |                         bool & seen_poly, unsigned & max_depth, unsigned depth ) {
 | 
|---|
| 206 |                 // This kind of gets in the way of grouping arguments.
 | 
|---|
| 207 |                 unsigned ignored = 0;
 | 
|---|
| 208 |                 analyzeType(
 | 
|---|
| 209 |                         type, stats, elSeen, ignored, ignored, n_poly, ignored,
 | 
|---|
| 210 |                         seen_poly, max_depth, depth + 1 );
 | 
|---|
| 211 |         }
 | 
|---|
| 212 | 
 | 
|---|
| 213 |         /// Perform type analysis on each subtype.
 | 
|---|
| 214 |         void analyzeSubtypes(
 | 
|---|
| 215 |                         const std::vector<ast::ptr<ast::Type>> & types, Stats & stats,
 | 
|---|
| 216 |                         std::unordered_set<std::string> & elSeen, unsigned & n_poly,
 | 
|---|
| 217 |                         bool & seen_poly, unsigned & max_depth, unsigned depth ) {
 | 
|---|
| 218 |                 for ( const auto & type : types ) {
 | 
|---|
| 219 |                         analyzeSubtype( type, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 220 |                 }
 | 
|---|
| 221 |         }
 | 
|---|
| 222 | 
 | 
|---|
| 223 |         /// Perform sub-type analysis on each subtype in an argument pack.
 | 
|---|
| 224 |         void analyzeSubPack(
 | 
|---|
| 225 |                         const std::vector<ast::ptr<ast::Type>> & types, Stats & stats,
 | 
|---|
| 226 |                         std::unordered_set<std::string> & elSeen, unsigned & n_poly,
 | 
|---|
| 227 |                         bool & seen_poly, unsigned & max_depth, unsigned depth,
 | 
|---|
| 228 |                         unsigned & n_subs ) {
 | 
|---|
| 229 |                 // ... and count voids?
 | 
|---|
| 230 |                 for ( const auto & type : types ) {
 | 
|---|
| 231 |                         if ( type.as<ast::VoidType>() ) {
 | 
|---|
| 232 |                                 ++n_subs;
 | 
|---|
| 233 |                         }
 | 
|---|
| 234 |                         // Could this be in `else`?
 | 
|---|
| 235 |                         analyzeSubtype( type, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 236 |                 }
 | 
|---|
| 237 |         }
 | 
|---|
| 238 | 
 | 
|---|
| 239 |         /// Analyze and gather stats from a single type.
 | 
|---|
| 240 |         void analyzeType( const ast::ptr<ast::Type> & type, Stats & stats,
 | 
|---|
| 241 |                         std::unordered_set<std::string> & elSeen,
 | 
|---|
| 242 |                         unsigned & n_basic, unsigned & n_generic, unsigned & n_poly,
 | 
|---|
| 243 |                         unsigned & n_agg, bool & seen_poly,
 | 
|---|
| 244 |                         unsigned & max_depth, unsigned depth ) {
 | 
|---|
| 245 |                 // Almost a visit, except it is only types.
 | 
|---|
| 246 |                 if ( const ast::BasicType * t = type.as<ast::BasicType>() ) {
 | 
|---|
| 247 |                         const std::string name = ast::BasicType::typeNames[ t->kind ];
 | 
|---|
| 248 |                         countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
 | 
|---|
| 249 |                         update_max( max_depth, depth );
 | 
|---|
| 250 |                 } else if ( auto t = type.as<ast::PointerType>() ) {
 | 
|---|
| 251 |                         static const std::string name = "*";
 | 
|---|
| 252 |                         countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
 | 
|---|
| 253 |                         analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 254 |                         ++stats.n_generic_params.at( 1 );
 | 
|---|
| 255 |                 } else if ( auto t = type.as<ast::ArrayType>() ) {
 | 
|---|
| 256 |                         static const std::string name = "[]";
 | 
|---|
| 257 |                         countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
 | 
|---|
| 258 |                         analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 259 |                         ++stats.n_generic_params.at( 1 );
 | 
|---|
| 260 |                 } else if ( auto t = type.as<ast::ReferenceType>() ) {
 | 
|---|
| 261 |                         static const std::string name = "&";
 | 
|---|
| 262 |                         countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
 | 
|---|
| 263 |                         analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 264 |                         ++stats.n_generic_params.at( 1 );
 | 
|---|
| 265 |                 } else if ( auto t = type.as<ast::FunctionType>() ) {
 | 
|---|
| 266 |                         static const std::string name = "(*)";
 | 
|---|
| 267 |                         countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
 | 
|---|
| 268 |                         unsigned n_subs = 0;
 | 
|---|
| 269 |                         analyzeSubPack( t->returns, stats, elSeen, n_poly, seen_poly, max_depth, depth, n_subs );
 | 
|---|
| 270 |                         analyzeSubPack( t->params, stats, elSeen, n_poly, seen_poly, max_depth, depth, n_subs );
 | 
|---|
| 271 |                         ++stats.n_generic_params.at( n_subs );
 | 
|---|
| 272 |                 } else if ( auto t = type.as<ast::TypeInstType>() ) {
 | 
|---|
| 273 |                         if ( !seen_poly ) {
 | 
|---|
| 274 |                                 ++n_poly;
 | 
|---|
| 275 |                                 seen_poly = true;
 | 
|---|
| 276 |                         }
 | 
|---|
| 277 |                         countType( t->name, n_agg, stats.compound_type_names,
 | 
|---|
| 278 |                                         stats.compound_type_decls, elSeen );
 | 
|---|
| 279 |                         update_max( max_depth, depth );
 | 
|---|
| 280 |                 } else if ( auto t = type.as<ast::BaseInstType>() ) {
 | 
|---|
| 281 |                         auto & params = t->params;
 | 
|---|
| 282 |                         if ( params.empty() ) {
 | 
|---|
| 283 |                                 countType( t->name, n_agg, stats.compound_type_names,
 | 
|---|
| 284 |                                                 stats.compound_type_decls, elSeen );
 | 
|---|
| 285 |                                 update_max( max_depth, depth );
 | 
|---|
| 286 |                         } else {
 | 
|---|
| 287 |                                 countType( t->name, n_generic, stats.generic_type_names,
 | 
|---|
| 288 |                                                 stats.generic_type_decls, elSeen );
 | 
|---|
| 289 |                                 ++stats.n_generic_params.at( params.size() );
 | 
|---|
| 290 |                         }
 | 
|---|
| 291 |                 } else if ( auto t = type.as<ast::TupleType>() ) {
 | 
|---|
| 292 |                         static const std::string name = "[,]";
 | 
|---|
| 293 |                         countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
 | 
|---|
| 294 |                         analyzeSubtypes( t->types, stats, elSeen, n_poly, seen_poly, max_depth, depth );
 | 
|---|
| 295 |                         ++stats.n_generic_params.at( t->size() );
 | 
|---|
| 296 |                 } else if ( type.as<ast::VarArgsType>() ) {
 | 
|---|
| 297 |                         static const std::string name = "...";
 | 
|---|
| 298 |                         countType( name, n_agg, stats.compound_type_names, stats.compound_type_decls, elSeen );
 | 
|---|
| 299 |                         update_max( max_depth, depth );
 | 
|---|
| 300 |                 } else if ( type.as<ast::ZeroType>() ) {
 | 
|---|
| 301 |                         static const std::string name = "0";
 | 
|---|
| 302 |                         countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
 | 
|---|
| 303 |                         update_max( max_depth, depth );
 | 
|---|
| 304 |                 } else if ( type.as<ast::OneType>() ) {
 | 
|---|
| 305 |                         static const std::string name = "1";
 | 
|---|
| 306 |                         countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
 | 
|---|
| 307 |                         update_max( max_depth, depth );
 | 
|---|
| 308 |                 }
 | 
|---|
| 309 |         }
 | 
|---|
| 310 | 
 | 
|---|
| 311 |         /// Update an ArgPackStats based on the list of types it repersents.
 | 
|---|
| 312 |         void analyzeArgPack(
 | 
|---|
| 313 |                         const std::vector<ast::ptr<ast::Type>> & types,
 | 
|---|
| 314 |                         Stats & stats,
 | 
|---|
| 315 |                         ArgPackStats & packStats,
 | 
|---|
| 316 |                         // What are these two used for?
 | 
|---|
| 317 |                         std::unordered_set<std::string> & seen,
 | 
|---|
| 318 |                         std::unordered_set<std::string> & elSeen ) {
 | 
|---|
| 319 |                 std::unordered_set<std::string> type_names;
 | 
|---|
| 320 |                 unsigned n = 0;
 | 
|---|
| 321 |                 unsigned n_basic = 0;
 | 
|---|
| 322 |                 unsigned n_generic = 0;
 | 
|---|
| 323 |                 unsigned n_poly = 0;
 | 
|---|
| 324 |                 unsigned n_compound = 0;
 | 
|---|
| 325 |                 unsigned n_new = 0;
 | 
|---|
| 326 | 
 | 
|---|
| 327 |                 for ( auto & type : types ) {
 | 
|---|
| 328 |                         n += type->size();
 | 
|---|
| 329 | 
 | 
|---|
| 330 |                         std::stringstream ss;
 | 
|---|
| 331 |                         ast::print( ss, type );
 | 
|---|
| 332 |                         type_names.insert( ss.str() );
 | 
|---|
| 333 |                         if ( seen.insert( ss.str() ).second ) {
 | 
|---|
| 334 |                                 ++n_new;
 | 
|---|
| 335 |                         }
 | 
|---|
| 336 | 
 | 
|---|
| 337 |                         bool seen_poly = false;
 | 
|---|
| 338 |                         unsigned max_depth = 0;
 | 
|---|
| 339 |                         analyzeType(
 | 
|---|
| 340 |                                 type, stats, elSeen, n_basic, n_generic, n_poly, n_compound,
 | 
|---|
| 341 |                                 seen_poly, max_depth, 0
 | 
|---|
| 342 |                         );
 | 
|---|
| 343 |                         ++stats.n_generic_nesting.at( max_depth );
 | 
|---|
| 344 |                 }
 | 
|---|
| 345 | 
 | 
|---|
| 346 |                 ++packStats.n.at( n );
 | 
|---|
| 347 |                 ++packStats.n_basic.at( n_basic );
 | 
|---|
| 348 |                 ++packStats.n_generic.at( n_generic );
 | 
|---|
| 349 |                 ++packStats.n_poly.at( n_poly );
 | 
|---|
| 350 |                 ++packStats.n_compound.at( n_compound );
 | 
|---|
| 351 |                 if ( n > 0 ) {
 | 
|---|
| 352 |                         ++packStats.p_basic[ n_basic * 100 / n ];
 | 
|---|
| 353 |                         ++packStats.p_generic[ n_generic * 100 / n ];
 | 
|---|
| 354 |                         ++packStats.p_poly[ n_poly * 100 / n ];
 | 
|---|
| 355 |                         ++packStats.p_compound[ n_compound * 100 / n ];
 | 
|---|
| 356 |                         if ( n > 1 ) {
 | 
|---|
| 357 |                                 ++packStats.p_new[ (n_new - 1) * 100 / (n - 1) ];
 | 
|---|
| 358 |                         }
 | 
|---|
| 359 |                 }
 | 
|---|
| 360 |                 ++packStats.n_types.at( types.size() );
 | 
|---|
| 361 |         }
 | 
|---|
| 362 | 
 | 
|---|
| 363 |         /// Perform type analysis on a function type, storing information in the
 | 
|---|
| 364 |         /// given ArgPackStats.
 | 
|---|
| 365 |         void analyzeFunctionType( const ast::FunctionType * type, Stats& stats,
 | 
|---|
| 366 |                         ArgPackStats Stats::* param_pack,
 | 
|---|
| 367 |                         ArgPackStats Stats::* return_pack ) {
 | 
|---|
| 368 |                 // I still don't know what these are for.
 | 
|---|
| 369 |                 std::unordered_set<std::string> seen;
 | 
|---|
| 370 |                 std::unordered_set<std::string> elSeen;
 | 
|---|
| 371 |                 analyzeArgPack( type->params, stats, stats.*param_pack, seen, elSeen );
 | 
|---|
| 372 |                 analyzeArgPack( type->returns, stats, stats.*return_pack, seen, elSeen );
 | 
|---|
| 373 |         }
 | 
|---|
| 374 | 
 | 
|---|
| 375 |         /// If the assertion is a function, return the function type.
 | 
|---|
| 376 |         static const ast::FunctionType * getAssertionFunctionType(
 | 
|---|
| 377 |                         const ast::ptr<ast::DeclWithType> & assertion ) {
 | 
|---|
| 378 |                 if ( auto * assertionObject = assertion.as<ast::ObjectDecl>() ) {
 | 
|---|
| 379 |                         if ( auto * ptrTy = assertionObject->type.as<ast::PointerType>() ) {
 | 
|---|
| 380 |                                 return ptrTy->base.as<ast::FunctionType>();
 | 
|---|
| 381 |                         } else {
 | 
|---|
| 382 |                                 return assertionObject->type.as<ast::FunctionType>();
 | 
|---|
| 383 |                         }
 | 
|---|
| 384 |                 } else if ( auto * assertionDecl = assertion.as<ast::FunctionDecl>() ) {
 | 
|---|
| 385 |                         return assertionDecl->type;
 | 
|---|
| 386 |                 }
 | 
|---|
| 387 |                 return nullptr;
 | 
|---|
| 388 |         }
 | 
|---|
| 389 | 
 | 
|---|
| 390 |         void analyzeFunctionDecl( const ast::FunctionDecl * decl ) {
 | 
|---|
| 391 |                 Stats & stats = by_linkage[ linkage_index( decl->linkage ) ];
 | 
|---|
| 392 | 
 | 
|---|
| 393 |                 ++stats.n_decls;
 | 
|---|
| 394 |                 const ast::FunctionType * type = decl->type.get();
 | 
|---|
| 395 |                 const ast::FunctionType::ForallList & forall = type->forall;
 | 
|---|
| 396 |                 ++stats.n_type_params.at( forall.size() );
 | 
|---|
| 397 |                 unsigned num_assertions = 0;
 | 
|---|
| 398 |                 for ( const ast::ptr<ast::TypeInstType> & instType : forall ) {
 | 
|---|
| 399 |                         num_assertions += instType->base->assertions.size();
 | 
|---|
| 400 |                         for ( const auto & assertion : instType->base->assertions ) {
 | 
|---|
| 401 |                                 if ( auto assertionType = getAssertionFunctionType( assertion ) ) {
 | 
|---|
| 402 |                                         analyzeFunctionType( assertionType, stats,
 | 
|---|
| 403 |                                                         &Stats::assn_params, &Stats::assn_returns );
 | 
|---|
| 404 |                                 }
 | 
|---|
| 405 |                         }
 | 
|---|
| 406 |                 }
 | 
|---|
| 407 |                 ++stats.n_assns[ num_assertions ];
 | 
|---|
| 408 |                 ++stats.by_name[ decl->name ];
 | 
|---|
| 409 |                 analyzeFunctionType( type, stats, &Stats::params, &Stats::returns );
 | 
|---|
| 410 |         }
 | 
|---|
| 411 | 
 | 
|---|
| 412 |         void analyzeUntypedExpr( const ast::UntypedExpr * expr, unsigned depth ) {
 | 
|---|
| 413 |                 unsigned fanout = expr->args.size();
 | 
|---|
| 414 |                 ++exprs_by_fanout_at_depth[ std::make_pair( depth, fanout ) ];
 | 
|---|
| 415 | 
 | 
|---|
| 416 |                 for ( const ast::ptr<ast::Expr> & arg : expr->args ) {
 | 
|---|
| 417 |                         if ( const auto * untyped = arg.as<ast::UntypedExpr>() ) {
 | 
|---|
| 418 |                                 analyzeUntypedExpr( untyped, depth + 1 );
 | 
|---|
| 419 |                         }
 | 
|---|
| 420 |                 }
 | 
|---|
| 421 |         }
 | 
|---|
| 422 | 
 | 
|---|
| 423 | public:
 | 
|---|
| 424 |         void previsit( const ast::UntypedExpr * expr ) {
 | 
|---|
| 425 |                 visit_children = false;
 | 
|---|
| 426 |                 analyzeUntypedExpr( expr, 0 );
 | 
|---|
| 427 |         }
 | 
|---|
| 428 | 
 | 
|---|
| 429 |         void previsit( const ast::FunctionDecl * decl ) {
 | 
|---|
| 430 |                 const std::string & mangleName = decl->mangleName;
 | 
|---|
| 431 |                 const std::string & indexName = mangleName.empty() ? decl->name : mangleName;
 | 
|---|
| 432 |                 if ( seen_names.insert( indexName ).second ) {
 | 
|---|
| 433 |                         analyzeFunctionDecl( decl );
 | 
|---|
| 434 |                 }
 | 
|---|
| 435 |         }
 | 
|---|
| 436 | 
 | 
|---|
| 437 | private:
 | 
|---|
| 438 | 
 | 
|---|
| 439 |         // Trying to avoid duplication by templates.
 | 
|---|
| 440 |         // I couldn't do it in all cases.
 | 
|---|
| 441 |         template<typename T, typename U>
 | 
|---|
| 442 |         using getter = std::function<U(T const &)>;
 | 
|---|
| 443 | 
 | 
|---|
| 444 |         /// Print a single role, for every linkage and the totals.
 | 
|---|
| 445 |         void printRow( const std::string & name, getter<Stats, unsigned> extract ) {
 | 
|---|
| 446 |                 std::cout << "\"" << name << "\",";
 | 
|---|
| 447 |                 for ( const Stats & stats : by_linkage ) {
 | 
|---|
| 448 |                         std::cout << "," << extract( stats );
 | 
|---|
| 449 |                 }
 | 
|---|
| 450 |                 std::cout << "," << extract( total ) << std::endl;
 | 
|---|
| 451 |         }
 | 
|---|
| 452 | 
 | 
|---|
| 453 |         /// Print every row in a group of maps.
 | 
|---|
| 454 |         template<typename Func>
 | 
|---|
| 455 |         void printAllMap( const std::string & name, Func && extract ) {
 | 
|---|
| 456 |                 // Get all rows from the total stats.
 | 
|---|
| 457 |                 for ( auto & entry : extract( total ) ) {
 | 
|---|
| 458 |                         auto & key = entry.first;
 | 
|---|
| 459 |                         std::cout << "\"" << name << "\"," << key;
 | 
|---|
| 460 |                         for ( const auto & stats : by_linkage ) {
 | 
|---|
| 461 |                                 const auto & map = extract( stats );
 | 
|---|
| 462 |                                 auto it = map.find( key );
 | 
|---|
| 463 |                                 if ( map.end() == it ) {
 | 
|---|
| 464 |                                         std::cout << ",0";
 | 
|---|
| 465 |                                 } else {
 | 
|---|
| 466 |                                         std::cout << "," << it->second;
 | 
|---|
| 467 |                                 }
 | 
|---|
| 468 |                         }
 | 
|---|
| 469 |                         std::cout << "," << entry.second << std::endl;
 | 
|---|
| 470 |                 }
 | 
|---|
| 471 |         }
 | 
|---|
| 472 | 
 | 
|---|
| 473 |         /// Accumalate information, then print every row in the remaining maps.
 | 
|---|
| 474 |         template<typename Func>
 | 
|---|
| 475 |         void printAllSparseHisto( const std::string & name, Func && extract ) {
 | 
|---|
| 476 |                 std::map<unsigned, unsigned> histos[num_named_specs];
 | 
|---|
| 477 |                 std::map<unsigned, unsigned> histo_total;
 | 
|---|
| 478 | 
 | 
|---|
| 479 |                 // Collect all data into the histograms.
 | 
|---|
| 480 |                 for ( const auto & entry : extract( total ) ) {
 | 
|---|
| 481 |                         ++histo_total[ entry.second ];
 | 
|---|
| 482 |                 }
 | 
|---|
| 483 | 
 | 
|---|
| 484 |                 for ( unsigned i = 0 ; i < num_named_specs ; ++i ) {
 | 
|---|
| 485 |                         for ( const auto & entry : extract( by_linkage[i] ) ) {
 | 
|---|
| 486 |                                 ++histos[ i ][ entry.second ];
 | 
|---|
| 487 |                         }
 | 
|---|
| 488 |                 }
 | 
|---|
| 489 | 
 | 
|---|
| 490 |                 // Get all rows from the total stats.
 | 
|---|
| 491 |                 for ( const auto & entry : histo_total ) {
 | 
|---|
| 492 |                         const unsigned & key = entry.first;
 | 
|---|
| 493 |                         std::cout << "\"" << name << "\"," << key;
 | 
|---|
| 494 |                         for ( unsigned i = 0 ; i < num_named_specs ; ++i ) {
 | 
|---|
| 495 |                                 auto it = histos[i].find( key );
 | 
|---|
| 496 |                                 if ( histos[i].end() == it ) {
 | 
|---|
| 497 |                                         std::cout << ",0";
 | 
|---|
| 498 |                                 } else {
 | 
|---|
| 499 |                                         std::cout << "," << it->second;
 | 
|---|
| 500 |                                 }
 | 
|---|
| 501 |                         }
 | 
|---|
| 502 |                         std::cout << "," << entry.second << std::endl;
 | 
|---|
| 503 |                 }
 | 
|---|
| 504 |         }
 | 
|---|
| 505 | 
 | 
|---|
| 506 |         void printAllPack( const std::string & name, ArgPackStats Stats::* field ) {
 | 
|---|
| 507 |                 printAllMap("n_basic_" + name, [&field](const Stats& stats) { return (stats.*field).n_basic; });
 | 
|---|
| 508 |                 printAllMap("n_generic_" + name, [&field](const Stats& stats) { return (stats.*field).n_generic; });
 | 
|---|
| 509 |                 printAllMap("n_poly_" + name, [&field](const Stats& stats) { return (stats.*field).n_poly; });
 | 
|---|
| 510 |                 printAllMap("n_compound_" + name, [&field](const Stats& stats) { return (stats.*field).n_compound; });
 | 
|---|
| 511 |                 printAllMap("n_" + name, [&field](const Stats& stats) { return (stats.*field).n; });
 | 
|---|
| 512 |                 printAllMap("%_basic_" + name, [&field](const Stats& stats) { return (stats.*field).p_basic; });
 | 
|---|
| 513 |                 printAllMap("%_generic_" + name, [&field](const Stats& stats) { return (stats.*field).p_generic; });
 | 
|---|
| 514 |                 printAllMap("%_poly_" + name, [&field](const Stats& stats) { return (stats.*field).p_poly; });
 | 
|---|
| 515 |                 printAllMap("%_compound_" + name, [&field](const Stats& stats) { return (stats.*field).p_compound; });
 | 
|---|
| 516 |                 printAllMap("n_distinct_types_" + name, [&field](const Stats& stats) { return (stats.*field).n_types; });
 | 
|---|
| 517 |                 printAllMap("%_new_types_in_" + name, [&field](const Stats& stats) { return (stats.*field).p_new; });
 | 
|---|
| 518 |         }
 | 
|---|
| 519 | 
 | 
|---|
| 520 |         static void printPairMap (
 | 
|---|
| 521 |                         const std::string & name,
 | 
|---|
| 522 |                         const std::map<std::pair<unsigned, unsigned>, unsigned> & map ) {
 | 
|---|
| 523 |                 for ( const auto & entry : map ) {
 | 
|---|
| 524 |                         const auto & key = entry.first;
 | 
|---|
| 525 |                         std::cout << "\"" << name << "\"," << key.first << ','
 | 
|---|
| 526 |                                 << key.second << ',' << entry.second << std::endl;
 | 
|---|
| 527 |                 }
 | 
|---|
| 528 |         }
 | 
|---|
| 529 | 
 | 
|---|
| 530 | public:
 | 
|---|
| 531 |         void print() {
 | 
|---|
| 532 |                 for ( auto & stats : by_linkage ) {
 | 
|---|
| 533 |                         total += stats;
 | 
|---|
| 534 |                 }
 | 
|---|
| 535 | 
 | 
|---|
| 536 |                 std::cout << ",,\"intrinsic\",\"Cforall\",\"C\",\"autogen\",\"compiler\",\"builtinCFA\",\"builtinC\",\"other\",\"TOTAL\"" << std::endl;
 | 
|---|
| 537 | 
 | 
|---|
| 538 |                 printAllMap("n_type_params", [](const Stats& stats) { return stats.n_type_params; });
 | 
|---|
| 539 |                 printAllMap("n_generic_params", [](const Stats& stats) { return stats.n_generic_params; });
 | 
|---|
| 540 |                 printAllMap("n_generic_nesting", [](const Stats& stats) { return stats.n_generic_nesting; });
 | 
|---|
| 541 |                 printRow("n_decls", [](const Stats& stats) { return stats.n_decls; });
 | 
|---|
| 542 |                 printRow("unique_names", [](const Stats& stats) { return stats.by_name.size(); });
 | 
|---|
| 543 |                 printAllSparseHisto("overloads", [](const Stats& stats) { return stats.by_name; });
 | 
|---|
| 544 |                 printRow("basic_type_names", [](const Stats& stats) { return stats.basic_type_names.size(); });
 | 
|---|
| 545 |                 printAllSparseHisto("basic_type_uses", [](const Stats& stats) { return stats.basic_type_names; });
 | 
|---|
| 546 |                 printAllSparseHisto("decls_using_basic_type", [](const Stats& stats) { return stats.basic_type_decls; });
 | 
|---|
| 547 |                 printRow("generic_type_names", [](const Stats& stats) { return stats.generic_type_names.size(); });
 | 
|---|
| 548 |                 printAllSparseHisto("generic_type_uses", [](const Stats& stats) { return stats.generic_type_names; });
 | 
|---|
| 549 |                 printAllSparseHisto("decls_using_generic_type", [](const Stats& stats) { return stats.generic_type_decls; });
 | 
|---|
| 550 |                 printRow("compound_type_names", [](const Stats& stats) { return stats.compound_type_names.size(); });
 | 
|---|
| 551 |                 printAllSparseHisto("compound_type_uses", [](const Stats& stats) { return stats.compound_type_names; });
 | 
|---|
| 552 |                 printAllSparseHisto("decls_using_compound_type", [](const Stats& stats) { return stats.compound_type_decls; });
 | 
|---|
| 553 |                 printAllPack("params", &Stats::params);
 | 
|---|
| 554 |                 printAllPack("returns", &Stats::returns);
 | 
|---|
| 555 |                 printAllMap("n_assns", [](const Stats& stats) { return stats.n_assns; });
 | 
|---|
| 556 |                 printAllPack("assn_params", &Stats::assn_params);
 | 
|---|
| 557 |                 printAllPack("assn_returns", &Stats::assn_returns);
 | 
|---|
| 558 |                 std::cout << std::endl;
 | 
|---|
| 559 | 
 | 
|---|
| 560 |                 printPairMap( "exprs by depth+fanout", exprs_by_fanout_at_depth );
 | 
|---|
| 561 |         }
 | 
|---|
| 562 | };
 | 
|---|
| 563 | 
 | 
|---|
| 564 | } // namespace
 | 
|---|
| 565 | 
 | 
|---|
| 566 | void printDeclStats( ast::TranslationUnit & translationUnit ) {
 | 
|---|
| 567 |         ast::Pass<DeclStats> stats;
 | 
|---|
| 568 |         accept_all( translationUnit, stats );
 | 
|---|
| 569 |         stats.core.print();
 | 
|---|
| 570 | }
 | 
|---|
| 571 | 
 | 
|---|
| 572 | // Local Variables: //
 | 
|---|
| 573 | // tab-width: 4 //
 | 
|---|
| 574 | // mode: c++ //
 | 
|---|
| 575 | // compile-command: "make install" //
 | 
|---|
| 576 | // End: //
 | 
|---|