Files
revng-revng/lib/DataLayoutAnalysis/Middleend/DLACollapseSingleChild.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

104 lines
2.9 KiB
C++

//
// Copyright (c) rev.ng Srls. See LICENSE.md for details.
//
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "revng/Support/Assert.h"
#include "revng/Support/Debug.h"
#include "revng-c/DataLayoutAnalysis/DLATypeSystem.h"
#include "../DLAHelpers.h"
#include "DLAStep.h"
using LTSN = dla::LayoutTypeSystemNode;
using VecToCollapseT = std::vector<LTSN *>;
using NonPointerFilterT = EdgeFilteredGraph<LTSN *, dla::isNotPointerEdge>;
using Link = dla::LayoutTypeSystemNode::Link;
using namespace llvm;
static Logger<> Log("dla-collapse-single-child");
namespace dla {
bool CollapseSingleChild::collapseSingle(LayoutTypeSystem &TS,
LayoutTypeSystemNode *Node) {
bool Changed = false;
auto HasSingleChild = [](const LTSN *Node) {
return (Node->Successors.size() == 1);
};
auto ChildIsInstanceOrInheritance = [](const LTSN *Node) {
auto &Child = *Node->Successors.begin();
return (isInstanceEdge(Child) or isInheritanceEdge(Child));
};
auto HasAtMostOneParent = [](const LTSN *Node) {
return (Node->Predecessors.size() <= 1);
};
if (VerifyLog.isEnabled() and not HasSingleChild(Node)) {
revng_assert(llvm::none_of(Node->Successors,
[](const Link &L) { return isPointerEdge(L); }));
}
// Get nodes that have a single instance or inheritance child
if (HasSingleChild(Node) and ChildIsInstanceOrInheritance(Node)) {
auto &ChildEdge = *(Node->Successors.begin());
const unsigned ChildOffset = isInheritanceEdge(ChildEdge) ?
0U :
ChildEdge.second->getOffsetExpr().Offset;
auto &ToMerge = ChildEdge.first;
// Don't collapse if the child has more than one parent
if (not HasAtMostOneParent(ToMerge))
return false;
// Collapse only if the child is at offset 0
if (ChildOffset == 0) {
revng_log(Log, "Collapsing " << ToMerge->ID << " into " << Node->ID);
const unsigned ChildSize = ToMerge->Size;
revng_assert(Node->Size == 0 or Node->Size == ChildSize);
// Merge single child into parent
TS.mergeNodes({ /*Into=*/Node, /*From=*/ToMerge });
Node->Size = ChildSize;
Changed = true;
}
}
return Changed;
}
bool CollapseSingleChild::runOnTypeSystem(LayoutTypeSystem &TS) {
bool Changed = false;
if (VerifyLog.isEnabled())
revng_assert(TS.verifyDAG() and TS.verifyInheritanceTree());
if (Log.isEnabled())
TS.dumpDotOnFile("before-collapse-single-child.dot");
for (LTSN *Root : llvm::nodes(&TS)) {
revng_assert(Root != nullptr);
if (not isRoot(Root))
continue;
for (LTSN *Node : post_order(Root))
Changed |= collapseSingle(TS, Node);
}
if (Log.isEnabled())
TS.dumpDotOnFile("after-collapse-single-child.dot");
if (VerifyLog.isEnabled())
revng_assert(TS.verifyInheritanceDAG() and TS.verifyInheritanceTree());
return Changed;
}
} // end namespace dla