/// \file ModuleStatistics.cpp // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/IR/DebugInfo.h" #include "llvm/IR/TypeFinder.h" #include "revng/ADT/ZipMapIterator.h" #include "revng/Support/IRHelpers.h" #include "revng/Support/ModuleStatistics.h" #include "revng/Support/Tag.h" using namespace llvm; static void emitIncrement(llvm::raw_ostream &Output, unsigned NewValue, unsigned OldValue) { if (OldValue == 0) { Output << " (+Inf%)"; return; } unsigned Increment = 100 * NewValue / OldValue; Output << " ("; if (Increment >= 0) Output << "+"; Output << Increment; Output << "%)"; } static void emitIndentation(llvm::raw_ostream &Output, unsigned Indent) { for (unsigned I = 0; I < Indent; ++I) Output << " "; } void FunctionClass::dump(llvm::raw_ostream &Output, unsigned Indent, const FunctionClass *Old) const { static const FunctionClass Empty; bool HasOld = Old != nullptr; if (not HasOld) Old = &Empty; auto Emit = [&](StringRef Name, unsigned NewValue, unsigned OldValue) { emitIndentation(Output, Indent); Output << Name.str() << ": " << NewValue; if (HasOld) emitIncrement(Output, NewValue, OldValue); Output << "\n"; }; Emit("DeclarationsCount", DeclarationsCount, Old->DeclarationsCount); Emit("DefinitionsCount", DefinitionsCount, Old->DefinitionsCount); emitIndentation(Output, Indent); Output << "InstructionsStatistics: "; Output << InstructionsStatistics.toString(); if (HasOld) { emitIncrement(Output, InstructionsStatistics.sum(), Old->InstructionsStatistics.sum()); } Output << "\n"; } void ModuleStatistics::dump(llvm::raw_ostream &Output, unsigned Indent, const ModuleStatistics *Old) const { static const ModuleStatistics Empty; bool HasOld = Old != nullptr; if (not HasOld) Old = &Empty; auto Emit = [&](StringRef Name, unsigned NewValue, unsigned OldValue) { emitIndentation(Output, Indent); Output << Name.str() << ": " << NewValue; if (HasOld) emitIncrement(Output, NewValue, OldValue); Output << "\n"; }; #define EMIT(FieldName) \ do { \ Emit(#FieldName, FieldName, Old->FieldName); \ } while (0) EMIT(NamedGlobalsCount); EMIT(AnonymousGlobalsCount); EMIT(AliasesCount); EMIT(NamedMetadataCount); EMIT(MaxNamedMetadataSize); EMIT(MaxArrayElements); EMIT(MaxStructElements); emitIndentation(Output, Indent); Output << "AllFunctions:\n"; AllFunctions.dump(Output, Indent + 1, HasOld ? &Old->AllFunctions : nullptr); emitIndentation(Output, Indent); Output << "TaggedFunctions:\n"; for (auto &&[NewEntry, OldEntry] : zipmap_range(TaggedFunctions, Old->TaggedFunctions)) { const FunctionTags::Tag *Tag = nullptr; static const FunctionClass Empty; const FunctionClass *NewClass = nullptr; if (NewEntry == nullptr) { NewClass = &Empty; Tag = OldEntry->first; } else { Tag = NewEntry->first; NewClass = &NewEntry->second; } Output << " " << Tag->name().str() << "\n"; const FunctionClass *Other = nullptr; if (HasOld and OldEntry != nullptr) Other = &OldEntry->second; NewClass->dump(Output, Indent + 2, Other); } EMIT(NamedStructsCount); EMIT(AnonymousStructsCount); EMIT(DebugCompileUnitsCount); EMIT(DebugScopesCount); EMIT(DebugSubprogramsCount); EMIT(DebugGloblaVariablesCount); EMIT(DebugTypesCount); #undef EMIT } ModuleStatistics ModuleStatistics::analyze(const llvm::Module &M) { using namespace FunctionTags; ModuleStatistics Result; // Count global variables for (const GlobalVariable &Global : M.globals()) { if (Global.hasName()) ++Result.NamedGlobalsCount; else ++Result.AnonymousGlobalsCount; } // Count aliases Result.AliasesCount = M.alias_size(); // Count named metadata Result.NamedMetadataCount = M.named_metadata_size(); // Measure size of named metadata for (const NamedMDNode &MD : M.named_metadata()) { Result.MaxNamedMetadataSize = std::max(Result.MaxNamedMetadataSize, MD.getNumOperands()); } // Measure functions for (const Function &F : M) { Result.AllFunctions.process(F); for (const Tag *FunctionTag : TagsSet::from(&F)) Result.TaggedFunctions[FunctionTag].process(F); } // Measure types { std::set Types; // TODO: there would be much more stuff to look for for (const GlobalVariable &GV : M.globals()) collectTypes(GV.getValueType(), Types); for (const Function &F : M) collectTypes(F.getType(), Types); for (Type *T : Types) { if (auto *Struct = dyn_cast(T)) { if (Struct->hasName()) ++Result.NamedStructsCount; else ++Result.AnonymousStructsCount; Result.MaxStructElements = std::max(Result.MaxStructElements, Struct->getNumElements()); } else if (auto *Array = dyn_cast(T)) { unsigned Elements = Array->getNumElements(); Result.MaxArrayElements = std::max(Result.MaxArrayElements, Elements); } } } // Measure debug info { DebugInfoFinder DIFinder; DIFinder.processModule(M); Result.DebugCompileUnitsCount = DIFinder.compile_unit_count(); Result.DebugScopesCount = DIFinder.scope_count(); Result.DebugSubprogramsCount = DIFinder.subprogram_count(); Result.DebugGloblaVariablesCount = DIFinder.global_variable_count(); Result.DebugTypesCount = DIFinder.type_count(); } return Result; }