From cac7fee07d33d0d48aa3944e1f72276530ae7dc3 Mon Sep 17 00:00:00 2001 From: Pietro Fezzardi Date: Wed, 19 Jul 2023 15:02:00 +0200 Subject: [PATCH] LayoutTypeSystemNode: add NonScalar field This field represents that fact that a node of the DLA Graph is not a scalar and it comes from the Model. --- .../DataLayoutAnalysis/DLATypeSystem.h | 2 + lib/DataLayoutAnalysis/DLATypeSystem.cpp | 19 +++++- .../DLACreateInterProceduralTypes.cpp | 67 ++++++++++++++++++- 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h index 1996db607..b70a76176 100644 --- a/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h +++ b/include/revng-c/DataLayoutAnalysis/DLATypeSystem.h @@ -171,6 +171,8 @@ struct LayoutTypeSystemNode { NeighborsSet Predecessors{}; uint64_t Size{}; InterferingChildrenInfo InterferingInfo{ Unknown }; + bool NonScalar{ false }; + LayoutTypeSystemNode(uint64_t I) : ID(I) {} public: diff --git a/lib/DataLayoutAnalysis/DLATypeSystem.cpp b/lib/DataLayoutAnalysis/DLATypeSystem.cpp index 502730049..3ec4c8583 100644 --- a/lib/DataLayoutAnalysis/DLATypeSystem.cpp +++ b/lib/DataLayoutAnalysis/DLATypeSystem.cpp @@ -132,6 +132,8 @@ void debug_function LayoutTypeSystem::dumpDotOnFile(const char *FName, revng_unreachable(); } + DotFile << " NonScalar: " << L->NonScalar; + if (CollapsedNodePrinter.isEnabled() or ShowCollapsed) DebugPrinter->printNodeContent(*this, L, DotFile); @@ -290,12 +292,23 @@ void LayoutTypeSystem::mergeNodes(const LayoutTypeSystemNodePtrVec &ToMerge) { revng_assert(From != Into); revng_log(MergeLog, "Merging: " << From->ID << " Into: " << Into->ID); + Into->InterferingInfo = Unknown; + if (Into->NonScalar or From->NonScalar) { + revng_assert(not(Into->NonScalar and From->NonScalar) + or Into->Size == From->Size); + auto *NonScalar = Into->NonScalar ? Into : From; + auto *Other = Into->NonScalar ? From : Into; + revng_assert(Other->Size <= NonScalar->Size); + Into->Size = NonScalar->Size; + } else { + revng_assert(not Into->Size or From->Size <= Into->Size); + Into->Size = std::max(Into->Size, From->Size); + } + Into->NonScalar |= From->NonScalar; + EqClasses.join(IntoID, From->ID); fixPredSucc(From, Into); - Into->InterferingInfo = Unknown; - revng_assert(not Into->Size or From->Size <= Into->Size); - Into->Size = std::max(Into->Size, From->Size); // Remove From from Layouts bool Erased = Layouts.erase(From); diff --git a/lib/DataLayoutAnalysis/Frontend/DLACreateInterProceduralTypes.cpp b/lib/DataLayoutAnalysis/Frontend/DLACreateInterProceduralTypes.cpp index 8a97d188a..ad62fe811 100644 --- a/lib/DataLayoutAnalysis/Frontend/DLACreateInterProceduralTypes.cpp +++ b/lib/DataLayoutAnalysis/Frontend/DLACreateInterProceduralTypes.cpp @@ -19,6 +19,7 @@ #include "revng-c/DataLayoutAnalysis/DLATypeSystem.h" #include "revng-c/Support/FunctionTags.h" #include "revng-c/Support/IRHelpers.h" +#include "revng-c/Support/ModelHelpers.h" #include "../FuncOrCallInst.h" #include "DLATypeSystemBuilder.h" @@ -59,6 +60,7 @@ bool TSBuilder::createInterproceduralTypes(llvm::Module &M, revng_assert(TTR.isValid()); Prototype = TTR.getConst(); } + revng_assert(Prototype); FuncOrCallInst FuncWithSameProto; @@ -82,19 +84,78 @@ bool TSBuilder::createInterproceduralTypes(llvm::Module &M, revng_assert(FuncWithSameProto.isNull() or F.arg_size() == FuncWithSameProto.arg_size()); + const auto *RFT = dyn_cast(Prototype); + const auto *CABIFT = dyn_cast(Prototype); + if (RFT) { + revng_assert(F.arg_size() == RFT->Arguments().size() + or (RFT->StackArgumentsType().UnqualifiedType().isValid() + and (F.arg_size() == RFT->Arguments().size() + 1))); + } else if (CABIFT) { + revng_assert(CABIFT->Arguments().size() == F.arg_size()); + } else { + revng_abort(); + } + // Create types for the Function's arguments - for (const auto &Arg : llvm::enumerate(F.args())) { + for (const auto &ArgVal : F.args()) { + auto ArgIndex = ArgVal.getArgNo(); // Arguments can only be integers and pointers - auto &ArgVal = Arg.value(); revng_assert(isa(ArgVal.getType()) or isa(ArgVal.getType())); auto [ArgNode, _] = getOrCreateLayoutType(&ArgVal); revng_assert(ArgNode); + model::QualifiedType ArgumentModelType; + if (RFT) { + const auto &ModelArgs = RFT->Arguments(); + auto NumModelArguments = ModelArgs.size(); + if (ArgIndex < NumModelArguments) { + auto ArgIt = std::next(ModelArgs.begin(), ArgIndex); + ArgumentModelType = ArgIt->Type(); + } else { + ArgumentModelType = RFT->StackArgumentsType(); + } + } else { + revng_assert(CABIFT); + const auto &Args = CABIFT->Arguments(); + ArgumentModelType = Args.at(ArgIndex).Type(); + } + + if (ArgumentModelType.UnqualifiedType().isValid() + and ArgumentModelType.isPointer()) { + const model::QualifiedType + Pointee = stripPointer(peelConstAndTypedefs(ArgumentModelType)); + + bool IsScalar = Pointee.isScalar(); + + auto MaybeSize = Pointee.trySize(); + bool IsSized = MaybeSize.has_value(); + + bool IsFunction = Pointee.is(model::TypeKind::RawFunctionType) + or Pointee.is(model::TypeKind::CABIFunctionType); + + // If it is not scalar then it must be sized or a function type + revng_assert(IsScalar or IsSized or IsFunction); + + if (not IsScalar) { + ArgNode->NonScalar = true; + if (IsSized) + ArgNode->Size = *MaybeSize; + else if (IsFunction) + ArgNode->Size = getPointerSize(Model.Architecture()); + } else { + // Skip char, because they alias and propagate weird information. + if (IsSized and *MaybeSize > 1) + ArgNode->Size = *MaybeSize; + else if (IsFunction) + ArgNode->Size = getPointerSize(Model.Architecture()); + } + } + // If there is already a Function with the same prototype, add equality // edges between args if (not FuncWithSameProto.isNull()) { - auto &OtherArg = *(FuncWithSameProto.getArg(Arg.index())); + auto &OtherArg = *(FuncWithSameProto.getArg(ArgIndex)); auto *OtherArgNode = getLayoutType(&OtherArg); revng_assert(OtherArgNode); TS.addEqualityLink(ArgNode, OtherArgNode);