Files
revng-revng/lib/DataLayoutAnalysis/Middleend/DLACollapseIdentityAndInheritanceCC.cpp
T
Alvise de Faveri 4c8215fc47 DLA: Add pointers
* 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.
2021-11-16 17:00:34 +01:00

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