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.
130 lines
4.2 KiB
C++
130 lines
4.2 KiB
C++
//
|
|
// Copyright (c) rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "revng/ADT/FilteredGraphTraits.h"
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/Debug.h"
|
|
|
|
#include "revng-c/DataLayoutAnalysis/DLATypeSystem.h"
|
|
|
|
#include "../DLAHelpers.h"
|
|
#include "DLAStep.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static Logger<> Log("dla-compute-upper-member-access");
|
|
|
|
namespace dla {
|
|
|
|
using LTSN = LayoutTypeSystemNode;
|
|
using GraphNodeT = LTSN *;
|
|
using NonPointerFilterT = EdgeFilteredGraph<GraphNodeT, isNotPointerEdge>;
|
|
using ConstNonPointerFilterT = EdgeFilteredGraph<const LTSN *,
|
|
isNotPointerEdge>;
|
|
|
|
bool ComputeUpperMemberAccesses::runOnTypeSystem(LayoutTypeSystem &TS) {
|
|
if (VerifyLog.isEnabled())
|
|
revng_assert(TS.verifyDAG() and TS.verifyInheritanceTree());
|
|
bool Changed = false;
|
|
|
|
using LTSN = LayoutTypeSystemNode;
|
|
|
|
std::set<const LTSN *> Visited;
|
|
for (LTSN *Root : llvm::nodes(&TS)) {
|
|
revng_assert(Root != nullptr);
|
|
// Leaves need to have ValidLayouts, otherwise they should have been trimmed
|
|
// by PruneLayoutNodesWithoutLayout
|
|
revng_assert(not isLeaf(Root) or Root->Size);
|
|
if (not isRoot(Root))
|
|
continue;
|
|
|
|
revng_assert(isInheritanceRoot(Root));
|
|
|
|
for (LTSN *N : post_order_ext(NonPointerFilterT(Root), Visited)) {
|
|
revng_assert(not isLeaf(N) or N->Size);
|
|
uint64_t FinalSize = N->Size;
|
|
|
|
// Look at all the instance-of edges and inheritance edges all together.
|
|
bool HasBaseClass = false;
|
|
for (auto &[Child, EdgeTag] : children_edges<ConstNonPointerFilterT>(N)) {
|
|
auto ChildSize = Child->Size;
|
|
revng_assert(ChildSize > 0LL);
|
|
|
|
switch (EdgeTag->getKind()) {
|
|
|
|
case TypeLinkTag::LK_Inheritance: {
|
|
// Treated as instance at offset 0, but can only have one.
|
|
// Should only have one parent in inheritance hierarchy.
|
|
revng_assert(not HasBaseClass);
|
|
HasBaseClass = true;
|
|
FinalSize = std::max(FinalSize, ChildSize);
|
|
} break;
|
|
|
|
case TypeLinkTag::LK_Instance: {
|
|
const OffsetExpression &OE = EdgeTag->getOffsetExpr();
|
|
revng_assert(OE.Strides.size() == OE.TripCounts.size());
|
|
|
|
// Ignore stuff at negative offsets.
|
|
revng_assert(OE.Offset >= 0LL);
|
|
|
|
// If we have an array, we have to compute its size, taking into
|
|
// account the strides and the trip counts.
|
|
for (const auto &[TripCount, Stride] :
|
|
llvm::reverse(llvm::zip(OE.TripCounts, OE.Strides))) {
|
|
|
|
revng_assert(Stride > 0LL);
|
|
auto StrideSize = static_cast<uint64_t>(Stride);
|
|
|
|
// If we have a TripCount, we expect it to be strictly positive.
|
|
revng_assert(not TripCount.has_value() or TripCount.value() > 0LL);
|
|
|
|
// Arrays with unknown numbers of elements are considered as if
|
|
// they had a single element
|
|
auto NumElems = TripCount.has_value() ? TripCount.value() : 1;
|
|
revng_assert(NumElems);
|
|
|
|
// Here we are computing the larger size that is known to be
|
|
// accessed. So if we have an array, we consider it to be one
|
|
// element shorter than expected, and we add ChildSize only once
|
|
// at the end.
|
|
// This is equivalent to:
|
|
// ChildSize = (NumElems * StrideSize) - (StrideSize - ChildSize);
|
|
ChildSize = ((NumElems - 1) * StrideSize) + ChildSize;
|
|
}
|
|
|
|
revng_assert(ChildSize);
|
|
|
|
int64_t ChildOffset = std::max<int64_t>(OE.Offset, 0LL);
|
|
uint64_t ChildUpperOffset = ChildOffset + ChildSize;
|
|
FinalSize = std::max(FinalSize, ChildUpperOffset);
|
|
} break;
|
|
|
|
default:
|
|
revng_unreachable("unexpected edge");
|
|
}
|
|
}
|
|
if (FinalSize != N->Size)
|
|
Changed = true;
|
|
|
|
N->Size = FinalSize;
|
|
revng_assert(FinalSize);
|
|
}
|
|
}
|
|
|
|
if (Log.isEnabled())
|
|
TS.dumpDotOnFile("after-compute-upper-member-access.dot");
|
|
|
|
return Changed;
|
|
}
|
|
|
|
} // end namespace dla
|