From 0c7b9794530151054959fbb5df2ea20911e487b0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:30:35 +0200 Subject: [PATCH] EF SemiRing in Problem (#722) * Tie the EF semi-ring to the problem + integrate into solver * Incorporate combine and extend into IIA * minor * Fix IIA * apply review comment --- .../DataFlow/IfdsIde/EdgeFunctionUtils.h | 37 ++++ .../DataFlow/IfdsIde/IDETabulationProblem.h | 2 + .../DataFlow/IfdsIde/Solver/IDESolver.h | 21 ++- .../Problems/IDEInstInteractionAnalysis.h | 173 ++++++++---------- include/phasar/Utils/BitVectorSet.h | 10 +- include/phasar/Utils/SemiRing.h | 34 ++++ 6 files changed, 163 insertions(+), 114 deletions(-) create mode 100644 include/phasar/Utils/SemiRing.h diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index de9db609a..bfbc9d233 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -132,6 +132,23 @@ defaultComposeOrNull(EdgeFunctionRef This, return nullptr; } +template +EdgeFunction +defaultComposeOrNull(const EdgeFunction &This, + const EdgeFunction &SecondFunction) noexcept { + if (llvm::isa>(SecondFunction)) { + return This; + } + if (SecondFunction.isConstant() || llvm::isa>(This) || + llvm::isa>(This)) { + return SecondFunction; + } + if (llvm::isa>(This)) { + return This; + } + return nullptr; +} + template struct ConstantEdgeFunction { using l_t = L; using JLattice = JoinLatticeTraits; @@ -409,6 +426,26 @@ EdgeFunction defaultJoinOrNull(EdgeFunctionRef This, return nullptr; } +template +EdgeFunction defaultJoinOrNull(const EdgeFunction &This, + const EdgeFunction &OtherFunction) { + if (llvm::isa>(OtherFunction) || llvm::isa>(This)) { + return OtherFunction; + } + if (llvm::isa>(OtherFunction) || OtherFunction == This || + llvm::isa>(This)) { + return This; + } + if (llvm::isa>(OtherFunction)) { + if constexpr (N > 0) { + return JoinEdgeFunction::create(This, OtherFunction); + } else if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } + } + return nullptr; +} + template EdgeFunction EdgeIdentity::join(EdgeFunctionRef This, const EdgeFunction &OtherFunction) { diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index 4cdc3610f..5d3dc71f6 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -22,6 +22,7 @@ #include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/NullAnalysisPrinter.h" #include "phasar/Utils/Printer.h" +#include "phasar/Utils/SemiRing.h" #include "phasar/Utils/Soundness.h" #include "llvm/ADT/StringRef.h" @@ -62,6 +63,7 @@ template , public EdgeFunctions, public JoinLattice, + public SemiRing, public AllTopFnProvider { public: using ProblemAnalysisDomain = AnalysisDomainTy; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 3274ced1a..9f10b10e2 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -406,7 +406,7 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "Compose: " << SumEdgFnE << " * " << f << '\n'); WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)), - f.composeWith(SumEdgFnE)); + IDEProblem.extend(f, SumEdgFnE)); } } } else { @@ -498,15 +498,15 @@ class IDESolver << f4); PHASAR_LOG_LEVEL(DEBUG, " (return * calleeSummary * call)"); - EdgeFunction fPrime = - f4.composeWith(fCalleeSummary).composeWith(f5); + EdgeFunction fPrime = IDEProblem.extend( + IDEProblem.extend(f4, fCalleeSummary), f5); PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime); d_t d5_restoredCtx = restoreContextOnReturnedFact(n, d2, d5); // propagte the effects of the entire call PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f); WorkList.emplace_back( PathEdge(d1, RetSiteN, std::move(d5_restoredCtx)), - f.composeWith(fPrime)); + IDEProblem.extend(f, fPrime)); } } } @@ -538,7 +538,7 @@ class IDESolver .push_back(EdgeFnE); } INC_COUNTER("EF Queries", 1, Full); - auto fPrime = f.composeWith(EdgeFnE); + auto fPrime = IDEProblem.extend(f, EdgeFnE); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE << " * " << f << " = " << fPrime); WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)), @@ -570,7 +570,7 @@ class IDESolver EdgeFunction g = CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3); PHASAR_LOG_LEVEL(DEBUG, "Queried Normal Edge Function: " << g); - EdgeFunction fPrime = f.composeWith(g); + EdgeFunction fPrime = IDEProblem.extend(f, g); if (SolverConfig.emitESG()) { IntermediateEdgeFunctions[std::make_tuple(n, d2, nPrime, d3)] .push_back(g); @@ -950,7 +950,8 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << f << " * " << f4); PHASAR_LOG_LEVEL(DEBUG, " (return * function * call)"); - EdgeFunction fPrime = f4.composeWith(f).composeWith(f5); + EdgeFunction fPrime = + IDEProblem.extend(IDEProblem.extend(f4, f), f5); PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime); // for each jump function coming into the call, propagate to // return site using the composed function @@ -965,7 +966,7 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f3); WorkList.emplace_back(PathEdge(std::move(d3), RetSiteC, std::move(d5_restoredCtx)), - f3.composeWith(fPrime)); + IDEProblem.extend(f3, fPrime)); } } } @@ -1004,7 +1005,7 @@ class IDESolver } INC_COUNTER("EF Queries", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << f); - propagteUnbalancedReturnFlow(RetSiteC, d5, f.composeWith(f5), + propagteUnbalancedReturnFlow(RetSiteC, d5, IDEProblem.extend(f, f5), Caller); // register for value processing (2nd IDE phase) UnbalancedRetSites.insert(RetSiteC); @@ -1153,7 +1154,7 @@ class IDESolver // was found return AllTop; }(); - EdgeFunction fPrime = JumpFnE.joinWith(f); + EdgeFunction fPrime = IDEProblem.combine(JumpFnE, f); bool NewFunction = fPrime != JumpFnE; IF_LOG_LEVEL_ENABLED(DEBUG, { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 40d1dff44..b4410d1f9 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -11,6 +11,7 @@ #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONANALYSIS_H #include "phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" @@ -949,59 +950,15 @@ class IDEInstInteractionAnalysisT l_t computeTarget(ByConstRef /* Src */) const { return Replacement; } - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction SecondFunction) { - - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - auto Cache = This.getCacheOrNull(); - assert(Cache != nullptr && "We expect a cache, because " - "IIAAKillOrReplaceEF is too large for SOO"); - - if (auto *AD = llvm::dyn_cast(SecondFunction)) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data); - return Cache->createEdgeFunction(std::move(Union)); - } - - if (auto *KR = llvm::dyn_cast(SecondFunction)) { - return SecondFunction; - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAKillOrReplaceEF'"); + static EdgeFunction + compose(EdgeFunctionRef /*This*/, + const EdgeFunction /*SecondFunction*/) { + llvm::report_fatal_error("Implemented in 'extend'"); } - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - /// XXX: Here, we underapproximate joins with EdgeIdentity - if (llvm::isa>(OtherFunction)) { - return This; - } - - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - auto Cache = This.getCacheOrNull(); - assert(Cache != nullptr && "We expect a cache, because " - "IIAAKillOrReplaceEF is too large for SOO"); - - if (auto *AD = llvm::dyn_cast(OtherFunction)) { - auto ADCache = OtherFunction.template getCacheOrNull(); - assert(ADCache); - auto Union = - IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data); - return ADCache->createEdgeFunction(std::move(Union)); - } - if (auto *KR = llvm::dyn_cast(OtherFunction)) { - auto Union = IDEInstInteractionAnalysisT::joinImpl(This->Replacement, - KR->Replacement); - return Cache->createEdgeFunction(std::move(Union)); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAKillOrReplaceEF'"); + static EdgeFunction join(EdgeFunctionRef /*This*/, + const EdgeFunction & /*OtherFunction*/) { + llvm::report_fatal_error("Implemented in 'combine'"); } bool operator==(const IIAAKillOrReplaceEF &Other) const noexcept { @@ -1044,55 +1001,15 @@ class IDEInstInteractionAnalysisT return IDEInstInteractionAnalysisT::joinImpl(Src, Data); } - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction &SecondFunction) { - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - auto Cache = This.getCacheOrNull(); - assert(Cache != nullptr && "We expect a cache, because " - "IIAAAddLabelsEF is too large for SOO"); - - if (auto *AD = llvm::dyn_cast(SecondFunction)) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data); - return Cache->createEdgeFunction(std::move(Union)); - } - if (auto *KR = llvm::dyn_cast(SecondFunction)) { - return SecondFunction; - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAAddLabelsEF'"); + static EdgeFunction + compose(EdgeFunctionRef /*This*/, + const EdgeFunction & /*SecondFunction*/) { + llvm::report_fatal_error("Implemented in 'extend'"); } - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - /// XXX: Here, we underapproximate joins with EdgeIdentity - if (llvm::isa>(OtherFunction)) { - return This; - } - - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - auto Cache = This.getCacheOrNull(); - assert(Cache != nullptr && "We expect a cache, because " - "IIAAAddLabelsEF is too large for SOO"); - - if (auto *AD = llvm::dyn_cast(OtherFunction)) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data); - return Cache->createEdgeFunction(std::move(Union)); - } - if (auto *KR = llvm::dyn_cast(OtherFunction)) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(This->Data, KR->Replacement); - return Cache->createEdgeFunction(std::move(Union)); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAAddLabelsEF'"); + static EdgeFunction join(EdgeFunctionRef /*This*/, + const EdgeFunction & /*OtherFunction*/) { + llvm::report_fatal_error("Implemented in 'combine'"); } bool operator==(const IIAAAddLabelsEF &Other) const noexcept { @@ -1112,6 +1029,64 @@ class IDEInstInteractionAnalysisT } }; + const auto &getData(const EdgeFunction &EF) { + if (const auto *AddLabels = llvm::dyn_cast(EF)) { + return AddLabels->Data; + } + if (const auto *KillOrReplace = llvm::dyn_cast(EF)) { + return KillOrReplace->Replacement; + } + llvm::report_fatal_error( + "found unexpected first edge function in 'getData': " + + llvm::Twine(to_string(EF))); + } + + EdgeFunction extend(const EdgeFunction &FirstFunction, + const EdgeFunction &SecondFunction) override { + if (auto Default = defaultComposeOrNull(FirstFunction, SecondFunction)) { + return Default; + } + + const auto &ThisData = getData(FirstFunction); + + if (auto *AD = llvm::dyn_cast(SecondFunction)) { + auto Union = IDEInstInteractionAnalysisT::joinImpl(ThisData, AD->Data); + return llvm::isa(FirstFunction) + ? IIAAAddLabelsEFCache.createEdgeFunction(std::move(Union)) + : IIAAKillOrReplaceEFCache.createEdgeFunction( + std::move(Union)); + } + + llvm::report_fatal_error( + "found unexpected second edge function in 'extend'"); + } + + EdgeFunction combine(const EdgeFunction &FirstFunction, + const EdgeFunction &OtherFunction) override { + /// XXX: Here, we underapproximate joins with EdgeIdentity + if (llvm::isa>(FirstFunction)) { + return OtherFunction; + } + if (llvm::isa>(OtherFunction) && + !llvm::isa>(FirstFunction)) { + return FirstFunction; + } + + if (auto Default = defaultJoinOrNull(FirstFunction, OtherFunction)) { + return Default; + } + + const auto &ThisData = getData(FirstFunction); + const auto &OtherData = getData(OtherFunction); + auto Union = IDEInstInteractionAnalysisT::joinImpl(ThisData, OtherData); + + if (llvm::isa(FirstFunction) && + llvm::isa(OtherFunction)) { + return IIAAKillOrReplaceEFCache.createEdgeFunction(std::move(Union)); + } + return IIAAAddLabelsEFCache.createEdgeFunction(std::move(Union)); + } + // Provide functionalities for printing things and emitting text reports. static void stripBottomResults(std::unordered_map &Res) { @@ -1173,7 +1148,7 @@ class IDEInstInteractionAnalysisT } if (const auto *H = llvm::dyn_cast(I)) { if (!H->isIndirectCall() && H->getCalledFunction() && - this->ICF->isHeapAllocatingFunction(H->getCalledFunction())) { + psr::isHeapAllocatingFunction(H->getCalledFunction())) { Variables.insert(H); } } diff --git a/include/phasar/Utils/BitVectorSet.h b/include/phasar/Utils/BitVectorSet.h index 418d90e60..308245c82 100644 --- a/include/phasar/Utils/BitVectorSet.h +++ b/include/phasar/Utils/BitVectorSet.h @@ -177,11 +177,11 @@ template class BitVectorSet { } [[nodiscard]] BitVectorSet setUnion(const BitVectorSet &Other) const { - size_t MaxSize = std::max(Bits.size(), Other.Bits.size()); - BitVectorSet Res; - Res.Bits.reserve(MaxSize); - Res.Bits = Bits; - Res.Bits |= Other.Bits; + const bool ThisSetIsSmaller = Bits.size() < Other.Bits.size(); + BitVectorSet Res = ThisSetIsSmaller ? Other : *this; + const BitVectorSet &Smaller = ThisSetIsSmaller ? *this : Other; + + Res.Bits |= Smaller.Bits; return Res; } diff --git a/include/phasar/Utils/SemiRing.h b/include/phasar/Utils/SemiRing.h new file mode 100644 index 000000000..e4999d329 --- /dev/null +++ b/include/phasar/Utils/SemiRing.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_SEMIRING_H +#define PHASAR_UTILS_SEMIRING_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" + +namespace psr { +template class SemiRing { +public: + using l_t = typename AnalysisDomainTy::l_t; + + virtual ~SemiRing() = default; + + virtual EdgeFunction extend(const EdgeFunction &L, + const EdgeFunction &R) { + return L.composeWith(R); + } + + virtual EdgeFunction combine(const EdgeFunction &L, + const EdgeFunction &R) { + return L.joinWith(R); + } +}; +} // namespace psr + +#endif // PHASAR_UTILS_SEMIRING_H