Skip to content

[LifetimeSafety] Add per-program-point lattice tracking #149199

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
39 changes: 31 additions & 8 deletions clang/lib/Analysis/LifetimeSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {

enum class Direction { Forward, Backward };

/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
/// `Fact`. identified by a lifetime-related event (`Fact`).
///
/// A `ProgramPoint` has "after" semantics: it represents the location
/// immediately after its corresponding `Fact`.
using ProgramPoint = const Fact *;

/// A generic, policy-based driver for dataflow analyses. It combines
/// the dataflow runner and the transferer logic into a single class hierarchy.
///
Expand All @@ -524,14 +531,20 @@ template <typename Derived, typename LatticeType, Direction Dir>
class DataflowAnalysis {
public:
using Lattice = LatticeType;
using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
using Base = DataflowAnalysis<Derived, Lattice, Dir>;

private:
const CFG &Cfg;
AnalysisDeclContext &AC;

/// The dataflow state before a basic block is processed.
llvm::DenseMap<const CFGBlock *, Lattice> InStates;
/// The dataflow state after a basic block is processed.
llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
/// The dataflow state at a Program Point.
/// In a forward analysis, this is the state after the Fact at that point has
/// been applied, while in a backward analysis, it is the state before.
llvm::DenseMap<ProgramPoint, Lattice> PerPointStates;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think all of the analyses need PerPointStates? E.g., what about the ExpiredLoansAnalysis? I wonder if we should have a boolean policy here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah never mind. Now I remember you want to keep these states instead of replaying the analysis for the blocks.


static constexpr bool isForward() { return Dir == Direction::Forward; }

Expand Down Expand Up @@ -577,6 +590,8 @@ class DataflowAnalysis {
}
}

Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); }

Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }

Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
Expand All @@ -590,18 +605,23 @@ class DataflowAnalysis {
getOutState(&B).dump(llvm::dbgs());
}

private:
/// Computes the state at one end of a block by applying all its facts
/// sequentially to a given state from the other end.
/// TODO: We might need to store intermediate states per-fact in the block for
/// later analysis.
Lattice transferBlock(const CFGBlock *Block, Lattice State) {
auto Facts = AllFacts.getFacts(Block);
if constexpr (isForward())
for (const Fact *F : Facts)
if constexpr (isForward()) {
for (const Fact *F : Facts) {
State = transferFact(State, F);
else
for (const Fact *F : llvm::reverse(Facts))
PerPointStates[F] = State;
}
} else {
for (const Fact *F : llvm::reverse(Facts)) {
// In backward analysis, capture the state before applying the fact.
PerPointStates[F] = State;
State = transferFact(State, F);
}
}
return State;
}

Expand Down Expand Up @@ -769,6 +789,10 @@ class LoanPropagationAnalysis
Factory.OriginMapFactory.add(In.Origins, DestOID, SrcLoans));
}

LoanSet getLoans(OriginID OID, ProgramPoint P) {
return getLoans(getState(P), OID);
}

private:
LoanSet getLoans(Lattice L, OriginID OID) {
if (auto *Loans = L.Origins.lookup(OID))
Expand All @@ -779,7 +803,6 @@ class LoanPropagationAnalysis

// ========================================================================= //
// TODO:
// - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)`
// - Modify loan expiry analysis to answer `bool isExpired(Loan L, Point P)`
// - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
// - Using the above three to perform the final error reporting.
Expand Down