Files
revng-revng/lib/Support/ModuleStatistics.cpp
T
Ivan Krysak 7d235f4fd0 Enforce licence header consistency
Also do some basic cleanup: capitalize first letters, add `.`
at the end of the sentences, and so on.
2023-07-03 15:23:10 +00:00

208 lines
5.7 KiB
C++

/// \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"
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<llvm::Type *> 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<StructType>(T)) {
if (Struct->hasName())
++Result.NamedStructsCount;
else
++Result.AnonymousStructsCount;
Result.MaxStructElements = std::max(Result.MaxStructElements,
Struct->getNumElements());
} else if (auto *Array = dyn_cast<ArrayType>(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;
}