Skip to content

Commit b109b6a

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

File tree

1 file changed

+59
-51
lines changed

1 file changed

+59
-51
lines changed

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 59 additions & 51 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,21 @@ 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.
517-
/// TODO: Maybe use the dataflow framework! The framework might need changes
518-
/// to support the current comparison done at block-entry.
519-
template <typename Derived, typename LatticeType> class DataflowAnalysis {
520+
/// \tparam Dir The direction of the analysis (Forward or Backward).
521+
template <typename Derived, typename LatticeType, Direction Dir>
522+
class DataflowAnalysis {
520523
public:
521524
using Lattice = LatticeType;
525+
using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
522526

523527
private:
524528
const CFG &Cfg;
525529
AnalysisDeclContext &AC;
526530

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

530536
protected:
531537
FactManager &AllFacts;
@@ -539,75 +545,76 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
539545
Derived &D = static_cast<Derived &>(*this);
540546
llvm::TimeTraceScope Time(D.getAnalysisName());
541547

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());
548+
using Worklist =
549+
std::conditional_t<Dir == Direction::Forward, ForwardDataflowWorklist,
550+
BackwardDataflowWorklist>;
551+
Worklist W(Cfg, AC);
552+
553+
const CFGBlock *Start = isForward() ? &Cfg.getEntry() : &Cfg.getExit();
554+
InStates[Start] = D.getInitialState();
555+
W.enqueueBlock(Start);
554556

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

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

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

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

578582
void dump() const {
579583
const Derived *D = static_cast<const Derived *>(this);
580584
llvm::dbgs() << "==========================================\n";
581585
llvm::dbgs() << D->getAnalysisName() << " results:\n";
582586
llvm::dbgs() << "==========================================\n";
583-
const CFGBlock &B = Cfg.getExit();
584-
getExitState(&B).dump(llvm::dbgs());
587+
const CFGBlock &B = isForward() ? Cfg.getExit() : Cfg.getEntry();
588+
getOutStates(&B).dump(llvm::dbgs());
585589
}
586590

587-
private:
588-
/// Computes the exit state of a block by applying all its facts sequentially
589-
/// to a given entry state.
591+
/// Computes the state at one end of a block by applying all its facts
592+
/// sequentially to a given state from the other end.
590593
/// TODO: We might need to store intermediate states per-fact in the block for
591594
/// 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;
595+
Lattice transferBlock(const CFGBlock *Block, Lattice State) {
596+
auto Facts = AllFacts.getFacts(Block);
597+
if constexpr (isForward())
598+
for (const Fact *F : Facts)
599+
State = transferFact(State, F);
600+
else
601+
for (const Fact *F : llvm::reverse(Facts))
602+
State = transferFact(State, F);
603+
return State;
598604
}
599605

600606
Lattice transferFact(Lattice In, const Fact *F) {
601-
Derived *d = static_cast<Derived *>(this);
607+
assert(F);
608+
Derived *D = static_cast<Derived *>(this);
602609
switch (F->getKind()) {
603610
case Fact::Kind::Issue:
604-
return d->transfer(In, *F->getAs<IssueFact>());
611+
return D->transfer(In, *F->getAs<IssueFact>());
605612
case Fact::Kind::Expire:
606-
return d->transfer(In, *F->getAs<ExpireFact>());
613+
return D->transfer(In, *F->getAs<ExpireFact>());
607614
case Fact::Kind::AssignOrigin:
608-
return d->transfer(In, *F->getAs<AssignOriginFact>());
615+
return D->transfer(In, *F->getAs<AssignOriginFact>());
609616
case Fact::Kind::ReturnOfOrigin:
610-
return d->transfer(In, *F->getAs<ReturnOfOriginFact>());
617+
return D->transfer(In, *F->getAs<ReturnOfOriginFact>());
611618
}
612619
llvm_unreachable("Unknown fact kind");
613620
}
@@ -715,7 +722,8 @@ struct LoanPropagationLattice {
715722

716723
/// The analysis that tracks which loans belong to which origins.
717724
class LoanPropagationAnalysis
718-
: public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
725+
: public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
726+
Direction::Forward> {
719727

720728
LifetimeFactory &Factory;
721729

@@ -724,7 +732,7 @@ class LoanPropagationAnalysis
724732
LifetimeFactory &Factory)
725733
: DataflowAnalysis(C, AC, F), Factory(Factory) {}
726734

727-
using DataflowAnalysis<LoanPropagationAnalysis, Lattice>::transfer;
735+
using Base::transfer;
728736

729737
StringRef getAnalysisName() const { return "LoanPropagation"; }
730738

0 commit comments

Comments
 (0)