Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EF SemiRing in Problem #722

Merged
merged 7 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,23 @@ defaultComposeOrNull(EdgeFunctionRef<ConcreteEF> This,
return nullptr;
}

template <typename L>
EdgeFunction<L>
defaultComposeOrNull(const EdgeFunction<L> &This,
const EdgeFunction<L> &SecondFunction) noexcept {
if (llvm::isa<EdgeIdentity<L>>(SecondFunction)) {
return This;
}
if (SecondFunction.isConstant() || llvm::isa<AllTop<L>>(This) ||
llvm::isa<EdgeIdentity<L>>(This)) {
return SecondFunction;
}
if (llvm::isa<AllBottom<L>>(This)) {
return This;
}
return nullptr;
}

template <typename L> struct ConstantEdgeFunction {
using l_t = L;
using JLattice = JoinLatticeTraits<L>;
Expand Down Expand Up @@ -409,6 +426,26 @@ EdgeFunction<L> defaultJoinOrNull(EdgeFunctionRef<ConcreteEF> This,
return nullptr;
}

template <typename L, uint8_t N = 0>
EdgeFunction<L> defaultJoinOrNull(const EdgeFunction<L> &This,
const EdgeFunction<L> &OtherFunction) {
if (llvm::isa<AllBottom<L>>(OtherFunction) || llvm::isa<AllTop<L>>(This)) {
return OtherFunction;
}
if (llvm::isa<AllTop<L>>(OtherFunction) || OtherFunction == This ||
llvm::isa<AllBottom<L>>(This)) {
return This;
}
if (llvm::isa<EdgeIdentity<L>>(OtherFunction)) {
if constexpr (N > 0) {
return JoinEdgeFunction<L, N>::create(This, OtherFunction);
} else if constexpr (HasJoinLatticeTraits<L>) {
return AllBottom<L>{};
}
}
return nullptr;
}

template <typename L>
EdgeFunction<L> EdgeIdentity<L>::join(EdgeFunctionRef<EdgeIdentity> This,
const EdgeFunction<L> &OtherFunction) {
Expand Down
2 changes: 2 additions & 0 deletions include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -62,6 +63,7 @@ template <typename AnalysisDomainTy,
class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
public EdgeFunctions<AnalysisDomainTy>,
public JoinLattice<AnalysisDomainTy>,
public SemiRing<AnalysisDomainTy>,
public AllTopFnProvider<AnalysisDomainTy> {
public:
using ProblemAnalysisDomain = AnalysisDomainTy;
Expand Down
21 changes: 11 additions & 10 deletions include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -498,15 +498,15 @@ class IDESolver
<< f4);
PHASAR_LOG_LEVEL(DEBUG,
" (return * calleeSummary * call)");
EdgeFunction<l_t> fPrime =
f4.composeWith(fCalleeSummary).composeWith(f5);
EdgeFunction<l_t> 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));
}
}
}
Expand Down Expand Up @@ -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)),
Expand Down Expand Up @@ -570,7 +570,7 @@ class IDESolver
EdgeFunction<l_t> g =
CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3);
PHASAR_LOG_LEVEL(DEBUG, "Queried Normal Edge Function: " << g);
EdgeFunction<l_t> fPrime = f.composeWith(g);
EdgeFunction<l_t> fPrime = IDEProblem.extend(f, g);
if (SolverConfig.emitESG()) {
IntermediateEdgeFunctions[std::make_tuple(n, d2, nPrime, d3)]
.push_back(g);
Expand Down Expand Up @@ -950,7 +950,8 @@ class IDESolver
PHASAR_LOG_LEVEL(DEBUG,
"Compose: " << f5 << " * " << f << " * " << f4);
PHASAR_LOG_LEVEL(DEBUG, " (return * function * call)");
EdgeFunction<l_t> fPrime = f4.composeWith(f).composeWith(f5);
EdgeFunction<l_t> 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
Expand All @@ -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));
}
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1153,7 +1154,7 @@ class IDESolver
// was found
return AllTop;
}();
EdgeFunction<l_t> fPrime = JumpFnE.joinWith(f);
EdgeFunction<l_t> fPrime = IDEProblem.combine(JumpFnE, f);
bool NewFunction = fPrime != JumpFnE;

IF_LOG_LEVEL_ENABLED(DEBUG, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -949,59 +950,15 @@ class IDEInstInteractionAnalysisT

l_t computeTarget(ByConstRef<l_t> /* Src */) const { return Replacement; }

static EdgeFunction<l_t> compose(EdgeFunctionRef<IIAAKillOrReplaceEF> This,
const EdgeFunction<l_t> 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<IIAAAddLabelsEF>(SecondFunction)) {
auto Union =
IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data);
return Cache->createEdgeFunction(std::move(Union));
}

if (auto *KR = llvm::dyn_cast<IIAAKillOrReplaceEF>(SecondFunction)) {
return SecondFunction;
}
llvm::report_fatal_error(
"found unexpected edge function in 'IIAAKillOrReplaceEF'");
static EdgeFunction<l_t>
compose(EdgeFunctionRef<IIAAKillOrReplaceEF> /*This*/,
const EdgeFunction<l_t> /*SecondFunction*/) {
llvm::report_fatal_error("Implemented in 'extend'");
}

static EdgeFunction<l_t> join(EdgeFunctionRef<IIAAKillOrReplaceEF> This,
const EdgeFunction<l_t> &OtherFunction) {
/// XXX: Here, we underapproximate joins with EdgeIdentity
if (llvm::isa<EdgeIdentity<l_t>>(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<IIAAAddLabelsEF>(OtherFunction)) {
auto ADCache = OtherFunction.template getCacheOrNull<IIAAAddLabelsEF>();
assert(ADCache);
auto Union =
IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data);
return ADCache->createEdgeFunction(std::move(Union));
}
if (auto *KR = llvm::dyn_cast<IIAAKillOrReplaceEF>(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<l_t> join(EdgeFunctionRef<IIAAKillOrReplaceEF> /*This*/,
const EdgeFunction<l_t> & /*OtherFunction*/) {
llvm::report_fatal_error("Implemented in 'combine'");
}

bool operator==(const IIAAKillOrReplaceEF &Other) const noexcept {
Expand Down Expand Up @@ -1044,55 +1001,15 @@ class IDEInstInteractionAnalysisT
return IDEInstInteractionAnalysisT::joinImpl(Src, Data);
}

static EdgeFunction<l_t> compose(EdgeFunctionRef<IIAAAddLabelsEF> This,
const EdgeFunction<l_t> &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<IIAAAddLabelsEF>(SecondFunction)) {
auto Union =
IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data);
return Cache->createEdgeFunction(std::move(Union));
}
if (auto *KR = llvm::dyn_cast<IIAAKillOrReplaceEF>(SecondFunction)) {
return SecondFunction;
}
llvm::report_fatal_error(
"found unexpected edge function in 'IIAAAddLabelsEF'");
static EdgeFunction<l_t>
compose(EdgeFunctionRef<IIAAAddLabelsEF> /*This*/,
const EdgeFunction<l_t> & /*SecondFunction*/) {
llvm::report_fatal_error("Implemented in 'extend'");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this left for legacy reasons?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the EdgeFunction interface requires compose and join to be implemented. The default implementation of the semi-ring methods also assumes these functions to be implemented. We may want to make them optional at some point

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they not strictly required, disabling them would be a option, otherwise this could crash at some point.

}

static EdgeFunction<l_t> join(EdgeFunctionRef<IIAAAddLabelsEF> This,
const EdgeFunction<l_t> &OtherFunction) {
/// XXX: Here, we underapproximate joins with EdgeIdentity
if (llvm::isa<EdgeIdentity<l_t>>(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<IIAAAddLabelsEF>(OtherFunction)) {
auto Union =
IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data);
return Cache->createEdgeFunction(std::move(Union));
}
if (auto *KR = llvm::dyn_cast<IIAAKillOrReplaceEF>(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<l_t> join(EdgeFunctionRef<IIAAAddLabelsEF> /*This*/,
const EdgeFunction<l_t> & /*OtherFunction*/) {
llvm::report_fatal_error("Implemented in 'combine'");
}

bool operator==(const IIAAAddLabelsEF &Other) const noexcept {
Expand All @@ -1112,6 +1029,64 @@ class IDEInstInteractionAnalysisT
}
};

const auto &getData(const EdgeFunction<l_t> &EF) {
if (const auto *AddLabels = llvm::dyn_cast<IIAAAddLabelsEF>(EF)) {
return AddLabels->Data;
}
if (const auto *KillOrReplace = llvm::dyn_cast<IIAAKillOrReplaceEF>(EF)) {
return KillOrReplace->Replacement;
}
llvm::report_fatal_error(
"found unexpected first edge function in 'getData': " +
llvm::Twine(to_string(EF)));
}

EdgeFunction<l_t> extend(const EdgeFunction<l_t> &FirstFunction,
const EdgeFunction<l_t> &SecondFunction) override {
if (auto Default = defaultComposeOrNull(FirstFunction, SecondFunction)) {
return Default;
}

const auto &ThisData = getData(FirstFunction);

if (auto *AD = llvm::dyn_cast<IIAAAddLabelsEF>(SecondFunction)) {
auto Union = IDEInstInteractionAnalysisT::joinImpl(ThisData, AD->Data);
return llvm::isa<IIAAAddLabelsEF>(FirstFunction)
? IIAAAddLabelsEFCache.createEdgeFunction(std::move(Union))
: IIAAKillOrReplaceEFCache.createEdgeFunction(
std::move(Union));
}

llvm::report_fatal_error(
"found unexpected second edge function in 'extend'");
}

EdgeFunction<l_t> combine(const EdgeFunction<l_t> &FirstFunction,
const EdgeFunction<l_t> &OtherFunction) override {
/// XXX: Here, we underapproximate joins with EdgeIdentity
if (llvm::isa<EdgeIdentity<l_t>>(FirstFunction)) {
return OtherFunction;
}
if (llvm::isa<EdgeIdentity<l_t>>(OtherFunction) &&
!llvm::isa<AllTop<l_t>>(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<IIAAKillOrReplaceEF>(FirstFunction) &&
llvm::isa<IIAAKillOrReplaceEF>(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<d_t, l_t> &Res) {
Expand Down Expand Up @@ -1173,7 +1148,7 @@ class IDEInstInteractionAnalysisT
}
if (const auto *H = llvm::dyn_cast<llvm::CallBase>(I)) {
if (!H->isIndirectCall() && H->getCalledFunction() &&
this->ICF->isHeapAllocatingFunction(H->getCalledFunction())) {
psr::isHeapAllocatingFunction(H->getCalledFunction())) {
Variables.insert(H);
}
}
Expand Down
10 changes: 5 additions & 5 deletions include/phasar/Utils/BitVectorSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ template <typename T> class BitVectorSet {
}

[[nodiscard]] BitVectorSet<T> setUnion(const BitVectorSet<T> &Other) const {
size_t MaxSize = std::max(Bits.size(), Other.Bits.size());
BitVectorSet<T> Res;
Res.Bits.reserve(MaxSize);
Res.Bits = Bits;
Res.Bits |= Other.Bits;
const bool ThisSetIsSmaller = Bits.size() < Other.Bits.size();
BitVectorSet<T> Res = ThisSetIsSmaller ? Other : *this;
const BitVectorSet &Smaller = ThisSetIsSmaller ? *this : Other;

Res.Bits |= Smaller.Bits;
return Res;
}

Expand Down
Loading
Loading