From 335d402245d9eb79ac4d4b2cf5777593f48fdc28 Mon Sep 17 00:00:00 2001 From: Massimo Fioravanti Date: Mon, 14 Nov 2022 14:29:20 +0100 Subject: [PATCH] Change signatures to forward metadata cache. --- include/revng-c/Backend/DecompileFunction.h | 4 +- .../revng-c/InitModelTypes/InitModelTypes.h | 5 +- include/revng-c/Support/ModelHelpers.h | 9 +- .../ValueManipulationAnalysis/VMAPipeline.h | 3 +- lib/Backend/CDecompilationPipe.cpp | 3 +- lib/Backend/DecompileFunction.cpp | 341 ++++++++---------- .../Backend/DLAMakeModelTypes.h | 4 +- .../Backend/DLAUpdateModelTypes.cpp | 7 +- lib/DataLayoutAnalysis/DLAPass.cpp | 6 +- .../DLACreateIntraProceduralTypes.cpp | 12 +- .../Frontend/DLATypeSystemBuilder.h | 7 +- lib/IRCanonicalization/MakeModelCastPass.cpp | 51 +-- lib/IRCanonicalization/MakeModelGEPPass.cpp | 27 +- lib/IRCanonicalization/RemoveLoadStore.cpp | 4 +- lib/InitModelTypes/InitModelTypes.cpp | 25 +- .../DetectStackSizePass.cpp | 21 +- .../PromoteStackPointerPass.cpp | 20 +- .../SegregateStackAccessesPass.cpp | 28 +- lib/Support/ModelHelpers.cpp | 18 +- .../TypeFlowGraph.cpp | 26 +- lib/ValueManipulationAnalysis/TypeFlowGraph.h | 7 +- lib/ValueManipulationAnalysis/VMAPipeline.cpp | 4 +- .../ValueManipulationAnalysis.cpp | 3 +- tests/unit/ValueManipulationAnalysis.cpp | 3 +- tools/decompile/Main.cpp | 3 +- 25 files changed, 352 insertions(+), 289 deletions(-) diff --git a/include/revng-c/Backend/DecompileFunction.h b/include/revng-c/Backend/DecompileFunction.h index efecc9914..878da0076 100644 --- a/include/revng-c/Backend/DecompileFunction.h +++ b/include/revng-c/Backend/DecompileFunction.h @@ -6,6 +6,7 @@ #include "llvm/IR/Module.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Pipes/FunctionStringMap.h" @@ -15,6 +16,7 @@ namespace detail { using Container = revng::pipes::DecompiledCCodeInYAMLStringMap; } -void decompile(llvm::Module &M, +void decompile(FunctionMetadataCache &Cache, + llvm::Module &M, const model::Binary &Model, detail::Container &DecompiledFunctions); diff --git a/include/revng-c/InitModelTypes/InitModelTypes.h b/include/revng-c/InitModelTypes/InitModelTypes.h index 0b165dfaa..2ba2638f2 100644 --- a/include/revng-c/InitModelTypes/InitModelTypes.h +++ b/include/revng-c/InitModelTypes/InitModelTypes.h @@ -6,6 +6,8 @@ #include +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" + namespace llvm { class Value; class Function; @@ -27,7 +29,8 @@ class Binary; /// \note If the `PointersOnly` flag is set, only pointer types will be added to /// the map extern std::map -initModelTypes(const llvm::Function &F, +initModelTypes(FunctionMetadataCache &Cache, + const llvm::Function &F, const model::Function *ModelF, const model::Binary &Model, bool PointersOnly); diff --git a/include/revng-c/Support/ModelHelpers.h b/include/revng-c/Support/ModelHelpers.h index be89ddd06..65bcd95fd 100644 --- a/include/revng-c/Support/ModelHelpers.h +++ b/include/revng-c/Support/ModelHelpers.h @@ -7,6 +7,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Type.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/QualifiedType.h" #include "revng/Model/Type.h" @@ -93,7 +94,9 @@ traverseModelGEP(const model::Binary &Model, const llvm::CallInst *Call); /// \return nothing if no information could be deduced locally on Inst /// \return one or more QualifiedTypes associated to Inst extern RecursiveCoroutine> -getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model); +getStrongModelInfo(FunctionMetadataCache &Cache, + const llvm::Instruction *Inst, + const model::Binary &Model); /// If possible, deduce the expected model type of an operand (e.g. the base /// operand of a ModelGEP) by looking only at the User. Note that, in the case @@ -102,4 +105,6 @@ getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model); /// \return nothing if no information could be deduced locally on U /// \return one or more QualifiedTypes associated to U extern llvm::SmallVector -getExpectedModelType(const llvm::Use *U, const model::Binary &Model); +getExpectedModelType(FunctionMetadataCache &Cache, + const llvm::Use *U, + const model::Binary &Model); diff --git a/include/revng-c/ValueManipulationAnalysis/VMAPipeline.h b/include/revng-c/ValueManipulationAnalysis/VMAPipeline.h index 8a69870b9..84f007c40 100644 --- a/include/revng-c/ValueManipulationAnalysis/VMAPipeline.h +++ b/include/revng-c/ValueManipulationAnalysis/VMAPipeline.h @@ -5,6 +5,7 @@ #include "llvm/ADT/SmallVector.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/QualifiedType.h" @@ -119,5 +120,5 @@ public: bool isSolverEnabled() { return UseSolver; } public: - void run(const llvm::Function *F); + void run(FunctionMetadataCache &Cache, const llvm::Function *F); }; diff --git a/lib/Backend/CDecompilationPipe.cpp b/lib/Backend/CDecompilationPipe.cpp index 58d06adb2..33ed0181f 100644 --- a/lib/Backend/CDecompilationPipe.cpp +++ b/lib/Backend/CDecompilationPipe.cpp @@ -22,7 +22,8 @@ void CDecompilation::run(const pipeline::Context &Ctx, llvm::Module &Module = IRContainer.getModule(); const model::Binary &Model = *getModelFromContext(Ctx); - decompile(Module, Model, DecompiledFunctions); + FunctionMetadataCache Cache; + decompile(Cache, Module, Model, DecompiledFunctions); } void CDecompilation::print(const pipeline::Context &Ctx, diff --git a/lib/Backend/DecompileFunction.cpp b/lib/Backend/DecompileFunction.cpp index 922ad7f0b..642265635 100644 --- a/lib/Backend/DecompileFunction.cpp +++ b/lib/Backend/DecompileFunction.cpp @@ -20,7 +20,7 @@ #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/IRHelpers.h" #include "revng/Model/PrimitiveTypeKind.h" @@ -88,9 +88,9 @@ using ValueSet = llvm::SmallPtrSet; static constexpr const char *StackFrameVarName = "stack"; -static Logger<> Log{ "c-backend" }; -static Logger<> VisitLog{ "c-backend-visit-order" }; -static Logger<> InlineLog{ "c-backend-inline" }; +static Logger<> Log{"c-backend"}; +static Logger<> VisitLog{"c-backend-visit-order"}; +static Logger<> InlineLog{"c-backend-inline"}; /// Helper function that also writes the logged string as a comment in the C /// file if the corresponding logger is enabled @@ -147,8 +147,7 @@ static const std::string getBinOpString(const llvm::BinaryOperator *BinOp) { default: revng_abort("Unknown const Binary operation"); } - } - (); + }(); return " " + *Op + " "; } @@ -176,8 +175,7 @@ static const std::string getCmpOpString(const llvm::CmpInst::Predicate &Pred) { default: revng_abort("Unknown comparison operator"); } - } - (); + }(); return " " + *Op + " "; } @@ -238,6 +236,8 @@ private: /// switches std::vector SwitchStateVars; + FunctionMetadataCache &Cache; + private: /// Stateful generator for variable names VarNameGenerator NameGenerator; @@ -274,28 +274,21 @@ private: bool IsOperatorPrecedenceResolutionPassEnabled = false; public: - CCodeGenerator(const Binary &Model, - const llvm::Function &LLVMFunction, - const ASTTree &GHAST, - const ValueSet &TopScopeVariables, - raw_ostream &Out) : - Model(Model), - LLVMFunction(LLVMFunction), - ModelFunction(*llvmToModelFunction(Model, LLVMFunction)), - ParentPrototype(*ModelFunction.Prototype.getConst()), - GHAST(GHAST), - TopScopeVariables(TopScopeVariables), - TypeMap(initModelTypes(LLVMFunction, - &ModelFunction, - Model, - /*PointersOnly=*/false)), - Out(Out, 4), - SwitchStateVars() { + CCodeGenerator(FunctionMetadataCache &Cache, const Binary &Model, + const llvm::Function &LLVMFunction, const ASTTree &GHAST, + const ValueSet &TopScopeVariables, raw_ostream &Out) + : Model(Model), LLVMFunction(LLVMFunction), + ModelFunction(*llvmToModelFunction(Model, LLVMFunction)), + ParentPrototype(*ModelFunction.Prototype.getConst()), GHAST(GHAST), + TopScopeVariables(TopScopeVariables), + TypeMap(initModelTypes(Cache, LLVMFunction, &ModelFunction, Model, + /*PointersOnly=*/false)), + Out(Out, 4), SwitchStateVars(), Cache(Cache) { // TODO: don't use a global loop state variable - LoopStateVar = getVariableLocationReference("loop_state_var", - ModelFunction); - LoopStateVarDeclaration = getVariableLocationDefinition("loop_state_var", - ModelFunction); + LoopStateVar = + getVariableLocationReference("loop_state_var", ModelFunction); + LoopStateVarDeclaration = + getVariableLocationDefinition("loop_state_var", ModelFunction); if (LLVMFunction.getMetadata(ExplicitParenthesesMDName)) IsOperatorPrecedenceResolutionPassEnabled = true; @@ -378,8 +371,8 @@ private: } else { VarName = NameGenerator.nextVarName(); } - return { getVariableLocationDefinition(VarName.str(), ModelFunction), - getVariableLocationReference(VarName.str(), ModelFunction) }; + return {getVariableLocationDefinition(VarName.str(), ModelFunction), + getVariableLocationReference(VarName.str(), ModelFunction)}; } /// Returns a variable name and a boolean indicating if the variable is new @@ -387,7 +380,7 @@ private: VariableTokens getOrCreateVarName(const llvm::Value *V) { if (const auto *I = dyn_cast(V); I && TopScopeVariables.contains(I)) - return { TokenMap.at(I) }; + return {TokenMap.at(I)}; VariableTokens NewVar = createVarName(V); TokenMap[V] = NewVar.Use.str().str(); @@ -397,8 +390,8 @@ private: private: /// Declare a local variable representing the given `Alloca` and return a /// token that represents is address. - VariableTokens - declareAllocaVariable(const llvm::AllocaInst *Alloca, VariableTokens Var) { + VariableTokens declareAllocaVariable(const llvm::AllocaInst *Alloca, + VariableTokens Var) { // In LLVM IR, an alloca instruction returns a pointer, so the model type // associated to this value is actually a pointer to the model type of // the variable being allocated. Hence, to get the actual type of the @@ -411,7 +404,7 @@ private: Out << getNamedCInstance(AllocatedType, Var.Declaration) << ";\n"; // Use the address of this variable as the token associated to the alloca - return { Var.Declaration, operators::AddressOf + Var.Use }; + return {Var.Declaration, operators::AddressOf + Var.Use}; } }; @@ -438,15 +431,15 @@ CCodeGenerator::buildCastExpr(StringRef ExprToCast, const model::QualifiedType &SrcType, const model::QualifiedType &DestType) { StringToken Result = ExprToCast; - if (SrcType == DestType or not SrcType.UnqualifiedType.isValid() - or not DestType.UnqualifiedType.isValid()) + if (SrcType == DestType or not SrcType.UnqualifiedType.isValid() or + not DestType.UnqualifiedType.isValid()) return Result; - revng_assert((SrcType.isScalar() or SrcType.isPointer()) - and (DestType.isScalar() or DestType.isPointer())); + revng_assert((SrcType.isScalar() or SrcType.isPointer()) and + (DestType.isScalar() or DestType.isPointer())); Result.assign(addAlwaysParentheses(getTypeName(DestType))); - Result.append({ " ", addParentheses(ExprToCast) }); + Result.append({" ", addParentheses(ExprToCast)}); return Result; } @@ -563,8 +556,8 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) { llvm::APInt Value = Const->getValue(); if (Value.isIntN(64)) { // TODO: Decide how to print constants - TokenMap[Operand] = constants::number(Value.getLimitedValue()) - .serialize(); + TokenMap[Operand] = + constants::number(Value.getLimitedValue()).serialize(); } else { // In C, even if you can have 128-bit variables, you cannot have 128-bit // literals, so we need this hack to assign a big constant value to a @@ -584,11 +577,11 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) { /*signed=*/false, /*formatAsCLiteral=*/true); - auto HighConstant = constants::constant(HighBitsString) + " " - + operators::LShift + " " + constants::number(64); - auto CompositeConstant = addParentheses(HighConstant).str().str() + " " - + operators::Or + " " - + constants::constant(LowBitsString); + auto HighConstant = constants::constant(HighBitsString) + " " + + operators::LShift + " " + constants::number(64); + auto CompositeConstant = addParentheses(HighConstant).str().str() + " " + + operators::Or + " " + + constants::constant(LowBitsString); TokenMap[Operand] = addAlwaysParentheses(CompositeConstant).str(); } @@ -613,11 +606,10 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) { if (SrcType.isPointer()) TokenMap[ConstExpr] = TokenMap.at(ConstExprOperand); else - TokenMap[ConstExpr] = buildCastExpr(TokenMap.at(ConstExprOperand), - SrcType, - DstType) - .str() - .str(); + TokenMap[ConstExpr] = + buildCastExpr(TokenMap.at(ConstExprOperand), SrcType, DstType) + .str() + .str(); } break; default: @@ -652,8 +644,8 @@ StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) { StringToken Expression; - if (FunctionTags::ModelGEP.isTagOf(CalledFunc) - or FunctionTags::ModelGEPRef.isTagOf(CalledFunc)) { + if (FunctionTags::ModelGEP.isTagOf(CalledFunc) or + FunctionTags::ModelGEPRef.isTagOf(CalledFunc)) { revng_assert(Call->getNumArgOperands() >= 2); bool IsRef = FunctionTags::ModelGEPRef.isTagOf(CalledFunc); @@ -764,15 +756,14 @@ StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) { llvm::Value *BaseValue = CurArg->get(); // Emit the parenthesized cast expr, and we are done - StringToken CastExpr = buildCastExpr(TokenMap.at(BaseValue), - TypeMap.at(BaseValue), - CurType); + StringToken CastExpr = + buildCastExpr(TokenMap.at(BaseValue), TypeMap.at(BaseValue), CurType); Expression = CastExpr; } else if (FunctionTags::AddressOf.isTagOf(CalledFunc)) { // First operand is the type of the value being addressed (should not // introduce casts) - QualifiedType ArgType = deserializeFromLLVMString(Call->getArgOperand(0), - Model); + QualifiedType ArgType = + deserializeFromLLVMString(Call->getArgOperand(0), Model); // Second argument is the value being addressed llvm::Value *Arg = Call->getArgOperand(1); @@ -832,9 +823,9 @@ StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) { // Use the name of the assigned variable when referencing this value Expression = VarNames.Use; - } else if (FunctionTags::LocalVariable.isTagOf(CalledFunc) - or FuncName.startswith("revng_stack_frame") - or FuncName.startswith("revng_call_stack_arguments")) { + } else if (FunctionTags::LocalVariable.isTagOf(CalledFunc) or + FuncName.startswith("revng_stack_frame") or + FuncName.startswith("revng_call_stack_arguments")) { const auto VarNames = getOrCreateVarName(Call); // Declare a new local variable if it hasn't already been declared @@ -844,9 +835,9 @@ StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) { Expression = VarNames.Use; } else if (FunctionTags::SegmentRef.isTagOf(CalledFunc)) { - const auto &[StartAddress, - VirtualSize] = extractSegmentKeyFromMetadata(*CalledFunc); - model::Segment Segment = Model.Segments.at({ StartAddress, VirtualSize }); + const auto &[StartAddress, VirtualSize] = + extractSegmentKeyFromMetadata(*CalledFunc); + model::Segment Segment = Model.Segments.at({StartAddress, VirtualSize}); auto Name = Segment.name(); Expression = ptml::getLocationReference(Segment); @@ -856,18 +847,17 @@ StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) { const llvm::Value *PointerVal = Call->getArgOperand(1); const QualifiedType PointedType = TypeMap.at(PointerVal); - Expression = buildAssignmentExpr(PointedType, - { TokenMap.at(PointerVal) }, + Expression = buildAssignmentExpr(PointedType, {TokenMap.at(PointerVal)}, TokenMap.at(StoredVal)); } else if (FunctionTags::Copy.isTagOf(CalledFunc)) { // Forward expression Expression = TokenMap.at(Call->getArgOperand(0)); - } else if (FunctionTags::QEMU.isTagOf(CalledFunc) - or FunctionTags::Helper.isTagOf(CalledFunc) - or FunctionTags::OpaqueCSVValue.isTagOf(CalledFunc) - or CalledFunc->isIntrinsic()) { + } else if (FunctionTags::QEMU.isTagOf(CalledFunc) or + FunctionTags::Helper.isTagOf(CalledFunc) or + FunctionTags::OpaqueCSVValue.isTagOf(CalledFunc) or + CalledFunc->isIntrinsic()) { std::string HelperRef = getHelperFunctionLocationReference(CalledFunc); Expression = buildFuncCallExpr(Call, HelperRef, /*prototype=*/nullptr); @@ -917,9 +907,9 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { revng_log(Log, "Emitting call to isolated function"); // Retrieve the CallEdge - const auto &[CallEdge, _] = getCallEdge(Model, Call); + const auto &[CallEdge, _] = Cache.getCallEdge(Model, Call); revng_assert(CallEdge); - const auto &PrototypePath = getCallSitePrototype(Model, Call); + const auto &PrototypePath = Cache.getCallSitePrototype(Model, Call); // Construct the callee token (can be a function name or a function // pointer) @@ -939,31 +929,31 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { // Dynamic Function auto &DynFuncID = CallEdge->DynamicFunction; auto &DynamicFunc = Model.ImportedDynamicFunctions.at(DynFuncID); - std::string Location = serializedLocation(ranks::DynamicFunction, - DynamicFunc.key()); - CalleeToken = Tag(tags::Span, DynamicFunc.name().str()) - .addAttribute(attributes::Token, tokens::Function) - .addAttribute(attributes::ModelEditPath, - getCustomNamePath(DynamicFunc)) - .addAttribute(attributes::LocationReferences, - Location) - .serialize(); + std::string Location = + serializedLocation(ranks::DynamicFunction, DynamicFunc.key()); + CalleeToken = + Tag(tags::Span, DynamicFunc.name().str()) + .addAttribute(attributes::Token, tokens::Function) + .addAttribute(attributes::ModelEditPath, + getCustomNamePath(DynamicFunc)) + .addAttribute(attributes::LocationReferences, Location) + .serialize(); } else { // Isolated function llvm::Function *CalledFunc = Call->getCalledFunction(); revng_assert(CalledFunc); - const model::Function *ModelFunc = llvmToModelFunction(Model, - *CalledFunc); + const model::Function *ModelFunc = + llvmToModelFunction(Model, *CalledFunc); revng_assert(ModelFunc); CalleeToken = ModelFunc->name(); CalleeToken = Tag(tags::Span, ModelFunc->name().str()) - .addAttribute(attributes::Token, tokens::Function) - .addAttribute(attributes::ModelEditPath, - getCustomNamePath(*ModelFunc)) - .addAttribute(attributes::LocationReferences, - serializedLocation(ranks::Function, - ModelFunc->key())) - .serialize(); + .addAttribute(attributes::Token, tokens::Function) + .addAttribute(attributes::ModelEditPath, + getCustomNamePath(*ModelFunc)) + .addAttribute(attributes::LocationReferences, + serializedLocation(ranks::Function, + ModelFunc->key())) + .serialize(); } } @@ -1025,10 +1015,10 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { // have a mismatch. In this case, we want to cast the pointer operand to // correct type pointer before dereferencing it. QualifiedType ResultPtrType = Model.getPointerTo(TypeMap.at(Load)); - Expression = (buildDerefExpr(buildCastExpr(TokenMap.at(LoadedArg), - TypeMap.at(LoadedArg), - ResultPtrType))) - .str(); + Expression = + (buildDerefExpr(buildCastExpr(TokenMap.at(LoadedArg), + TypeMap.at(LoadedArg), ResultPtrType))) + .str(); } else if (auto *Store = dyn_cast(&I)) { @@ -1038,9 +1028,8 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { StringToken PointerOperandExpr = StringToken(TokenMap.at(PointerOp)); - Expression = buildAssignmentExpr(StoredType, - { buildDerefExpr(PointerOperandExpr) }, - TokenMap.at(ValueOp)); + Expression = buildAssignmentExpr( + StoredType, {buildDerefExpr(PointerOperandExpr)}, TokenMap.at(ValueOp)); } else if (auto *Select = dyn_cast(&I)) { @@ -1048,24 +1037,21 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { const llvm::Value *Op1 = Select->getOperand(1); const llvm::Value *Op2 = Select->getOperand(2); - StringToken Op1Token = buildCastExpr(TokenMap.at(Op1), - TypeMap.at(Op1), - TypeMap.at(Select)); - StringToken Op2Token = buildCastExpr(TokenMap.at(Op2), - TypeMap.at(Op2), - TypeMap.at(Select)); + StringToken Op1Token = + buildCastExpr(TokenMap.at(Op1), TypeMap.at(Op1), TypeMap.at(Select)); + StringToken Op2Token = + buildCastExpr(TokenMap.at(Op2), TypeMap.at(Op2), TypeMap.at(Select)); - Expression = (addParentheses(Condition) + " ? " + addParentheses(Op1Token) - + " : " + addParentheses(Op2Token)) - .str(); + Expression = (addParentheses(Condition) + " ? " + addParentheses(Op1Token) + + " : " + addParentheses(Op2Token)) + .str(); } else if (auto *Alloca = dyn_cast(&I)) { auto [VarName, VarDeclaration] = getOrCreateVarName(Alloca); if (!VarDeclaration.empty()) { // Declare a local variable - auto AllocaDeclaration = declareAllocaVariable(Alloca, - { VarName, - VarDeclaration }); + auto AllocaDeclaration = + declareAllocaVariable(Alloca, {VarName, VarDeclaration}); Expression = AllocaDeclaration.Use; } else { // If it's a top-scope variable it has already been declared, so we have @@ -1096,41 +1082,37 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { const llvm::Value *Op2 = Bin->getOperand(1); const QualifiedType &ResultType = TypeMap.at(Bin); - const auto &Op1Token = buildCastExpr(TokenMap.at(Op1), - TypeMap.at(Op1), - ResultType); - const auto &Op2Token = buildCastExpr(TokenMap.at(Op2), - TypeMap.at(Op2), - ResultType); + const auto &Op1Token = + buildCastExpr(TokenMap.at(Op1), TypeMap.at(Op1), ResultType); + const auto &Op2Token = + buildCastExpr(TokenMap.at(Op2), TypeMap.at(Op2), ResultType); // TODO: Integer promotion - Expression = (addParentheses(Op1Token) + getBinOpString(Bin) - + addParentheses(Op2Token)) - .str(); + Expression = (addParentheses(Op1Token) + getBinOpString(Bin) + + addParentheses(Op2Token)) + .str(); } else if (auto *Cmp = dyn_cast(&I)) { const llvm::Value *Op1 = Cmp->getOperand(0); const llvm::Value *Op2 = Cmp->getOperand(1); const QualifiedType &ResultType = llvmIntToModelType(Op1->getType(), Model); - const auto &Op1Token = buildCastExpr(TokenMap.at(Op1), - TypeMap.at(Op1), - ResultType); - const auto &Op2Token = buildCastExpr(TokenMap.at(Op2), - TypeMap.at(Op2), - ResultType); + const auto &Op1Token = + buildCastExpr(TokenMap.at(Op1), TypeMap.at(Op1), ResultType); + const auto &Op2Token = + buildCastExpr(TokenMap.at(Op2), TypeMap.at(Op2), ResultType); // TODO: Integer promotion - Expression = (addParentheses(Op1Token) + getCmpOpString(Cmp->getPredicate()) - + addParentheses(Op2Token)) - .str(); + Expression = + (addParentheses(Op1Token) + getCmpOpString(Cmp->getPredicate()) + + addParentheses(Op2Token)) + .str(); } else if (auto *Cast = dyn_cast(&I)) { const llvm::Value *Op = Cast->getOperand(0); - Expression = buildCastExpr(TokenMap.at(Op), - TypeMap.at(Op), - TypeMap.at(Cast)); + Expression = + buildCastExpr(TokenMap.at(Op), TypeMap.at(Op), TypeMap.at(Cast)); } else if (auto *ExtractVal = dyn_cast(&I)) { @@ -1148,11 +1130,12 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { const llvm::Value *FirstArg = CallReturnsStruct->getArgOperand(0); CallReturnsStruct = llvm::cast(FirstArg); Callee = CallReturnsStruct->getCalledFunction(); - revng_assert(not Callee - or not FunctionTags::AssignmentMarker.isTagOf(Callee)); + revng_assert(not Callee or + not FunctionTags::AssignmentMarker.isTagOf(Callee)); } - const auto CalleePrototype = getCallSitePrototype(Model, CallReturnsStruct); + const auto CalleePrototype = + Cache.getCallSitePrototype(Model, CallReturnsStruct); std::string StructFieldRef; if (not CalleePrototype.isValid()) { @@ -1179,9 +1162,9 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) { } void CCodeGenerator::emitBasicBlock(const llvm::BasicBlock *BB) { - LoggerIndent Indent{ VisitLog }; + LoggerIndent Indent{VisitLog}; revng_log(VisitLog, "|__ Visiting BB " << BB->getName()); - LoggerIndent MoreIndent{ VisitLog }; + LoggerIndent MoreIndent{VisitLog}; revng_log(Log, "--------- BB " << BB->getName()); for (const Instruction &I : *BB) { @@ -1211,9 +1194,9 @@ void CCodeGenerator::emitBasicBlock(const llvm::BasicBlock *BB) { RecursiveCoroutine CCodeGenerator::buildGHASTCondition(const ExprNode *E) { - LoggerIndent Indent{ VisitLog }; + LoggerIndent Indent{VisitLog}; revng_log(VisitLog, "|__ Visiting Condition " << E); - LoggerIndent MoreIndent{ VisitLog }; + LoggerIndent MoreIndent{VisitLog}; using NodeKind = ExprNode::NodeKind; switch (E->getKind()) { @@ -1247,8 +1230,8 @@ CCodeGenerator::buildGHASTCondition(const ExprNode *E) { ExprNode *Negated = N->getNegatedNode(); StringToken Expression; - Expression = operators::BoolNot - + addAlwaysParentheses(rc_recur buildGHASTCondition(Negated)); + Expression = operators::BoolNot + + addAlwaysParentheses(rc_recur buildGHASTCondition(Negated)); rc_return Expression; } break; @@ -1261,8 +1244,8 @@ CCodeGenerator::buildGHASTCondition(const ExprNode *E) { const auto &[Child1, Child2] = Binary->getInternalNodes(); const auto Child1Token = rc_recur buildGHASTCondition(Child1); const auto Child2Token = rc_recur buildGHASTCondition(Child2); - const Tag &OpToken = E->getKind() == NodeKind::NK_And ? operators::BoolAnd : - operators::BoolOr; + const Tag &OpToken = E->getKind() == NodeKind::NK_And ? operators::BoolAnd + : operators::BoolOr; StringToken Expression = addAlwaysParentheses(Child1Token); Expression += " " + OpToken + " "; Expression += addAlwaysParentheses(Child2Token); @@ -1279,7 +1262,7 @@ RecursiveCoroutine CCodeGenerator::emitGHASTNode(const ASTNode *N) { rc_return; revng_log(VisitLog, "|__ GHAST Node " << N->getID()); - LoggerIndent Indent{ VisitLog }; + LoggerIndent Indent{VisitLog}; auto Kind = N->getKind(); switch (Kind) { @@ -1289,8 +1272,8 @@ RecursiveCoroutine CCodeGenerator::emitGHASTNode(const ASTNode *N) { const BreakNode *Break = llvm::cast(N); if (Break->breaksFromWithinSwitch()) { - revng_assert(not SwitchStateVars.empty() - and not SwitchStateVars.back().empty()); + revng_assert(not SwitchStateVars.empty() and + not SwitchStateVars.back().empty()); Out << SwitchStateVars.back() << " " + operators::Assign + " " + constants::True + ";\n"; } @@ -1410,8 +1393,8 @@ RecursiveCoroutine CCodeGenerator::emitGHASTNode(const ASTNode *N) { if (Switch->needsStateVariable()) { revng_assert(Switch->needsLoopBreakDispatcher()); StringToken NewVarName = NameGenerator.nextSwitchStateVar(); - std::string SwitchStateVar = getVariableLocationReference(NewVarName, - ModelFunction); + std::string SwitchStateVar = + getVariableLocationReference(NewVarName, ModelFunction); SwitchStateVars.push_back(std::move(SwitchStateVar)); Out << ptml::tokenTag("bool", tokens::Type) << " " << getVariableLocationDefinition(NewVarName, ModelFunction) @@ -1502,8 +1485,8 @@ RecursiveCoroutine CCodeGenerator::emitGHASTNode(const ASTNode *N) { // If the switch needs a loop break dispatcher, reset the associated // state variable before emitting the switch statement. if (Switch->needsLoopBreakDispatcher()) { - revng_assert(not SwitchStateVars.empty() - and not SwitchStateVars.back().empty()); + revng_assert(not SwitchStateVars.empty() and + not SwitchStateVars.back().empty()); Out << keywords::If + " (" + SwitchStateVars.back() + ")"; { auto Scope = scopeTags::Scope.scope(Out, true); @@ -1545,7 +1528,7 @@ RecursiveCoroutine CCodeGenerator::emitGHASTNode(const ASTNode *N) { void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) { revng_log(Log, "========= Emitting Function " << LLVMFunction.getName()); revng_log(VisitLog, "========= Function " << LLVMFunction.getName()); - LoggerIndent Indent{ VisitLog }; + LoggerIndent Indent{VisitLog}; // Create a token for each of the function's arguments if (auto *RawPrototype = dyn_cast(&ParentPrototype)) { @@ -1556,26 +1539,25 @@ void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) { const auto &StackArgType = RawPrototype->StackArgumentsType.UnqualifiedType; const auto ArgSize = ModelArgs.size(); - revng_assert(LLVMArgsNum == ArgSize - or (LLVMArgsNum == ArgSize + 1 and StackArgType.isValid())); + revng_assert(LLVMArgsNum == ArgSize or + (LLVMArgsNum == ArgSize + 1 and StackArgType.isValid())); // Associate each LLVM argument with its name for (const auto &[ModelArg, LLVMArg] : llvm::zip_first(ModelArgs, LLVMArgs)) { revng_log(Log, "Adding token for: " << dumpToString(LLVMArg)); - std::string ArgIdentifier = model::Identifier::fromString(ModelArg.name()) - .str() - .str(); - TokenMap[&LLVMArg] = getArgumentLocationReference(ArgIdentifier, - ModelFunction); + std::string ArgIdentifier = + model::Identifier::fromString(ModelArg.name()).str().str(); + TokenMap[&LLVMArg] = + getArgumentLocationReference(ArgIdentifier, ModelFunction); } // Add a token for the stack arguments if (StackArgType.isValid()) { const auto *LLVMArg = LLVMFunction.getArg(LLVMArgsNum - 1); revng_log(Log, "Adding token for: " << dumpToString(LLVMArg)); - TokenMap[LLVMArg] = getArgumentLocationReference("stack_args", - ModelFunction); + TokenMap[LLVMArg] = + getArgumentLocationReference("stack_args", ModelFunction); } } else if (auto *CPrototype = dyn_cast(&ParentPrototype)) { @@ -1587,11 +1569,10 @@ void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) { // Associate each LLVM argument with its name for (const auto &[ModelArg, LLVMArg] : llvm::zip(ModelArgs, LLVMArgs)) { revng_log(Log, "Adding token for: " << dumpToString(LLVMArg)); - std::string ArgIdentifier = model::Identifier::fromString(ModelArg.name()) - .str() - .str(); - TokenMap[&LLVMArg] = getArgumentLocationReference(ArgIdentifier, - ModelFunction); + std::string ArgIdentifier = + model::Identifier::fromString(ModelArg.name()).str().str(); + TokenMap[&LLVMArg] = + getArgumentLocationReference(ArgIdentifier, ModelFunction); } } else { revng_abort("Functions can only have RawFunctionType or " @@ -1642,8 +1623,8 @@ void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) { revng_assert(CalledFunction); if (FunctionTags::Isolated.isTagOf(CalledFunction)) { - const auto &Prototype = getCallSitePrototype(Model, Call) - .getConst(); + const auto &Prototype = + Cache.getCallSitePrototype(Model, Call).getConst(); auto *RawPrototype = llvm::cast(Prototype); Out << getReturnTypeName(*RawPrototype) << " " << VarName.Declaration << ";\n"; @@ -1670,15 +1651,15 @@ void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) { Out << "\n"; } -static std::string decompileFunction(const llvm::Function &LLVMFunc, - const ASTTree &CombedAST, - const Binary &Model, - const ValueSet &TopScopeVariables, - bool NeedsLocalStateVar) { +static std::string +decompileFunction(FunctionMetadataCache &Cache, const llvm::Function &LLVMFunc, + const ASTTree &CombedAST, const Binary &Model, + const ValueSet &TopScopeVariables, bool NeedsLocalStateVar) { std::string Result; llvm::raw_string_ostream Out(Result); - CCodeGenerator Backend(Model, LLVMFunc, CombedAST, TopScopeVariables, Out); + CCodeGenerator Backend(Cache, Model, LLVMFunc, CombedAST, TopScopeVariables, + Out); Backend.emitFunction(NeedsLocalStateVar); Out.flush(); @@ -1686,9 +1667,8 @@ static std::string decompileFunction(const llvm::Function &LLVMFunc, } using Container = revng::pipes::DecompiledCCodeInYAMLStringMap; -void decompile(llvm::Module &Module, - const model::Binary &Model, - Container &DecompiledFunctions) { +void decompile(FunctionMetadataCache &Cache, llvm::Module &Module, + const model::Binary &Model, Container &DecompiledFunctions) { if (Log.isEnabled()) writeToFile(Model.toString(), "model-during-c-codegen.yaml"); @@ -1711,19 +1691,16 @@ void decompile(llvm::Module &Module, } if (Log.isEnabled()) { - const llvm::Twine &ASTFileName = F.getName() - + "GHAST-during-c-codegen.dot"; + const llvm::Twine &ASTFileName = + F.getName() + "GHAST-during-c-codegen.dot"; GHAST.dumpASTOnFile(ASTFileName.str()); } // Generated C code for F auto TopScopeVariables = collectTopScopeVariables(F); auto NeedsLoopStateVar = hasLoopDispatchers(GHAST); - std::string CCode = decompileFunction(F, - GHAST, - Model, - TopScopeVariables, - NeedsLoopStateVar); + std::string CCode = decompileFunction(Cache, F, GHAST, Model, + TopScopeVariables, NeedsLoopStateVar); // Push the C code into MetaAddress Key = getMetaAddressMetadata(&F, "revng.function.entry"); diff --git a/lib/DataLayoutAnalysis/Backend/DLAMakeModelTypes.h b/lib/DataLayoutAnalysis/Backend/DLAMakeModelTypes.h index 9ecd2ed52..ddc9b1341 100644 --- a/lib/DataLayoutAnalysis/Backend/DLAMakeModelTypes.h +++ b/lib/DataLayoutAnalysis/Backend/DLAMakeModelTypes.h @@ -4,6 +4,7 @@ // Copyright (c) rev.ng Labs Srl. See LICENSE.md for details. // +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/Type.h" @@ -25,7 +26,8 @@ TypeMapT makeModelTypes(const LayoutTypeSystem &TS, /// Whether there was anything to update in the model. bool updateFuncSignatures(const llvm::Module &M, TupleTree &Model, - const TypeMapT &TypeMap); + const TypeMapT &TypeMap, + FunctionMetadataCache &Cache); /// Attach model types to segments and update the model. bool updateSegmentsTypes(const llvm::Module &M, diff --git a/lib/DataLayoutAnalysis/Backend/DLAUpdateModelTypes.cpp b/lib/DataLayoutAnalysis/Backend/DLAUpdateModelTypes.cpp index 3fdcfe403..0068f151e 100644 --- a/lib/DataLayoutAnalysis/Backend/DLAUpdateModelTypes.cpp +++ b/lib/DataLayoutAnalysis/Backend/DLAUpdateModelTypes.cpp @@ -20,7 +20,7 @@ #include "llvm/Support/raw_ostream.h" #include "revng/ADT/FilteredGraphTraits.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/Type.h" #include "revng/Model/VerifyHelper.h" @@ -453,7 +453,8 @@ static bool updateFuncPrototype(model::Binary &Model, bool dla::updateFuncSignatures(const llvm::Module &M, TupleTree &Model, - const TypeMapT &TypeMap) { + const TypeMapT &TypeMap, + FunctionMetadataCache &Cache) { if (ModelLog.isEnabled()) writeToFile(Model->toString(), "model-before-func-update.yaml"); if (VerifyLog.isEnabled()) @@ -477,7 +478,7 @@ bool dla::updateFuncSignatures(const llvm::Module &M, // Update prototypes associated to indirect calls, if any are found for (const auto &Inst : LLVMFunc) if (const auto *I = llvm::dyn_cast(&Inst)) { - auto Prototype = getCallSitePrototype(*Model.get(), I, ModelFunc); + auto Prototype = Cache.getCallSitePrototype(*Model.get(), I, ModelFunc); if (Prototype.isValid()) { revng_log(Log, "Updating prototype of indirect call " diff --git a/lib/DataLayoutAnalysis/DLAPass.cpp b/lib/DataLayoutAnalysis/DLAPass.cpp index 3c3204931..36eaf4bcc 100644 --- a/lib/DataLayoutAnalysis/DLAPass.cpp +++ b/lib/DataLayoutAnalysis/DLAPass.cpp @@ -28,16 +28,18 @@ void DLAPass::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } bool DLAPass::runOnModule(llvm::Module &M) { auto &ModelWrapper = getAnalysis().get(); + auto &Cache = getAnalysis().get(); // Front-end: Create the LayoutTypeSystem graph from an LLVM module dla::LayoutTypeSystem TS; - dla::DLATypeSystemLLVMBuilder Builder{ TS }; + dla::DLATypeSystemLLVMBuilder Builder{ TS, Cache }; const model::Binary &Model = *ModelWrapper.getReadOnlyModel(); Builder.buildFromLLVMModule(M, this, Model); @@ -91,7 +93,7 @@ bool DLAPass::runOnModule(llvm::Module &M) { auto ValueToTypeMap = dla::makeModelTypes(TS, Values, WritableModel); bool Changed = false; - Changed |= dla::updateFuncSignatures(M, WritableModel, ValueToTypeMap); + Changed |= dla::updateFuncSignatures(M, WritableModel, ValueToTypeMap, Cache); Changed |= dla::updateSegmentsTypes(M, WritableModel, ValueToTypeMap); return Changed; diff --git a/lib/DataLayoutAnalysis/Frontend/DLACreateIntraProceduralTypes.cpp b/lib/DataLayoutAnalysis/Frontend/DLACreateIntraProceduralTypes.cpp index 3e64fc8b6..96a3c64f2 100644 --- a/lib/DataLayoutAnalysis/Frontend/DLACreateIntraProceduralTypes.cpp +++ b/lib/DataLayoutAnalysis/Frontend/DLACreateIntraProceduralTypes.cpp @@ -19,7 +19,7 @@ #include "llvm/IR/Module.h" #include "llvm/Pass.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Architecture.h" #include "revng/Support/Assert.h" #include "revng/Support/Debug.h" @@ -50,7 +50,8 @@ static int64_t getSCEVConstantSExtVal(const SCEV *S) { class DLATypeSystemLLVMBuilder::InstanceLinkAdder { public: - InstanceLinkAdder(const model::Binary &M) : Model(M) {} + InstanceLinkAdder(const model::Binary &M, FunctionMetadataCache &Cache) : + Model(M), Cache(&Cache) {} private: const model::Binary &Model; @@ -60,6 +61,7 @@ private: llvm::PostDominatorTree PDT; SCEVTypeMap SCEVToLayoutType; + FunctionMetadataCache *Cache; protected: bool addInstanceLink(DLATypeSystemLLVMBuilder &Builder, @@ -452,7 +454,7 @@ public: if (not isCallToIsolatedFunction(C)) continue; - const auto PrototypeRef = getCallSitePrototype(Model, C); + const auto PrototypeRef = Cache->getCallSitePrototype(Model, C); if (not PrototypeRef.isValid()) continue; @@ -635,7 +637,7 @@ bool Builder::connectToFuncsWithSamePrototype(const llvm::CallInst *Call, revng_assert(Call->isIndirectCall()); bool Changed = false; - auto Prototype = getCallSitePrototype(Model, Call); + auto Prototype = Cache->getCallSitePrototype(Model, Call); if (not Prototype.isValid()) return false; @@ -691,7 +693,7 @@ bool Builder::createIntraproceduralTypes(llvm::Module &M, llvm::ModulePass *MP, const model::Binary &Model) { bool Changed = false; - InstanceLinkAdder ILA{ Model }; + InstanceLinkAdder ILA(Model, *Cache); raw_fd_ostream *OutFile = nullptr; diff --git a/lib/DataLayoutAnalysis/Frontend/DLATypeSystemBuilder.h b/lib/DataLayoutAnalysis/Frontend/DLATypeSystemBuilder.h index 91de63560..cd45ad6ee 100644 --- a/lib/DataLayoutAnalysis/Frontend/DLATypeSystemBuilder.h +++ b/lib/DataLayoutAnalysis/Frontend/DLATypeSystemBuilder.h @@ -6,6 +6,7 @@ #include "llvm/Pass.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng-c/DataLayoutAnalysis/DLALayouts.h" @@ -69,6 +70,9 @@ private: /// first `llvm::CallInst` found with that prototype, PrototypesMapT VisitedPrototypes; + /// Metadata cache to store deserialized revng metadata + FunctionMetadataCache *Cache; + private: LayoutTypeSystemNode *getLayoutType(const llvm::Value *V, unsigned Id); @@ -109,7 +113,8 @@ public: void debug_function dumpValuesMapping(const llvm::StringRef Name) const; public: - DLATypeSystemLLVMBuilder(LayoutTypeSystem &TS) : TS(TS){}; + DLATypeSystemLLVMBuilder(LayoutTypeSystem &TS, FunctionMetadataCache &Cache) : + TS(TS), Cache(&Cache){}; /// Create a DLATypeSystem graph for a given LLVM module /// diff --git a/lib/IRCanonicalization/MakeModelCastPass.cpp b/lib/IRCanonicalization/MakeModelCastPass.cpp index fdc7554e6..1e7a51ff9 100644 --- a/lib/IRCanonicalization/MakeModelCastPass.cpp +++ b/lib/IRCanonicalization/MakeModelCastPass.cpp @@ -10,7 +10,7 @@ #include "llvm/Pass.h" #include "revng/ABI/FunctionType.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/IRHelpers.h" #include "revng/Model/LoadModelPass.h" @@ -51,11 +51,14 @@ public: void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); + AU.addRequired(); } private: std::vector - serializeTypesForModelCast(Instruction *, const model::Binary &); + serializeTypesForModelCast(FunctionMetadataCache &Cache, + Instruction *, + const model::Binary &); void createAndInjectModelCast(Instruction *, const SerializedType &, OpaqueFunctionsPool &); @@ -64,33 +67,36 @@ private: using MMCP = MakeModelCastPass; std::vector -MMCP::serializeTypesForModelCast(Instruction *I, const model::Binary &Model) { +MMCP::serializeTypesForModelCast(FunctionMetadataCache &Cache, + Instruction *I, + const model::Binary &Model) { using namespace model; using namespace abi::FunctionType; std::vector Result; Module *M = I->getModule(); - auto SerializeTypeFor = [this, &Model, &Result, &M](const llvm::Use &Op) { - // Check if we have strong model information about this operand - auto ModelTypes = getExpectedModelType(&Op, Model); + auto SerializeTypeFor = + [this, &Model, &Result, &M, &Cache](const llvm::Use &Op) { + // Check if we have strong model information about this operand + auto ModelTypes = getExpectedModelType(Cache, &Op, Model); - // Aggregates that do not correspond to model structs (e.g. return types of - // RawFunctionTypes that return more than one value) cannot be handled with - // casts, since we don't have a model::Type to cast them to. - if (ModelTypes.size() == 1) { - QualifiedType ExpectedType = ModelTypes.back(); - revng_assert(ExpectedType.UnqualifiedType.isValid()); + // Aggregates that do not correspond to model structs (e.g. return types + // of RawFunctionTypes that return more than one value) cannot be handled + // with casts, since we don't have a model::Type to cast them to. + if (ModelTypes.size() == 1) { + QualifiedType ExpectedType = ModelTypes.back(); + revng_assert(ExpectedType.UnqualifiedType.isValid()); - if (ExpectedType != TypeMap.at(Op.get())) { - // Create a cast only if the expected type is different from the actual - // type propagated until here - auto Type = SerializedType(serializeToLLVMString(ExpectedType, *M), - Op.getOperandNo()); - Result.emplace_back(std::move(Type)); + if (ExpectedType != TypeMap.at(Op.get())) { + // Create a cast only if the expected type is different from the + // actual type propagated until here + auto Type = SerializedType(serializeToLLVMString(ExpectedType, *M), + Op.getOperandNo()); + Result.emplace_back(std::move(Type)); + } } - } - }; + }; if (auto *Call = dyn_cast(I)) { // Lifted functions have their prototype on the model @@ -189,12 +195,13 @@ bool MMCP::runOnFunction(Function &F) { ModelFunction = llvmToModelFunction(*Model, F); revng_assert(ModelFunction != nullptr); + auto &Cache = getAnalysis().get(); - TypeMap = initModelTypes(F, ModelFunction, *Model, false); + TypeMap = initModelTypes(Cache, F, ModelFunction, *Model, false); for (BasicBlock &BB : F) { for (Instruction &I : BB) { - auto SerializedTypes = serializeTypesForModelCast(&I, *Model); + auto SerializedTypes = serializeTypesForModelCast(Cache, &I, *Model); if (!SerializedTypes.empty()) { Changed = true; diff --git a/lib/IRCanonicalization/MakeModelGEPPass.cpp b/lib/IRCanonicalization/MakeModelGEPPass.cpp index 598352a78..2b576b84b 100644 --- a/lib/IRCanonicalization/MakeModelGEPPass.cpp +++ b/lib/IRCanonicalization/MakeModelGEPPass.cpp @@ -24,7 +24,7 @@ #include "revng/ADT/RecursiveCoroutine.h" #include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Architecture.h" #include "revng/Model/Binary.h" #include "revng/Model/LoadModelPass.h" @@ -87,6 +87,7 @@ public: void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); + AU.addRequired(); } }; @@ -160,7 +161,8 @@ struct ModelGEPSummation { return ModelGEPSummation{ // The base address is unknown .BaseAddress = TypedBaseAddress{ .Type = {}, .Address = nullptr }, - // The summation has only one element, which is not valid, because it does + // The summation has only one element, which is not valid, because it + // does // not have a valid Index nor a valid Coefficient. .Summation = { ModelGEPSummationElement{ .Coefficient = nullptr, .Index = nullptr } } @@ -209,7 +211,8 @@ struct IRAccessPattern { using UseTypeMap = std::map; static IRAccessPattern -computeAccessPattern(const Use &U, +computeAccessPattern(FunctionMetadataCache &Cache, + const Use &U, const ModelGEPSummation &GEPSum, const model::Binary &Model, const ModelTypesMap &PointerTypes, @@ -445,7 +448,7 @@ computeAccessPattern(const Use &U, } } else if (FunctionTags::CallToLifted.isTagOf(Call)) { - auto Proto = getCallSitePrototype(Model, Call); + auto Proto = Cache.getCallSitePrototype(Model, Call); revng_assert(Proto.isValid()); if (const auto *RFT = dyn_cast(Proto.get())) { @@ -1339,8 +1342,8 @@ class GEPSummationCache { Result = ModelGEPSummation{ .BaseAddress = TypedBaseAddress{ .Type = dropPointer(Type), .Address = AddressArith }, - // The summation is empty since AddressArith has exactly the type - // we're looking at here. + // The summation is empty since AddressArith + // has exactly the type we're looking at here. .Summation = {} }; @@ -1917,7 +1920,8 @@ using UseGEPInfoMap = std::map; static UseGEPInfoMap makeGEPReplacements(llvm::Function &F, const model::Binary &Model, - model::VerifyHelper &VH) { + model::VerifyHelper &VH, + FunctionMetadataCache &Cache) { UseGEPInfoMap Result; @@ -1927,7 +1931,8 @@ static UseGEPInfoMap makeGEPReplacements(llvm::Function &F, // First, try to initialize a map for the known model types of llvm::Values // that are reachable from F. If this fails, we just bail out because we // cannot infer any modelGEP in F, if we have no type information to rely on. - ModelTypesMap PointerTypes = initModelTypes(F, + ModelTypesMap PointerTypes = initModelTypes(Cache, + F, ModelF, Model, /*PointersOnly=*/true); @@ -2025,7 +2030,8 @@ static UseGEPInfoMap makeGEPReplacements(llvm::Function &F, continue; // Now we extract an IRAccessPattern from the ModelGEPSummation - IRAccessPattern IRPattern = computeAccessPattern(U, + IRAccessPattern IRPattern = computeAccessPattern(Cache, + U, GEPSum, Model, PointerTypes, @@ -2127,8 +2133,9 @@ bool MakeModelGEPPass::runOnFunction(llvm::Function &F) { auto &Model = getAnalysis().get().getReadOnlyModel(); + auto &Cache = getAnalysis().get(); model::VerifyHelper VH; - UseGEPInfoMap GEPReplacementMap = makeGEPReplacements(F, *Model, VH); + UseGEPInfoMap GEPReplacementMap = makeGEPReplacements(F, *Model, VH, Cache); llvm::Module &M = *F.getParent(); LLVMContext &Ctxt = M.getContext(); diff --git a/lib/IRCanonicalization/RemoveLoadStore.cpp b/lib/IRCanonicalization/RemoveLoadStore.cpp index f0b291aa1..955be43b8 100644 --- a/lib/IRCanonicalization/RemoveLoadStore.cpp +++ b/lib/IRCanonicalization/RemoveLoadStore.cpp @@ -32,6 +32,7 @@ public: void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); + AU.addRequired(); AU.setPreservesCFG(); } }; @@ -75,7 +76,8 @@ bool RemoveLoadStore::runOnFunction(llvm::Function &F) { &Model = getAnalysis().get().getReadOnlyModel().get(); // Collect model types - auto TypeMap = initModelTypes(F, + auto TypeMap = initModelTypes(getAnalysis().get(), + F, llvmToModelFunction(*Model, F), *Model, /*PointersOnly=*/false); diff --git a/lib/InitModelTypes/InitModelTypes.cpp b/lib/InitModelTypes/InitModelTypes.cpp index b075a29b8..e2fb4ad62 100644 --- a/lib/InitModelTypes/InitModelTypes.cpp +++ b/lib/InitModelTypes/InitModelTypes.cpp @@ -13,7 +13,7 @@ #include "llvm/Support/Casting.h" #include "revng/ABI/FunctionType.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Architecture.h" #include "revng/Model/Binary.h" #include "revng/Model/CABIFunctionType.h" @@ -141,7 +141,8 @@ static RecursiveCoroutine addOperandType(const llvm::Value *Operand, /// Reconstruct the return type(s) of a Call instruction from its /// prototype, if it's an isolated function. For non-isolated functions, /// special rules apply to recover the returned type. -static TypeVector getReturnTypes(const llvm::CallInst *Call, +static TypeVector getReturnTypes(FunctionMetadataCache &Cache, + const llvm::CallInst *Call, const model::Function *ParentFunc, const Binary &Model, ModelTypesMap &TypeMap) { @@ -151,7 +152,7 @@ static TypeVector getReturnTypes(const llvm::CallInst *Call, return {}; // Check if we already have strong model information for this call - ReturnTypes = getStrongModelInfo(Call, Model); + ReturnTypes = getStrongModelInfo(Cache, Call, Model); if (not ReturnTypes.empty()) return ReturnTypes; @@ -201,13 +202,15 @@ static TypeVector getReturnTypes(const llvm::CallInst *Call, /// Given a call instruction, to either an isolated or a non-isolated /// function, assign to it its return type. If the call returns more than /// one type, infect the uses of the returned value with those types. -static void handleCallInstruction(const llvm::CallInst *Call, +static void handleCallInstruction(FunctionMetadataCache &Cache, + const llvm::CallInst *Call, const model::Function *ParentFunc, const Binary &Model, ModelTypesMap &TypeMap, bool PointersOnly) { - TypeVector ReturnedQualTypes = getReturnTypes(Call, + TypeVector ReturnedQualTypes = getReturnTypes(Cache, + Call, ParentFunc, Model, TypeMap); @@ -267,7 +270,8 @@ static void handleCallInstruction(const llvm::CallInst *Call, } } -ModelTypesMap initModelTypes(const llvm::Function &F, +ModelTypesMap initModelTypes(FunctionMetadataCache &Cache, + const llvm::Function &F, const model::Function *ModelF, const Binary &Model, bool PointersOnly) { @@ -297,7 +301,12 @@ ModelTypesMap initModelTypes(const llvm::Function &F, // the binary or to special intrinsics used by the backend, so they need // to be handled separately if (auto *Call = dyn_cast(&I)) { - handleCallInstruction(Call, ModelF, Model, TypeMap, PointersOnly); + handleCallInstruction(Cache, + Call, + ModelF, + Model, + TypeMap, + PointersOnly); continue; } @@ -443,7 +452,7 @@ ModelTypesMap initModelTypes(const llvm::Function &F, VMA.setUpdater(std::make_unique(TypeMap, &Model)); VMA.disableSolver(); - VMA.run(&F); + VMA.run(Cache, &F); return TypeMap; } diff --git a/lib/PromoteStackPointer/DetectStackSizePass.cpp b/lib/PromoteStackPointer/DetectStackSizePass.cpp index 12d6f192f..b2753acde 100644 --- a/lib/PromoteStackPointer/DetectStackSizePass.cpp +++ b/lib/PromoteStackPointer/DetectStackSizePass.cpp @@ -6,7 +6,7 @@ #include "llvm/IR/Constants.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/IRHelpers.h" #include "revng/Model/LoadModelPass.h" #include "revng/Model/VerifyHelper.h" @@ -107,10 +107,10 @@ public: CallInstructionPushSize(Architecture::getCallPushSize(B->Architecture)) {} public: - void run(Module &M) { + void run(FunctionMetadataCache &Cache, Module &M) { // Collect information about the stack of each function for (llvm::Function &F : FunctionTags::Isolated.functions(&M)) - collectStackBounds(F); + collectStackBounds(Cache, F); // At this point we have populated two data structures: // @@ -128,14 +128,15 @@ public: } private: - void collectStackBounds(Function &F); + void collectStackBounds(FunctionMetadataCache &Cache, Function &F); void electStackArgumentsSize(RawFunctionType *Prototype, const UpperBoundCollector &Bound) const; void electFunctionStackFrameSize(FunctionStackInfo &FSI); std::optional handleCallSite(const CallSite &CallSite); }; -void DetectStackSize::collectStackBounds(Function &F) { +void DetectStackSize::collectStackBounds(FunctionMetadataCache &Cache, + Function &F) { // Obtain model::Function corresponding to this llvm::Function MetaAddress Entry = getMetaAddressMetadata(&F, "revng.function.entry"); @@ -187,9 +188,10 @@ void DetectStackSize::collectStackBounds(Function &F) { NewCallSite.StackSize = Offset->getLimitedValue(); // Get the prototype - auto *Proto = getCallSitePrototype(*Binary.get(), - Call, - &ModelFunction) + auto *Proto = Cache + .getCallSitePrototype(*Binary.get(), + Call, + &ModelFunction) .get(); NewCallSite.Prototype = nullptr; @@ -337,13 +339,14 @@ bool DetectStackSizePass::runOnModule(Module &M) { TupleTree &Binary = ModelWrapper.getWriteableModel(); DetectStackSize StackSizeDetector(Binary); - StackSizeDetector.run(M); + StackSizeDetector.run(getAnalysis().get(), M); return false; } void DetectStackSizePass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); + AU.addRequired(); AU.setPreservesCFG(); } diff --git a/lib/PromoteStackPointer/PromoteStackPointerPass.cpp b/lib/PromoteStackPointer/PromoteStackPointerPass.cpp index 8cd612fbe..4ede1ea35 100644 --- a/lib/PromoteStackPointer/PromoteStackPointerPass.cpp +++ b/lib/PromoteStackPointer/PromoteStackPointerPass.cpp @@ -22,7 +22,7 @@ #include "llvm/Support/Casting.h" #include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/LoadModelPass.h" #include "revng/Pipeline/RegisterLLVMPass.h" #include "revng/Support/Assert.h" @@ -37,7 +37,8 @@ using namespace llvm; static Logger<> Log("promote-stack-pointer"); -static bool adjustStackAfterCalls(const model::Binary &Binary, +static bool adjustStackAfterCalls(FunctionMetadataCache &Cache, + const model::Binary &Binary, Function &F, GlobalVariable *GlobalSP) { bool Changed = false; @@ -56,9 +57,10 @@ static bool adjustStackAfterCalls(const model::Binary &Binary, revng_assert(MD != nullptr); // TODO: handle CABIFunctionType - auto *Proto = getCallSitePrototype(Binary, - cast(&I), - &ModelFunction) + auto *Proto = Cache + .getCallSitePrototype(Binary, + cast(&I), + &ModelFunction) .get(); if (auto *RawPrototype = dyn_cast(Proto)) { auto *FSO = ConstantInt::get(SPType, RawPrototype->FinalStackOffset); @@ -96,7 +98,12 @@ bool PromoteStackPointerPass::runOnFunction(Function &F) { auto &ModelWrapper = getAnalysis().get(); const model::Binary &Binary = *ModelWrapper.getReadOnlyModel(); - Changed = adjustStackAfterCalls(Binary, F, GlobalSP) or Changed; + Changed = adjustStackAfterCalls(getAnalysis() + .get(), + Binary, + F, + GlobalSP) + or Changed; std::vector SPUsers; for (User *U : GlobalSP->users()) { @@ -179,6 +186,7 @@ bool PromoteStackPointerPass::runOnFunction(Function &F) { void PromoteStackPointerPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesCFG(); } diff --git a/lib/PromoteStackPointer/SegregateStackAccessesPass.cpp b/lib/PromoteStackPointer/SegregateStackAccessesPass.cpp index 44f8205aa..5ba27c189 100644 --- a/lib/PromoteStackPointer/SegregateStackAccessesPass.cpp +++ b/lib/PromoteStackPointer/SegregateStackAccessesPass.cpp @@ -10,7 +10,7 @@ #include "revng/ABI/FunctionType.h" #include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/MFP/MFP.h" #include "revng/MFP/SetLattices.h" #include "revng/Model/IRHelpers.h" @@ -258,9 +258,11 @@ private: llvm::Type *PtrSizedInteger; OpaqueFunctionsPool AddressOfPool; + FunctionMetadataCache *Cache; public: - SegregateStackAccesses(const model::Binary &Binary, + SegregateStackAccesses(FunctionMetadataCache &Cache, + const model::Binary &Binary, Module &M, Value *StackPointer) : Binary(Binary), @@ -271,7 +273,8 @@ public: CallInstructionPushSize(getCallPushSize(Binary)), SPType(StackPointer->getType()->getPointerElementType()), PtrSizedInteger(getPointerSizedInteger(M.getContext(), Binary)), - AddressOfPool(&M, false) { + AddressOfPool(&M, false), + Cache(&Cache) { revng_assert(SSACS != nullptr); @@ -304,7 +307,7 @@ public: upgradeLocalFunctions(); for (Function &F : FunctionTags::StackPointerPromoted.functions(&M)) { - segregateStackAccesses(F); + segregateStackAccesses(*Cache, F); FunctionTags::StackAccessesSegregated.addTo(&F); } @@ -493,7 +496,7 @@ private: } } - void segregateStackAccesses(Function &F) { + void segregateStackAccesses(FunctionMetadataCache &Cache, Function &F) { if (F.isDeclaration()) return; @@ -549,7 +552,7 @@ private: // // Handle a call to an isolated function // - handleCallSite(ModelFunction, AnalysisResult, SSACSCall); + handleCallSite(Cache, ModelFunction, AnalysisResult, SSACSCall); } else if ((isa(&I) or isa(&I)) and Redirector != nullptr) { // @@ -581,7 +584,8 @@ private: } } - void handleCallSite(const model::Function &ModelFunction, + void handleCallSite(FunctionMetadataCache &Cache, + const model::Function &ModelFunction, MFIResult &AnalysisResult, CallInst *SSACSCall) { revng_log(Log, "Handling call site " << getName(SSACSCall)); @@ -599,7 +603,9 @@ private: // Obtain RawFunctionType auto *MD = SSACSCall->getMetadata("revng.callerblock.start"); revng_assert(MD != nullptr); - auto Prototype = getCallSitePrototype(Binary, SSACSCall, &ModelFunction); + auto Prototype = Cache.getCallSitePrototype(Binary, + SSACSCall, + &ModelFunction); using namespace abi::FunctionType; abi::FunctionType::Layout Layout = Layout::make(*Prototype.get()); @@ -999,7 +1005,10 @@ bool SegregateStackAccessesPass::runOnModule(Module &M) { // Get the stack pointer type auto &GCBI = getAnalysis().getGCBI(); - SegregateStackAccesses SSA(Binary, M, GCBI.spReg()); + SegregateStackAccesses SSA(getAnalysis().get(), + Binary, + M, + GCBI.spReg()); return SSA.run(); } @@ -1007,6 +1016,7 @@ void SegregateStackAccessesPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); } char SegregateStackAccessesPass::ID = 0; diff --git a/lib/Support/ModelHelpers.cpp b/lib/Support/ModelHelpers.cpp index c0e9c9a54..b39e076a6 100644 --- a/lib/Support/ModelHelpers.cpp +++ b/lib/Support/ModelHelpers.cpp @@ -12,7 +12,7 @@ #include "revng/ABI/FunctionType.h" #include "revng/ADT/RecursiveCoroutine.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Model/IRHelpers.h" #include "revng/Model/QualifiedType.h" @@ -265,7 +265,9 @@ traverseModelGEP(const model::Binary &Model, const llvm::CallInst *Call) { } RecursiveCoroutine> -getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model) { +getStrongModelInfo(FunctionMetadataCache &Cache, + const llvm::Instruction *Inst, + const model::Binary &Model) { llvm::SmallVector ReturnTypes; auto ParentFunc = [&Model, &Inst]() { @@ -276,7 +278,7 @@ getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model) { if (FunctionTags::CallToLifted.isTagOf(Call)) { // Isolated functions have their prototype in the model - auto Prototype = getCallSitePrototype(Model, Call); + auto Prototype = Cache.getCallSitePrototype(Model, Call); revng_assert(Prototype.isValid()); auto PrototypePath = Prototype.get(); @@ -364,7 +366,7 @@ getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model) { } else if (FuncName.startswith("revng_call_stack_arguments")) { // The prototype attached to this callsite represents the prototype of // the function that needs the stack arguments returned by this call - auto Prototype = getCallSitePrototype(Model, Call, ParentFunc()); + auto Prototype = Cache.getCallSitePrototype(Model, Call, ParentFunc()); revng_assert(Prototype.isValid()); // Only RawFunctionTypes have explicit stack arguments @@ -383,14 +385,16 @@ getStrongModelInfo(const llvm::Instruction *Inst, const model::Binary &Model) { AggregateOp = Call->getArgOperand(0); if (auto *OriginalInst = llvm::dyn_cast(AggregateOp)) - rc_return rc_recur getStrongModelInfo(OriginalInst, Model); + rc_return rc_recur getStrongModelInfo(Cache, OriginalInst, Model); } rc_return ReturnTypes; } llvm::SmallVector -getExpectedModelType(const llvm::Use *U, const model::Binary &Model) { +getExpectedModelType(FunctionMetadataCache &Cache, + const llvm::Use *U, + const model::Binary &Model) { llvm::Instruction *User = dyn_cast(U->getUser()); if (not User) @@ -403,7 +407,7 @@ getExpectedModelType(const llvm::Use *U, const model::Binary &Model) { if (auto *Call = dyn_cast(User)) { if (FunctionTags::CallToLifted.isTagOf(Call)) { // Isolated functions have their prototype in the model - auto Prototype = getCallSitePrototype(Model, Call); + auto Prototype = Cache.getCallSitePrototype(Model, Call); revng_assert(Prototype.isValid()); auto PrototypePath = Prototype.get(); diff --git a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp index 9994ba905..164895ace 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp +++ b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp @@ -36,8 +36,9 @@ static Logger<> TGLog("vma-tg"); /// Returns a ColorSet with the types that can be assigned to a given use or /// value. -static ColorSet -getAcceptedColors(const UseOrValue &Content, const model::Binary *Model) { +static ColorSet getAcceptedColors(FunctionMetadataCache &Cache, + const UseOrValue &Content, + const model::Binary *Model) { // Instructions and operand uses should be the only thing remaining bool IsContentInst = isInst(Content); @@ -59,8 +60,10 @@ getAcceptedColors(const UseOrValue &Content, const model::Binary *Model) { // Deduce type for the use or for the value, depending on which type of // node we are looking at auto DeducedTypes = IsContentInst ? - getStrongModelInfo(ContentInst, *Model) : - getExpectedModelType(getUse(Content), *Model); + getStrongModelInfo(Cache, ContentInst, *Model) : + getExpectedModelType(Cache, + getUse(Content), + *Model); // If we weren't able to deduce anything, fallthrough to the default // handling when there is no model. @@ -216,10 +219,12 @@ getAcceptedColors(const UseOrValue &Content, const model::Binary *Model) { return ~NUMBERNESS; } -TypeFlowNode *TypeFlowGraph::addNodeContaining(const UseOrValue &NC) { +TypeFlowNode *TypeFlowGraph::addNodeContaining(FunctionMetadataCache &Cache, + const UseOrValue &NC) { revng_assert(not ContentToNodeMap.count(NC)); - NodeColorProperty InitialColors = { NO_COLOR, getAcceptedColors(NC, Model) }; + NodeColorProperty InitialColors = { NO_COLOR, + getAcceptedColors(Cache, NC, Model) }; auto *N = this->addNode(NC, InitialColors); ContentToNodeMap[NC] = N; @@ -418,7 +423,8 @@ static bool connect(TypeFlowNode *N1, TypeFlowNode *N2) { return false; } -TypeFlowGraph vma::makeTypeFlowGraphFromFunction(const llvm::Function *F, +TypeFlowGraph vma::makeTypeFlowGraphFromFunction(FunctionMetadataCache &Cache, + const llvm::Function *F, const model::Binary *Model) { TypeFlowGraph TG; TG.Func = F; @@ -455,7 +461,7 @@ TypeFlowGraph vma::makeTypeFlowGraphFromFunction(const llvm::Function *F, revng_assert(any_of(I.users(), IsPhiInstr)); InstNode = TG.ContentToNodeMap[&I]; } else if (ShouldValueBeAdded(&I)) { - InstNode = TG.addNodeContaining(&I); + InstNode = TG.addNodeContaining(Cache, &I); } else { // Skip values that should not be added to the TypeFlowGraph continue; @@ -469,7 +475,7 @@ TypeFlowGraph vma::makeTypeFlowGraphFromFunction(const llvm::Function *F, if (not ShouldUseBeAdded(&Op)) continue; - TypeFlowNode *UseNode = TG.addNodeContaining(&Op); + TypeFlowNode *UseNode = TG.addNodeContaining(Cache, &Op); connect(UseNode, InstNode); revng_log(TGLog, "USE: " << UseNode); @@ -485,7 +491,7 @@ TypeFlowGraph vma::makeTypeFlowGraphFromFunction(const llvm::Function *F, if (not TG.ContentToNodeMap.count(Op.get())) { revng_assert(I.getOpcode() == Instruction::PHI or not isa(Op.get())); - TG.addNodeContaining(Op.get()); + TG.addNodeContaining(Cache, Op.get()); } auto *OpValNode = TG.ContentToNodeMap[Op.get()]; diff --git a/lib/ValueManipulationAnalysis/TypeFlowGraph.h b/lib/ValueManipulationAnalysis/TypeFlowGraph.h index f4d2ee670..27e90e8d9 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowGraph.h +++ b/lib/ValueManipulationAnalysis/TypeFlowGraph.h @@ -12,6 +12,7 @@ #include "revng/ADT/FilteredGraphTraits.h" #include "revng/ADT/GenericGraph.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng-c/ValueManipulationAnalysis/TypeColors.h" @@ -32,7 +33,8 @@ struct TypeFlowGraph : public GenericGraph { TypeFlowGraph &operator=(const TypeFlowGraph &N) = default; TypeFlowGraph &operator=(TypeFlowGraph &&N) = default; - TypeFlowNode *addNodeContaining(const UseOrValue &); + TypeFlowNode * + addNodeContaining(FunctionMetadataCache &Cache, const UseOrValue &); TypeFlowNode *getNodeContaining(const UseOrValue &) const; /// Print the graph on a `.dot` file @@ -55,7 +57,8 @@ struct TypeFlowGraph : public GenericGraph { // --------------- TypeFlowGraph manipulation /// Add to \a TG the `llvm::Use`s and `llvm::Value`s inside \a F -TypeFlowGraph makeTypeFlowGraphFromFunction(const llvm::Function *F, +TypeFlowGraph makeTypeFlowGraphFromFunction(FunctionMetadataCache &Cache, + const llvm::Function *F, const model::Binary *Model); /// Propagate colors from colored nodes trough colored edges diff --git a/lib/ValueManipulationAnalysis/VMAPipeline.cpp b/lib/ValueManipulationAnalysis/VMAPipeline.cpp index 438fdfd11..7d0402938 100644 --- a/lib/ValueManipulationAnalysis/VMAPipeline.cpp +++ b/lib/ValueManipulationAnalysis/VMAPipeline.cpp @@ -295,9 +295,9 @@ void VMAPipeline::runSolver() { minCut(*TFG); } -void VMAPipeline::run(const llvm::Function *F) { +void VMAPipeline::run(FunctionMetadataCache &Cache, const llvm::Function *F) { // Nodes and edges initialization - auto TypeGraph = vma::makeTypeFlowGraphFromFunction(F, &Model); + auto TypeGraph = vma::makeTypeFlowGraphFromFunction(Cache, F, &Model); TFG = &TypeGraph; // Color initialization diff --git a/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp b/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp index 22a4fdf8d..84b9839bc 100644 --- a/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp +++ b/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp @@ -50,6 +50,7 @@ public: // LLVM Pass void VMA::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } @@ -71,7 +72,7 @@ bool VMA::runOnFunction(Function &F) { VMA.setUpdater(std::make_unique(ColorMap)); VMA.enableSolver(); - VMA.run(&F); + VMA.run(getAnalysis().get(), &F); return false; } diff --git a/tests/unit/ValueManipulationAnalysis.cpp b/tests/unit/ValueManipulationAnalysis.cpp index fe2492b9b..f661f44de 100644 --- a/tests/unit/ValueManipulationAnalysis.cpp +++ b/tests/unit/ValueManipulationAnalysis.cpp @@ -154,6 +154,7 @@ static void checkInit(const char *Body, const ExpectedShape ExpectedInit, const ExpectedShape ExpectedAfterProp, const ExpectedShape ExpectedFinal) { + FunctionMetadataCache Cache; // Read the LLVM IR LLVMContext C; std::unique_ptr M = loadModule(C, Body); @@ -162,7 +163,7 @@ static void checkInit(const char *Body, Function *F = M->getFunction("main"); // Build the TG - TypeFlowGraph TG = makeTypeFlowGraphFromFunction(F, /*Model=*/nullptr); + TypeFlowGraph TG = makeTypeFlowGraphFromFunction(Cache, F, /*Model=*/nullptr); LLVMInitializer Init; Init.initializeColors(&TG); diff --git a/tools/decompile/Main.cpp b/tools/decompile/Main.cpp index b6c5b502b..6b8572d4a 100644 --- a/tools/decompile/Main.cpp +++ b/tools/decompile/Main.cpp @@ -128,7 +128,8 @@ int main(int Argc, const char *Argv[]) { revng::pipes::DecompiledCCodeInYAMLStringMap DecompiledFunctions("" /*Name*/, &Model); - decompile(*Module, *Model, DecompiledFunctions); + FunctionMetadataCache Cache; + decompile(Cache, *Module, *Model, DecompiledFunctions); llvm::cantFail(DecompiledFunctions.serialize(DecompiledOutFile));