Skip to content

Commit 7502ee5

Browse files
committed
add-backward-analysis-capability
1 parent 7b26a72 commit 7502ee5

File tree

1 file changed

+59
-49
lines changed

1 file changed

+59
-49
lines changed

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -499,13 +499,16 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
499499
// ========================================================================= //
500500
// Generic Dataflow Analysis
501501
// ========================================================================= //
502-
/// A generic, policy-based driver for forward dataflow analyses. It combines
502+
503+
enum class Direction { Forward, Backward };
504+
505+
/// A generic, policy-based driver for dataflow analyses. It combines
503506
/// the dataflow runner and the transferer logic into a single class hierarchy.
504507
///
505508
/// The derived class is expected to provide:
506509
/// - A `Lattice` type.
507510
/// - `StringRef getAnalysisName() const`
508-
/// - `Lattice getInitialState();` The initial state at the function entry.
511+
/// - `Lattice getInitialState();` The initial state of the analysis.
509512
/// - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
510513
/// - `Lattice transfer(Lattice, const FactType&);` Defines how a single
511514
/// lifetime-relevant `Fact` transforms the lattice state. Only overloads
@@ -514,18 +517,23 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
514517
/// \tparam Derived The CRTP derived class that implements the specific
515518
/// analysis.
516519
/// \tparam LatticeType The dataflow lattice used by the analysis.
520+
/// \tparam Dir The direction of the analysis (Forward or Backward).
517521
/// TODO: Maybe use the dataflow framework! The framework might need changes
518522
/// to support the current comparison done at block-entry.
519-
template <typename Derived, typename LatticeType> class DataflowAnalysis {
523+
template <typename Derived, typename LatticeType, Direction Dir>
524+
class DataflowAnalysis {
520525
public:
521526
using Lattice = LatticeType;
527+
using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
522528

523529
private:
524530
const CFG &Cfg;
525531
AnalysisDeclContext &AC;
526532

527-
llvm::DenseMap<const CFGBlock *, Lattice> BlockEntryStates;
528-
llvm::DenseMap<const CFGBlock *, Lattice> BlockExitStates;
533+
llvm::DenseMap<const CFGBlock *, Lattice> InStates;
534+
llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
535+
536+
static constexpr bool isForward() { return Dir == Direction::Forward; }
529537

530538
protected:
531539
FactManager &AllFacts;
@@ -539,75 +547,76 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
539547
Derived &D = static_cast<Derived &>(*this);
540548
llvm::TimeTraceScope Time(D.getAnalysisName());
541549

542-
ForwardDataflowWorklist Worklist(Cfg, AC);
543-
const CFGBlock *Entry = &Cfg.getEntry();
544-
BlockEntryStates[Entry] = D.getInitialState();
545-
Worklist.enqueueBlock(Entry);
546-
llvm::SmallBitVector Visited;
547-
Visited.resize(Cfg.getNumBlockIDs() + 1);
548-
549-
while (const CFGBlock *B = Worklist.dequeue()) {
550-
Lattice EntryState = getEntryState(B);
551-
Lattice ExitState = transferBlock(B, EntryState);
552-
BlockExitStates[B] = ExitState;
553-
Visited.set(B->getBlockID());
550+
using Worklist =
551+
std::conditional_t<Dir == Direction::Forward, ForwardDataflowWorklist,
552+
BackwardDataflowWorklist>;
553+
Worklist W(Cfg, AC);
554+
555+
const CFGBlock *Start = isForward() ? &Cfg.getEntry() : &Cfg.getExit();
556+
InStates[Start] = D.getInitialState();
557+
W.enqueueBlock(Start);
554558

555-
for (const CFGBlock *Successor : B->succs()) {
556-
Lattice OldSuccEntryState = getEntryState(Successor);
557-
Lattice NewSuccEntryState = D.join(OldSuccEntryState, ExitState);
559+
llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1);
558560

559-
// Enqueue the successor if its entry state has changed or if we have
561+
while (const CFGBlock *B = W.dequeue()) {
562+
Lattice StateIn = getInState(B);
563+
Lattice StateOut = transferBlock(B, StateIn);
564+
OutStates[B] = StateOut;
565+
Visited.set(B->getBlockID());
566+
for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
567+
Lattice OldInState = getInState(AdjacentB);
568+
Lattice NewInState = D.join(OldInState, StateOut);
569+
// Enqueue the adjacent block if its in-state has changed or if we have
560570
// never visited it.
561-
if (!Visited.test(Successor->getBlockID()) ||
562-
NewSuccEntryState != OldSuccEntryState) {
563-
BlockEntryStates[Successor] = NewSuccEntryState;
564-
Worklist.enqueueBlock(Successor);
571+
if (!Visited.test(AdjacentB->getBlockID()) ||
572+
NewInState != OldInState) {
573+
InStates[AdjacentB] = NewInState;
574+
W.enqueueBlock(AdjacentB);
565575
}
566576
}
567577
}
568578
}
569579

570-
Lattice getEntryState(const CFGBlock *B) const {
571-
return BlockEntryStates.lookup(B);
572-
}
580+
Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
573581

574-
Lattice getExitState(const CFGBlock *B) const {
575-
return BlockExitStates.lookup(B);
576-
}
582+
Lattice getOutStates(const CFGBlock *B) const { return OutStates.lookup(B); }
577583

578584
void dump() const {
579585
const Derived *D = static_cast<const Derived *>(this);
580586
llvm::dbgs() << "==========================================\n";
581587
llvm::dbgs() << D->getAnalysisName() << " results:\n";
582588
llvm::dbgs() << "==========================================\n";
583-
const CFGBlock &B = Cfg.getExit();
584-
getExitState(&B).dump(llvm::dbgs());
589+
const CFGBlock &B = isForward() ? Cfg.getExit() : Cfg.getEntry();
590+
getOutStates(&B).dump(llvm::dbgs());
585591
}
586592

587-
private:
588-
/// Computes the exit state of a block by applying all its facts sequentially
589-
/// to a given entry state.
593+
/// Computes the state at one end of a block by applying all its facts
594+
/// sequentially to a given state from the other end.
590595
/// TODO: We might need to store intermediate states per-fact in the block for
591596
/// later analysis.
592-
Lattice transferBlock(const CFGBlock *Block, Lattice EntryState) {
593-
Lattice BlockState = EntryState;
594-
for (const Fact *F : AllFacts.getFacts(Block)) {
595-
BlockState = transferFact(BlockState, F);
596-
}
597-
return BlockState;
597+
Lattice transferBlock(const CFGBlock *Block, Lattice State) {
598+
auto Facts = AllFacts.getFacts(Block);
599+
if constexpr (isForward())
600+
for (const Fact *F : Facts)
601+
State = transferFact(State, F);
602+
else
603+
for (const Fact *F : llvm::reverse(Facts))
604+
State = transferFact(State, F);
605+
return State;
598606
}
599607

600608
Lattice transferFact(Lattice In, const Fact *F) {
601-
Derived *d = static_cast<Derived *>(this);
609+
assert(F);
610+
Derived *D = static_cast<Derived *>(this);
602611
switch (F->getKind()) {
603612
case Fact::Kind::Issue:
604-
return d->transfer(In, *F->getAs<IssueFact>());
613+
return D->transfer(In, *F->getAs<IssueFact>());
605614
case Fact::Kind::Expire:
606-
return d->transfer(In, *F->getAs<ExpireFact>());
615+
return D->transfer(In, *F->getAs<ExpireFact>());
607616
case Fact::Kind::AssignOrigin:
608-
return d->transfer(In, *F->getAs<AssignOriginFact>());
617+
return D->transfer(In, *F->getAs<AssignOriginFact>());
609618
case Fact::Kind::ReturnOfOrigin:
610-
return d->transfer(In, *F->getAs<ReturnOfOriginFact>());
619+
return D->transfer(In, *F->getAs<ReturnOfOriginFact>());
611620
}
612621
llvm_unreachable("Unknown fact kind");
613622
}
@@ -715,7 +724,8 @@ struct LoanPropagationLattice {
715724

716725
/// The analysis that tracks which loans belong to which origins.
717726
class LoanPropagationAnalysis
718-
: public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
727+
: public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
728+
Direction::Forward> {
719729

720730
LifetimeFactory &Factory;
721731

@@ -724,7 +734,7 @@ class LoanPropagationAnalysis
724734
LifetimeFactory &Factory)
725735
: DataflowAnalysis(C, AC, F), Factory(Factory) {}
726736

727-
using DataflowAnalysis<LoanPropagationAnalysis, Lattice>::transfer;
737+
using Base::transfer;
728738

729739
StringRef getAnalysisName() const { return "LoanPropagation"; }
730740

0 commit comments

Comments
 (0)