diff --git a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h index 4a0644695..f732979fd 100644 --- a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h +++ b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h @@ -308,6 +308,8 @@ public: bool verifyLeafs() const; // Checks that there are no equality edges. bool verifyNoEquality() const; + // Checks that no node conflicting edges. + bool verifyConflicts() const; private: // Equivalence classes between nodes. Each node is identified by an ID. @@ -527,6 +529,15 @@ isInstanceEdge(const llvm::GraphTraits::EdgeRef &E) { return hasLinkKind(E); } +inline bool +isInstanceOff0Edge(llvm::GraphTraits::EdgeRef &E) { + if (not isInstanceEdge(E)) + return false; + + auto &OE = E.second->getOffsetExpr(); + return OE.Offset == 0 and OE.Strides.empty() and OE.TripCounts.empty(); +} + template inline bool isLeaf(const LayoutTypeSystemNode *N) { using LTSN = const LayoutTypeSystemNode; diff --git a/lib/DataLayoutAnalysis/CMakeLists.txt b/lib/DataLayoutAnalysis/CMakeLists.txt index fb8e033cd..b90574fde 100644 --- a/lib/DataLayoutAnalysis/CMakeLists.txt +++ b/lib/DataLayoutAnalysis/CMakeLists.txt @@ -13,6 +13,7 @@ revng_add_analyses_library(DataLayoutAnalysis revngc Middleend/DLARemoveTransitiveInheritanceEdges.cpp Middleend/DLAMakeInheritanceTree.cpp Middleend/DLACollapseSingleChild.cpp + Middleend/DLARemoveConflictingEdges.cpp Middleend/DLAStep.cpp Backend/DLAMakeLayouts.cpp DLAHelpers.cpp diff --git a/lib/DataLayoutAnalysis/DLAPass.cpp b/lib/DataLayoutAnalysis/DLAPass.cpp index 5dbe4ccb5..37fb07fd7 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 6479a4a8b..3888b3fc7 100644 --- a/lib/DataLayoutAnalysis/DLATypeSystem.cpp +++ b/lib/DataLayoutAnalysis/DLATypeSystem.cpp @@ -12,6 +12,7 @@ #include "llvm/Support/raw_ostream.h" #include "revng/ADT/FilteredGraphTraits.h" +#include "revng/Support/Assert.h" #include "revng/Support/Debug.h" #include "revng/Support/DebugHelper.h" @@ -639,6 +640,29 @@ bool LayoutTypeSystem::verifyInheritanceTree() const { return true; } +bool LayoutTypeSystem::verifyConflicts() const { + using GraphNodeT = const LayoutTypeSystemNode *; + using LinkT = const LayoutTypeSystemNode::Link; + + for (GraphNodeT Node : llvm::nodes(this)) { + for (auto &Succ : Node->Successors) { + + auto HasSameSucc = [&Succ](const LinkT &L2) { + return isInstanceOff0Edge(L2) and (Succ.first == L2.first); + }; + + if (isInheritanceEdge(Succ) + and llvm::any_of(Node->Successors, HasSameSucc)) { + if (VerifyDLALog.isEnabled()) + revng_check(false); + return false; + } + } + } + + return true; +} + unsigned VectEqClasses::growBy1() { ++NElems; grow(NElems); diff --git a/lib/DataLayoutAnalysis/Middleend/DLARemoveConflictingEdges.cpp b/lib/DataLayoutAnalysis/Middleend/DLARemoveConflictingEdges.cpp new file mode 100644 index 000000000..711e66e7a --- /dev/null +++ b/lib/DataLayoutAnalysis/Middleend/DLARemoveConflictingEdges.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) rev.ng Srls. See LICENSE.md for details. +// + +#include + +#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; +using Link = dla::LayoutTypeSystemNode::Link; + +using namespace llvm; + +static Logger<> Log("dla-remove-conflicting-edges"); + +namespace dla { + +bool RemoveConflictingEdges::removeConflicts(LayoutTypeSystem &TS, + LayoutTypeSystemNode *Node) { + bool Changed = false; + std::set InhNodes; + for (auto &L : Node->Successors) + if (isInheritanceEdge(L)) + InhNodes.insert(L.first); + + auto It = Node->Successors.begin(); + while (It != Node->Successors.end()) { + auto &L = *It; + if (isInstanceOff0Edge(L) and InhNodes.contains(L.first)) { + // Remove from successor's predecessors + size_t NFound = std::erase_if(L.first->Predecessors, + [Node](const Link &Pred) { + return Pred.first->ID == Node->ID + and isInstanceOff0Edge(Pred); + }); + revng_assert(NFound > 0); + + It = Node->Successors.erase(It); + Changed = true; + } else { + ++It; + } + } + + return Changed; +} + +bool RemoveConflictingEdges::runOnTypeSystem(LayoutTypeSystem &TS) { + bool Changed = false; + if (VerifyLog.isEnabled()) + revng_assert(TS.verifyConsistency() and TS.verifyDAG() + and TS.verifyInheritanceTree()); + if (Log.isEnabled()) + TS.dumpDotOnFile("before-remove-conflicting-edges.dot"); + + for (LTSN *Node : llvm::nodes(&TS)) + Changed |= removeConflicts(TS, Node); + + if (Log.isEnabled()) + TS.dumpDotOnFile("after-remove-conflicting-edges.dot"); + if (VerifyLog.isEnabled()) { + revng_assert(TS.verifyConsistency()); + revng_assert(TS.verifyInheritanceDAG()); + revng_assert(TS.verifyInheritanceTree()); + } + + return Changed; +} +} // namespace dla \ No newline at end of file diff --git a/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp b/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp index d403c14a5..c2a8b66b0 100644 --- a/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp +++ b/lib/DataLayoutAnalysis/Middleend/DLAStep.cpp @@ -18,6 +18,7 @@ const char CollapseCompatibleArrays::ID = 0; const char PropagateInheritanceToAccessors::ID = 0; const char ComputeNonInterferingComponents::ID = 0; const char CollapseSingleChild::ID = 0; +const char RemoveConflictingEdges::ID = 0; static Logger<> DLAStepManagerLog("dla-step-manager"); diff --git a/lib/DataLayoutAnalysis/Middleend/DLAStep.h b/lib/DataLayoutAnalysis/Middleend/DLAStep.h index 1e3683961..87509c6f0 100644 --- a/lib/DataLayoutAnalysis/Middleend/DLAStep.h +++ b/lib/DataLayoutAnalysis/Middleend/DLAStep.h @@ -186,8 +186,27 @@ public: virtual bool runOnTypeSystem(LayoutTypeSystem &TS) override { return true; } }; -/// dla::Step that collapses nodes that have a single inheritance child at -/// offset 0 +/// Removes instance-of edges that connect nodes with an inheritance edge +class RemoveConflictingEdges : public Step { + static const char ID; + +public: + static const constexpr void *getID() { return &ID; } + static bool removeConflicts(LayoutTypeSystem &TS, LayoutTypeSystemNode *Node); + + RemoveConflictingEdges() : + Step(ID, + // Dependencies + {}, + // Invalidated + {}) {} + + virtual ~RemoveConflictingEdges() override = default; + + virtual bool runOnTypeSystem(LayoutTypeSystem &TS) override; +}; + +/// dla::Step that collapses nodes that have a single child at offset 0 class CollapseSingleChild : public Step { static const char ID; diff --git a/tests/Unit/DLASteps.cpp b/tests/Unit/DLASteps.cpp index 70aa2cc5e..23f59433e 100644 --- a/tests/Unit/DLASteps.cpp +++ b/tests/Unit/DLASteps.cpp @@ -73,13 +73,13 @@ addEquality(LayoutTypeSystem &TS, LTSN *Parent, unsigned ChildSize = 0U) { void checkNode(const LayoutTypeSystem &TS, const LayoutTypeSystemNode *N, const unsigned ExpectedSize, - const InterferingChildrenInfo EpectedInfo, + const InterferingChildrenInfo ExpectedInfo, const std::set &ExpectedEqClass) { const dla::VectEqClasses &Eq = TS.getEqClasses(); revng_check(N); revng_check(not Eq.isRemoved(N->ID)); revng_check(ExpectedSize == N->Size); - revng_check(EpectedInfo == N->InterferingInfo); + revng_check(ExpectedInfo == N->InterferingInfo); const auto &EqClass = Eq.computeEqClass(N->ID); revng_check(EqClass.size() == ExpectedEqClass.size()); @@ -644,9 +644,7 @@ BOOST_AUTO_TEST_CASE(PropagateToAccessors) { revng_check(SM.addStep()); revng_check(SM.addStep()); - TS.dumpDotOnFile("test-before"); SM.run(TS); - TS.dumpDotOnFile("test-after"); // Compress the equivalence classes dla::VectEqClasses &Eq = TS.getEqClasses(); @@ -657,4 +655,35 @@ BOOST_AUTO_TEST_CASE(PropagateToAccessors) { checkNode(TS, NodeA, 16, InterferingChildrenInfo::Unknown, { 0, 1, 2 }); checkNode(TS, NodeD, 8, InterferingChildrenInfo::Unknown, { 3, 4 }); checkNode(TS, NodeF, 8, InterferingChildrenInfo::Unknown, { 5, 6 }); +} + +// ----------------- Remove Conflicting edges -------------- + +BOOST_AUTO_TEST_CASE(RemoveConflictingEdges_basic) { + dla::LayoutTypeSystem TS; + + // Build TS + LTSN *NodeA = createRoot(TS); + LTSN *NodeB = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8); + TS.addInheritanceLink(NodeA, NodeB); + + LTSN *Node1 = createRoot(TS); + LTSN *Node2 = addInstanceAtOffset(TS, Node1, /*offset=*/4, /*size=*/8); + TS.addInheritanceLink(Node1, Node2); + + // Run steps + VerifyLog.enable(); + dla::StepManager SM; + revng_check(SM.addStep()); + + SM.run(TS); + + // Compress the equivalence classes + dla::VectEqClasses &Eq = TS.getEqClasses(); + Eq.compress(); + + // Check TS + revng_check(TS.getNumLayouts() == 4); + revng_check(NodeA->Successors.size() == 1); + revng_check(Node1->Successors.size() == 2); } \ No newline at end of file