mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
4c8215fc47
* Changes to the `LayoutTypeSystem` graph
Pointers are identified in the TypeSystem graph as leaf nodes which
have a new type of edge (PointerEdge) that connects them to another
node of the graph. The destination of the edge represents the layout of
the pointed type.
* Changes to the Front-end
Pointer edges, and their destination nodes, are created by the DLA
front-end (`DLACreateIntraProceduralTypes`) whenever an access node has
a size that is compatible with the size of a pointer in the current
Architecture.
Successors might then be added to the newly generated node, if any,
by looking up the llvm::Value it is attached to.
* Changes to the Middle-end
Most of the DLA passes should ignore Pointer Edges, so they are modified
accordingly. Most notably, nodes that represent pointed layouts should
never be merged/pruned-off.
* Changes to the Back-end
The `TypeDeclCreationAction` of the decompiler and the `DLAMakeLayouts`
step of the DLA back-end are modified to take into account the new
information about pointers.
⚠️ There is a known issue with this version of the decompiler,
namely the fact that type loops are not detected and can cause the
emitter to enter an infinite loop.
143 lines
4.5 KiB
C++
143 lines
4.5 KiB
C++
//
|
|
// Copyright (c) rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <set>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/ADT/SCCIterator.h"
|
|
|
|
#include "revng/ADT/FilteredGraphTraits.h"
|
|
#include "revng/Support/Debug.h"
|
|
|
|
#include "revng-c/DataLayoutAnalysis/DLATypeSystem.h"
|
|
|
|
#include "../DLAHelpers.h"
|
|
#include "DLAStep.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static Logger<> LogVerbose("dla-collapse-verbose");
|
|
static Logger<> Log("dla-collapse");
|
|
|
|
namespace dla {
|
|
|
|
using LTSN = LayoutTypeSystemNode;
|
|
using GraphNodeT = LTSN *;
|
|
using InstanceNodeT = EdgeFilteredGraph<GraphNodeT, isInstanceEdge>;
|
|
using InheritanceNodeT = EdgeFilteredGraph<GraphNodeT, isInheritanceEdge>;
|
|
using EqualityNodeT = EdgeFilteredGraph<GraphNodeT, isEqualityEdge>;
|
|
using NonPointerNodeT = EdgeFilteredGraph<GraphNodeT, isNotPointerEdge>;
|
|
|
|
template<typename NodeT>
|
|
static bool collapseSCCs(LayoutTypeSystem &TS) {
|
|
|
|
std::set<GraphNodeT> VisitedNodes;
|
|
|
|
using scc_t = std::vector<GraphNodeT>;
|
|
llvm::SmallVector<scc_t, 0> ToCollapse;
|
|
|
|
// We cannot start just from the roots because we cannot exclude that there
|
|
// are loops without entries.
|
|
for (const auto &Node : llvm::nodes(&TS)) {
|
|
revng_assert(Node != nullptr);
|
|
revng_log(LogVerbose, "## Analyzing SCCs from " << Node);
|
|
if (VisitedNodes.count(Node)) {
|
|
revng_log(LogVerbose, "## Was already visited");
|
|
continue;
|
|
}
|
|
|
|
llvm::scc_iterator<NodeT> I = llvm::scc_begin(NodeT(NonPointerNodeT(Node)));
|
|
llvm::scc_iterator<NodeT> E = llvm::scc_end(NodeT(NonPointerNodeT(Node)));
|
|
for (const auto &SCC : llvm::make_range(I, E)) {
|
|
revng_assert(not SCC.empty());
|
|
if (VisitedNodes.count(SCC[0]))
|
|
continue;
|
|
VisitedNodes.insert(SCC.begin(), SCC.end());
|
|
|
|
if (LogVerbose.isEnabled()) {
|
|
revng_log(LogVerbose, "# SCC has " << SCC.size() << " elements:");
|
|
size_t I = 0;
|
|
for (const LTSN *N : SCC)
|
|
revng_log(LogVerbose, " - " << I << ": " << N);
|
|
revng_log(LogVerbose, "# SCC End");
|
|
}
|
|
|
|
// If the SCC is larger than just a single point we track all the nodes
|
|
// that compose it as EqualityVisitedNodes, and we then add the SCC to the
|
|
// set of SCC ToCollapse.
|
|
if (SCC.size() > 1)
|
|
ToCollapse.push_back(SCC);
|
|
}
|
|
}
|
|
revng_log(LogVerbose, "## Collapsing " << ToCollapse.size() << " SCCs");
|
|
|
|
for (scc_t &SCC : ToCollapse) {
|
|
revng_log(LogVerbose, "# SCC with " << SCC.size() << " elements");
|
|
TS.mergeNodes(SCC);
|
|
}
|
|
|
|
return ToCollapse.size();
|
|
}
|
|
|
|
static bool collapseInheritanceSCC(LayoutTypeSystem &TS) {
|
|
using InheritanceGraph = EdgeFilteredGraph<NonPointerNodeT,
|
|
isInheritanceEdge>;
|
|
return collapseSCCs<InheritanceGraph>(TS);
|
|
}
|
|
|
|
static bool collapseEqualitySCC(LayoutTypeSystem &TS) {
|
|
return collapseSCCs<EdgeFilteredGraph<NonPointerNodeT, isEqualityEdge>>(TS);
|
|
}
|
|
|
|
bool CollapseIdentityAndInheritanceCC::runOnTypeSystem(LayoutTypeSystem &TS) {
|
|
if (Log.isEnabled())
|
|
TS.dumpDotOnFile("before-collapse.dot");
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyConsistency());
|
|
|
|
revng_log(LogVerbose, "#### Merging Equality SCC: ... ");
|
|
bool CollapsedEqual = collapseEqualitySCC(TS);
|
|
revng_log(LogVerbose, "#### Merging Equality SCC: Done!");
|
|
|
|
if (Log.isEnabled())
|
|
TS.dumpDotOnFile("after-collapse-equality.dot");
|
|
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyNoEquality());
|
|
|
|
revng_log(LogVerbose, "#### Merging Inheritance SCC: ... ");
|
|
bool CollapsedInheritance = collapseInheritanceSCC(TS);
|
|
revng_log(LogVerbose, "#### Merging Inheritance SCC: Done!");
|
|
|
|
if (Log.isEnabled())
|
|
TS.dumpDotOnFile("after-collapse-inheritance.dot");
|
|
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyInheritanceDAG());
|
|
|
|
// The following assertion is not really necessary.
|
|
// In principle all the rest of the pipeline should work fine without it, but
|
|
// I think that if it's triggered something might be wrong in how we emit
|
|
// instance edges earlier. If it's ever triggered, please double check.
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyInstanceDAG());
|
|
|
|
revng_log(LogVerbose, "#### Merging Mixed SCC: ... ");
|
|
bool Removed = false;
|
|
Removed = removeInstanceBackedgesFromInheritanceLoops(TS);
|
|
revng_log(LogVerbose, "#### Merging Mixed SCC: Done!");
|
|
|
|
if (Log.isEnabled())
|
|
TS.dumpDotOnFile("after-collapse.dot");
|
|
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyDAG());
|
|
|
|
return CollapsedEqual or CollapsedInheritance or Removed;
|
|
}
|
|
|
|
} // end namespace dla
|