mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
7d235f4fd0
Also do some basic cleanup: capitalize first letters, add `.` at the end of the sentences, and so on.
208 lines
5.7 KiB
C++
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;
|
|
}
|