diff --git a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h index 8c49fcaea..30bcc41d2 100644 --- a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h +++ b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h @@ -174,7 +174,7 @@ public: ///\brief Get all the elements that are in the same equivalence class of \a ID ///\note Expensive: performs a linear scan of all the elements - std::set getEqClass(const unsigned ID) const; + std::vector getEqClass(const unsigned ID) const; ///\brief Check if \a ID1 and \a ID2 have the same equivalence class bool haveSameEqClass(unsigned ID1, unsigned ID2) const; diff --git a/lib/DataLayoutAnalysis/CMakeLists.txt b/lib/DataLayoutAnalysis/CMakeLists.txt index af20d4b1b..2b0aa058b 100644 --- a/lib/DataLayoutAnalysis/CMakeLists.txt +++ b/lib/DataLayoutAnalysis/CMakeLists.txt @@ -11,6 +11,7 @@ revng_add_analyses_library(DataLayoutAnalysis revngc Middleend/DLAPruneLayoutNodesWithoutLayout.cpp Middleend/DLARemoveTransitiveInheritanceEdges.cpp Middleend/DLAMakeInheritanceTree.cpp + Middleend/DLACollapseSingleChild.cpp Middleend/DLAStep.cpp Backend/DLAMakeLayouts.cpp DLAHelpers.cpp diff --git a/lib/DataLayoutAnalysis/DLAPass.cpp b/lib/DataLayoutAnalysis/DLAPass.cpp index d2c4e94ff..5dbe4ccb5 100644 --- a/lib/DataLayoutAnalysis/DLAPass.cpp +++ b/lib/DataLayoutAnalysis/DLAPass.cpp @@ -52,6 +52,7 @@ bool DLAPass::runOnModule(llvm::Module &M) { revng_check(SM.addStep()); revng_check(SM.addStep()); revng_check(SM.addStep()); + revng_check(SM.addStep()); revng_check(SM.addStep()); revng_check(SM.addStep()); revng_check(SM.addStep()); diff --git a/lib/DataLayoutAnalysis/DLATypeSystem.cpp b/lib/DataLayoutAnalysis/DLATypeSystem.cpp index 60504dd52..37d68204f 100644 --- a/lib/DataLayoutAnalysis/DLATypeSystem.cpp +++ b/lib/DataLayoutAnalysis/DLATypeSystem.cpp @@ -677,12 +677,12 @@ std::optional VectEqClasses::getEqClassID(const unsigned ID) const { return EqID; } -std::set VectEqClasses::getEqClass(const unsigned ElemID) const { - std::set EqClass; +std::vector VectEqClasses::getEqClass(const unsigned ElemID) const { + std::vector EqClass; for (unsigned OtherID = 0; OtherID < NElems; OtherID++) if (haveSameEqClass(ElemID, OtherID)) - EqClass.insert(OtherID); + EqClass.push_back(OtherID); return EqClass; } diff --git a/lib/DataLayoutAnalysis/Middleend/DLACollapseSingleChild.cpp b/lib/DataLayoutAnalysis/Middleend/DLACollapseSingleChild.cpp new file mode 100644 index 000000000..f359191ef --- /dev/null +++ b/lib/DataLayoutAnalysis/Middleend/DLACollapseSingleChild.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) rev.ng Srls. See LICENSE.md for details. +// + +#include "llvm/ADT/PostOrderIterator.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; + +using namespace llvm; + +static Logger<> Log("dla-collapse-single-child"); + +namespace dla { + +bool CollapseSingleChild::runOnTypeSystem(LayoutTypeSystem &TS) { + bool Changed = false; + if (VerifyLog.isEnabled()) + revng_assert(TS.verifyDAG()); + + if (Log.isEnabled()) + TS.dumpDotOnFile("before-collapse-single-child.dot"); + + auto HasSingleChild = [](const LTSN *Node) { + return (Node->Successors.size() == 1); + }; + + auto FirstChildIsInstance = [](const LTSN *Node) { + return (isInstanceEdge(*Node->Successors.begin())); + }; + + // Find roots + for (LTSN *Root : llvm::nodes(&TS)) { + revng_assert(Root != nullptr); + if (not isRoot(Root)) + continue; + + // Visit their sub-tree in post order + for (LTSN *Node : post_order(Root)) { + if (HasSingleChild(Node) and FirstChildIsInstance(Node)) { + auto &ChildEdge = *(Node->Successors.begin()); + auto &OE = ChildEdge.second->getOffsetExpr(); + auto &ToMerge = ChildEdge.first; + + // Get nodes that have a single instance child at offset 0 + if (OE.Offset == 0) { + revng_log(Log, "Collapsing " << ToMerge->ID << " into " << Node->ID); + + const unsigned ChildSize = ToMerge->Size; + revng_assert(Node->Size == 0); + + // Merge single child into parent + TS.mergeNodes({ /*Into=*/Node, /*From=*/ToMerge }); + Node->InterferingInfo = AllChildrenAreNonInterfering; + Node->Size = ChildSize; + + Changed = true; + } + } + } + } + + if (Log.isEnabled()) + TS.dumpDotOnFile("after-collapse-single-child.dot"); + if (VerifyLog.isEnabled()) { + revng_assert(TS.verifyInheritanceDAG()); + revng_assert(TS.verifyInheritanceTree()); + } + + return Changed; +} + +} // end namespace dla diff --git a/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp b/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp index 8ef46fece..d403c14a5 100644 --- a/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp +++ b/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp @@ -17,6 +17,7 @@ const char ComputeUpperMemberAccesses::ID = 0; const char CollapseCompatibleArrays::ID = 0; const char PropagateInheritanceToAccessors::ID = 0; const char ComputeNonInterferingComponents::ID = 0; +const char CollapseSingleChild::ID = 0; static Logger<> DLAStepManagerLog("dla-step-manager"); diff --git a/lib/DataLayoutAnalysis/Middleend/DLAStep.h b/lib/DataLayoutAnalysis/Middleend/DLAStep.h index 0b02c139d..1e3683961 100644 --- a/lib/DataLayoutAnalysis/Middleend/DLAStep.h +++ b/lib/DataLayoutAnalysis/Middleend/DLAStep.h @@ -186,6 +186,26 @@ public: virtual bool runOnTypeSystem(LayoutTypeSystem &TS) override { return true; } }; +/// dla::Step that collapses nodes that have a single inheritance child at +/// offset 0 +class CollapseSingleChild : public Step { + static const char ID; + +public: + static const constexpr void *getID() { return &ID; } + + CollapseSingleChild() : + Step(ID, + // Dependencies + {}, + // Invalidated + {}) {} + + virtual ~CollapseSingleChild() override = default; + + virtual bool runOnTypeSystem(LayoutTypeSystem &TS) override; +}; + /// dla::Step that decompose the LayoutTypeSystem into components, each of which /// cannot overlap with others class ComputeNonInterferingComponents : public Step {