From 2b73e2924939a2fb5295ccf88ad32ad81315eb96 Mon Sep 17 00:00:00 2001 From: Pietro Fezzardi Date: Mon, 3 May 2021 11:53:09 +0200 Subject: [PATCH] Decouple LayoutTypeSystemNode from LLVM IR --- include/revng-c/Decompiler/DLALayouts.h | 2 + .../DLAComputeNonInterferingComponents.cpp | 28 +++------- .../DLAComputeUpperMemberAccess.cpp | 18 +++--- .../DLACreateIntraProceduralTypes.cpp | 4 +- lib/Decompiler/DLAMakeLayouts.cpp | 17 +++--- lib/Decompiler/DLATypeSystem.cpp | 55 +++++++++++++++---- lib/Decompiler/DLATypeSystem.h | 10 +--- 7 files changed, 74 insertions(+), 60 deletions(-) diff --git a/include/revng-c/Decompiler/DLALayouts.h b/include/revng-c/Decompiler/DLALayouts.h index 28472c031..24776780c 100644 --- a/include/revng-c/Decompiler/DLALayouts.h +++ b/include/revng-c/Decompiler/DLALayouts.h @@ -292,6 +292,8 @@ public: unsigned fieldNum() const { return FieldIdx; } void print(llvm::raw_ostream &Out) const; + + const llvm::Value &getValue() const { return *V; } }; // end class LayoutTypePtr using ValueLayoutMap = std::map; diff --git a/lib/Decompiler/DLAComputeNonInterferingComponents.cpp b/lib/Decompiler/DLAComputeNonInterferingComponents.cpp index 2f02f2502..8536d9e0d 100644 --- a/lib/Decompiler/DLAComputeNonInterferingComponents.cpp +++ b/lib/Decompiler/DLAComputeNonInterferingComponents.cpp @@ -38,11 +38,11 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { for (LTSN *N : llvm::post_order_ext(Root, Visited)) { revng_assert(not isLeaf(N) or hasValidLayout(N)); - revng_assert(N->L.Size); + revng_assert(N->Size); struct OrderedChild { int64_t Offset; - decltype(N->L.Size) Size; + decltype(N->Size) Size; LTSN *Child; // Make it sortable std::strong_ordering operator<=>(const OrderedChild &) const = default; @@ -59,7 +59,7 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { auto OrdChild = OrderedChild{ /* .Offset */ 0LL, - /* .Size */ Child->L.Size, + /* .Size */ Child->Size, /* .Child */ Child, }; @@ -122,10 +122,7 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { // If there is only one children and no accesses, we are sure that there's // nothing to do, because the only children cannot interfere with anything // else, and it is already a component on its own. - llvm::SmallSet AccessSizes; - for (const auto &A : N->L.Accesses) - AccessSizes.insert(getLoadStoreSizeFromPtrOpUse(TS, A)); - auto NumAccesses = AccessSizes.size(); + auto NumAccesses = N->AccessSizes.size(); if (Children.size() == 1ULL and not NumAccesses) { N->InterferingInfo = AllChildrenAreNonInterfering; continue; @@ -176,17 +173,10 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { auto FirstChildComp = MakeNewComponentFromChild(ChildIt); if (NumAccesses) { - const auto MaxAccessSize = [&TS](uint64_t PrevMax, - const llvm::Use *PtrOpUse) { - const auto ASize = getLoadStoreSizeFromPtrOpUse(TS, PtrOpUse); - return std::max(ASize, PrevMax); - }; - int64_t AccessStartByte = 0LL; - uint64_t AccEndByte = std::accumulate(N->L.Accesses.begin(), - N->L.Accesses.end(), - 0ULL, - MaxAccessSize); + auto MaxIt = std::max_element(N->AccessSizes.begin(), + N->AccessSizes.end()); + uint64_t AccEndByte = MaxIt != N->AccessSizes.end() ? *MaxIt : 0ULL; revng_assert(FirstChildComp.StartByte >= 0); if (static_cast(FirstChildComp.StartByte) < AccEndByte) { @@ -273,7 +263,7 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { // Set its size to the size of the component revng_assert(C.StartByte >= 0); revng_assert(C.EndByte > static_cast(C.StartByte)); - New->L.Size = C.EndByte - static_cast(C.StartByte); + New->Size = C.EndByte - static_cast(C.StartByte); // Move edges that were going directly from N to the children in the // component C, so that these edges now go from New to Child. @@ -291,7 +281,7 @@ bool ComputeNonInterferingComponents::runOnTypeSystem(LayoutTypeSystem &TS) { revng_assert(not FoundAccesses); FoundAccesses = true; revng_assert(not C.StartByte); - New->L.Accesses = std::move(N->L.Accesses); + New->AccessSizes = std::move(N->AccessSizes); } // Add a link between N and the New node representing the component. diff --git a/lib/Decompiler/DLAComputeUpperMemberAccess.cpp b/lib/Decompiler/DLAComputeUpperMemberAccess.cpp index a8101e647..4e774526a 100644 --- a/lib/Decompiler/DLAComputeUpperMemberAccess.cpp +++ b/lib/Decompiler/DLAComputeUpperMemberAccess.cpp @@ -42,20 +42,18 @@ bool ComputeUpperMemberAccesses::runOnTypeSystem(LayoutTypeSystem &TS) { for (LTSN *N : post_order_ext(Root, Visited)) { revng_assert(not isLeaf(N) or hasValidLayout(N)); - revng_assert(not N->L.Size); - auto FinalSize = N->L.Size; - - // Accumulate sizes of accesses associated to N - for (const Use *U : N->L.Accesses) { - FinalSize = std::max(FinalSize, getLoadStoreSizeFromPtrOpUse(TS, U)); - revng_assert(FinalSize); - } + revng_assert(not N->Size); + auto FinalSize = N->Size; + auto MaxIt = std::max_element(N->AccessSizes.begin(), + N->AccessSizes.end()); + FinalSize = std::max(FinalSize, + MaxIt != N->AccessSizes.end() ? *MaxIt : 0UL); // Look at all the instance-of edges and inheritance edges all together. bool HasBaseClass = false; for (auto &[Child, EdgeTag] : children_edges(N)) { - auto ChildSize = Child->L.Size; + auto ChildSize = Child->Size; revng_assert(ChildSize > 0LL); switch (EdgeTag->getKind()) { @@ -111,7 +109,7 @@ bool ComputeUpperMemberAccesses::runOnTypeSystem(LayoutTypeSystem &TS) { revng_unreachable("unexpected edge"); } } - N->L.Size = FinalSize; + N->Size = FinalSize; Changed = true; } } diff --git a/lib/Decompiler/DLACreateIntraProceduralTypes.cpp b/lib/Decompiler/DLACreateIntraProceduralTypes.cpp index be5e20dc3..c6cfb67d6 100644 --- a/lib/Decompiler/DLACreateIntraProceduralTypes.cpp +++ b/lib/Decompiler/DLACreateIntraProceduralTypes.cpp @@ -632,7 +632,8 @@ bool StepT::runOnTypeSystem(LayoutTypeSystem &TS) { Changed |= ILA.createBaseAddrWithInstanceLink(TS, PointerVal, *B); auto *AddrLayout = TS.getLayoutType(PointerVal); - AddrLayout->L.Accesses.insert(PtrUse); + auto AccessSize = getLoadStoreSizeFromPtrOpUse(TS, PtrUse); + AddrLayout->AccessSizes.insert(AccessSize); continue; } @@ -682,7 +683,6 @@ bool StepT::runOnTypeSystem(LayoutTypeSystem &TS) { auto *InsVal = cast(RetVal); Pointers = getInsertValueLeafOperands(InsVal); - } } else { diff --git a/lib/Decompiler/DLAMakeLayouts.cpp b/lib/Decompiler/DLAMakeLayouts.cpp index 7e4333de0..22330619f 100644 --- a/lib/Decompiler/DLAMakeLayouts.cpp +++ b/lib/Decompiler/DLAMakeLayouts.cpp @@ -105,17 +105,15 @@ static Layout *makeLayout(const LayoutTypeSystem &TS, case AllChildrenAreNonInterfering: { - llvm::SmallSet AccessSizes; - for (const auto &A : N->L.Accesses) - AccessSizes.insert(getLoadStoreSizeFromPtrOpUse(TS, A)); - auto NumAccesses = AccessSizes.size(); - uint64_t AccessSize = NumAccesses ? *AccessSizes.begin() : 0ULL; + auto NumAccesses = N->AccessSizes.size(); + uint64_t AccessSize = NumAccesses ? *N->AccessSizes.begin() : 0ULL; + revng_assert(NumAccesses == 0 or NumAccesses == 1); StructLayout::fields_container_t SFlds; struct OrderedChild { int64_t Offset; - decltype(N->L.Size) Size; + decltype(N->Size) Size; LTSN *Child; // Make it sortable std::strong_ordering operator<=>(const OrderedChild &) const = default; @@ -131,7 +129,7 @@ static Layout *makeLayout(const LayoutTypeSystem &TS, auto OrdChild = OrderedChild{ /* .Offset */ 0LL, - /* .Size */ Child->L.Size, + /* .Size */ Child->Size, /* .Child */ Child, }; @@ -260,8 +258,7 @@ static Layout *makeLayout(const LayoutTypeSystem &TS, case AllChildrenAreInterfering: { UnionLayout::elements_container_t UFlds; - for (const Use *U : N->L.Accesses) { - const auto AccessSize = getLoadStoreSizeFromPtrOpUse(TS, U); + for (uint64_t AccessSize : N->AccessSizes) { revng_log(Log, "Access: " << AccessSize); UFlds.insert(createLayout(Layouts, AccessSize)); } @@ -271,7 +268,7 @@ static Layout *makeLayout(const LayoutTypeSystem &TS, for (auto &[Child, EdgeTag] : children_edges(N)) { revng_log(Log, "Child ID: " << Child->ID); - revng_assert(Child->L.Size); + revng_assert(Child->Size); // Ignore children for which we haven't created a layout, because they // only have children from which it was not possible to create valid diff --git a/lib/Decompiler/DLATypeSystem.cpp b/lib/Decompiler/DLATypeSystem.cpp index 872210ffc..d2c9cc7fa 100644 --- a/lib/Decompiler/DLATypeSystem.cpp +++ b/lib/Decompiler/DLATypeSystem.cpp @@ -97,12 +97,13 @@ void LayoutTypeSystem::dumpDotOnFile(const char *FName) const { DotFile << "digraph LayoutTypeSystem {\n"; DotFile << " // List of nodes\n"; - unsigned AccessID = 0; + unsigned AccessSizeID = 0; for (const LayoutTypeSystemNode *L : getLayoutsRange()) { DotFile << " node_" << L->ID << " [shape=rect,label=\"NODE ID: " << L->ID - << " Size: " << L->L.Size << " InterferingChild: "; + << " Size: " << L->Size << " InterferingChild: "; + llvm::SmallVector PtrUses; switch (L->InterferingInfo) { case Unknown: DotFile << 'U'; @@ -129,20 +130,50 @@ void LayoutTypeSystem::dumpDotOnFile(const char *FName) const { for (const dla::LayoutTypePtr &P : TypePtrSet) { P.print(DotFile); DotFile << Ret; + + // Collect uses for which P is a pointer operand, so that we can print + // them later for debug + const llvm::Value &PtrV = P.getValue(); + for (const Use &U : PtrV.uses()) { + + const llvm::Value *PtrOp = nullptr; + const User *Usr = U.getUser(); + if (auto *Load = dyn_cast(Usr)) + PtrOp = Load->getPointerOperand(); + else if (auto *Store = dyn_cast(Usr)) + PtrOp = Store->getPointerOperand(); + else + continue; + + if (&PtrV == PtrOp) + PtrUses.push_back(&U); + } } } DotFile << "\"];\n"; - for (const llvm::Use *U : L->L.Accesses) { - const auto *I = cast(U->getUser()); - const llvm::Function *F = I->getFunction(); - DotFile << " access_" << AccessID << " [label=\"In: " << F->getName() - << " : "; - DotFile.write_escaped(dumpToString(U->getUser())); - DotFile << "\"];\n" - << " node_" << L->ID << " -> access_" << AccessID << ";\n"; - ++AccessID; + for (uint64_t AccessSize : L->AccessSizes) { + DotFile << " access_size_" << AccessSizeID + << " [label=\"Access Size: " << AccessSize; + + bool Found = false; + for (const llvm::Use *U : PtrUses) { + if (AccessSize == getLoadStoreSizeFromPtrOpUse(*this, U)) { + auto *I = cast(U->getUser()); + DotFile << "\\\\n" + << "In : " << I->getFunction()->getName() << " : "; + DotFile.write_escaped(dumpToString(I)); + Found = true; + } + } + + DotFile << "\"];\n"; + DotFile << " node_" << L->ID << " -> access_size_" << AccessSizeID + << ";\n"; + + revng_assert(Found); + ++AccessSizeID; } } @@ -585,7 +616,7 @@ LayoutTypeSystem::mergeNodes(LayoutTypeSystemNode *From, else revng_assert(IntoTypePtrs == &LayoutToTypePtrsMap.at(Into)); - Into->L.Accesses.insert(From->L.Accesses.begin(), From->L.Accesses.end()); + Into->AccessSizes.insert(From->AccessSizes.begin(), From->AccessSizes.end()); // Update LayoutToTypePtrsMap, the map that maps each LayoutTypeSystemNode * // to the set of LayoutTypePtrs that are associated to it. diff --git a/lib/Decompiler/DLATypeSystem.h b/lib/Decompiler/DLATypeSystem.h index f0e8bd113..99eeddbd0 100644 --- a/lib/Decompiler/DLATypeSystem.h +++ b/lib/Decompiler/DLATypeSystem.h @@ -104,11 +104,6 @@ public: std::strong_ordering operator<=>(const TypeLinkTag &Other) const = default; }; // end class TypeLinkTag -struct LayoutType { - llvm::SmallPtrSet Accesses{}; - uint64_t Size{}; -}; // end class LayoutType - class LayoutTypeSystem; enum InterferingChildrenInfo { @@ -123,7 +118,8 @@ struct LayoutTypeSystemNode { using NeighborsSet = std::set; NeighborsSet Successors{}; NeighborsSet Predecessors{}; - LayoutType L{}; + llvm::SmallSet AccessSizes{}; + uint64_t Size{}; InterferingChildrenInfo InterferingInfo{ Unknown }; LayoutTypeSystemNode(uint64_t I) : ID(I) {} @@ -145,7 +141,7 @@ public: inline bool hasValidLayout(const LayoutTypeSystemNode *N) { if (N == nullptr) return false; - return not N->L.Accesses.empty(); + return not N->AccessSizes.empty(); } class LayoutTypeSystem {