Skip to content

Commit c217d0d

Browse files
committed
bring back comments
1 parent 927f92a commit c217d0d

File tree

2 files changed

+88
-118
lines changed

2 files changed

+88
-118
lines changed

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 73 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -503,13 +503,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
503503
///
504504
/// The derived class is expected to provide:
505505
/// - A `Lattice` type.
506-
/// - `Lattice getInitialState()`
507-
/// - `Lattice join(Lattice, Lattice)`
508-
/// - `Lattice transfer(Lattice, const FactType&)` for relevant fact types.
506+
/// - `const char *getAnalysisName() const`
507+
/// - `Lattice getInitialState();` The initial state at the function entry.
508+
/// - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
509+
/// - `Lattice transfer(Lattice, const FactType&);` Defines how a single
510+
/// lifetime-relevant `Fact` transforms the lattice state. Only overloads
511+
/// for facts relevant to the analysis need to be implemented.
509512
///
510513
/// \tparam Derived The CRTP derived class that implements the specific
511514
/// analysis.
512515
/// \tparam LatticeType The lattice type used by the analysis.
516+
/// TODO: Maybe use the dataflow framework! The framework might need changes
517+
/// to support the current comparison done at block-entry.
513518
template <typename Derived, typename LatticeType> class DataflowAnalysis {
514519
public:
515520
using Lattice = LatticeType;
@@ -530,10 +535,12 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
530535

531536
public:
532537
void run() {
533-
Derived &d = static_cast<Derived &>(*this);
538+
Derived &D = static_cast<Derived &>(*this);
539+
llvm::TimeTraceScope Time(D.getAnalysisName());
540+
534541
ForwardDataflowWorklist Worklist(Cfg, AC);
535542
const CFGBlock *Entry = &Cfg.getEntry();
536-
BlockEntryStates[Entry] = d.getInitialState();
543+
BlockEntryStates[Entry] = D.getInitialState();
537544
Worklist.enqueueBlock(Entry);
538545

539546
while (const CFGBlock *B = Worklist.dequeue()) {
@@ -545,9 +552,11 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
545552
auto SuccIt = BlockEntryStates.find(Successor);
546553
Lattice OldSuccEntryState = (SuccIt != BlockEntryStates.end())
547554
? SuccIt->second
548-
: d.getInitialState();
549-
Lattice NewSuccEntryState = d.join(OldSuccEntryState, ExitState);
550-
555+
: D.getInitialState();
556+
Lattice NewSuccEntryState = D.join(OldSuccEntryState, ExitState);
557+
// Enqueue the successor if its entry state has changed.
558+
// TODO(opt): Consider changing 'join' to report a change if !=
559+
// comparison is found expensive.
551560
if (SuccIt == BlockEntryStates.end() ||
552561
NewSuccEntryState != OldSuccEntryState) {
553562
BlockEntryStates[Successor] = NewSuccEntryState;
@@ -565,7 +574,20 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
565574
return BlockExitStates.lookup(B);
566575
}
567576

577+
void dump() const {
578+
const Derived *D = static_cast<const Derived *>(this);
579+
llvm::dbgs() << "==========================================\n";
580+
llvm::dbgs() << " " << D->getAnalysisName() << " results:\n";
581+
llvm::dbgs() << "==========================================\n";
582+
const CFGBlock &B = Cfg.getExit();
583+
getExitState(&B).dump(llvm::dbgs());
584+
}
585+
568586
private:
587+
/// Computes the exit state of a block by applying all its facts sequentially
588+
/// to a given entry state.
589+
/// TODO: We might need to store intermediate states per-fact in the block for
590+
/// later analysis.
569591
Lattice transferBlock(const CFGBlock *Block, Lattice EntryState) {
570592
Lattice BlockState = EntryState;
571593
for (const Fact *F : AllFacts.getFacts(Block)) {
@@ -618,24 +640,24 @@ struct LifetimeFactory {
618640
}
619641
};
620642

621-
/// LifetimeLattice represents the state of our analysis at a given program
622-
/// point. It is an immutable object, and all operations produce a new
643+
/// LoanPropagationLattice represents the state of our analysis at a given
644+
/// program point. It is an immutable object, and all operations produce a new
623645
/// instance rather than modifying the existing one.
624-
struct LifetimeLattice {
646+
struct LoanPropagationLattice {
625647
/// The map from an origin to the set of loans it contains.
626648
/// The lattice has a finite height: An origin's loan set is bounded by the
627649
/// total number of loans in the function.
628650
/// TODO(opt): To reduce the lattice size, propagate origins of declarations,
629651
/// not expressions, because expressions are not visible across blocks.
630652
OriginLoanMap Origins = OriginLoanMap(nullptr);
631653

632-
explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {}
633-
LifetimeLattice() = default;
654+
explicit LoanPropagationLattice(const OriginLoanMap &S) : Origins(S) {}
655+
LoanPropagationLattice() = default;
634656

635-
bool operator==(const LifetimeLattice &Other) const {
657+
bool operator==(const LoanPropagationLattice &Other) const {
636658
return Origins == Other.Origins;
637659
}
638-
bool operator!=(const LifetimeLattice &Other) const {
660+
bool operator!=(const LoanPropagationLattice &Other) const {
639661
return !(*this == Other);
640662
}
641663

@@ -653,7 +675,7 @@ struct LifetimeLattice {
653675
};
654676

655677
class LoanPropagationAnalysis
656-
: public DataflowAnalysis<LoanPropagationAnalysis, LifetimeLattice> {
678+
: public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
657679

658680
LifetimeFactory &Factory;
659681

@@ -662,49 +684,58 @@ class LoanPropagationAnalysis
662684
LifetimeFactory &Factory)
663685
: DataflowAnalysis(C, AC, F), Factory(Factory) {}
664686

665-
// Make the base class's transfer overloads visible.
666687
using DataflowAnalysis<LoanPropagationAnalysis, Lattice>::transfer;
667688

689+
const char *getAnalysisName() const { return "LoanPropagation"; }
690+
668691
Lattice getInitialState() { return Lattice{}; }
669692

670-
Lattice join(Lattice L1, Lattice L2) {
693+
/// Computes the union of two lattices by performing a key-wise join of
694+
/// their OriginLoanMaps.
695+
// TODO(opt): This key-wise join is a performance bottleneck. A more
696+
// efficient merge could be implemented using a Patricia Trie or HAMT
697+
// instead of the current AVL-tree-based ImmutableMap.
698+
// TODO(opt): Keep the state small by removing origins which become dead.
699+
Lattice join(Lattice A, Lattice B) {
671700
/// Merge the smaller map into the larger one ensuring we iterate over the
672701
/// smaller map.
673-
if (L1.Origins.getHeight() < L2.Origins.getHeight())
674-
std::swap(L1, L2);
702+
if (A.Origins.getHeight() < B.Origins.getHeight())
703+
std::swap(A, B);
675704

676-
OriginLoanMap JoinedState = L1.Origins;
705+
OriginLoanMap JoinedState = A.Origins;
677706
// For each origin in the other map, union its loan set with ours.
678-
for (const auto &Entry : L2.Origins) {
707+
for (const auto &Entry : B.Origins) {
679708
OriginID OID = Entry.first;
680709
LoanSet OtherLoanSet = Entry.second;
681710
JoinedState = Factory.OriginMapFactory.add(
682-
JoinedState, OID, join(getLoans(L1, OID), OtherLoanSet));
711+
JoinedState, OID, join(getLoans(A, OID), OtherLoanSet));
683712
}
684713
return Lattice(JoinedState);
685714
}
686715

687-
LoanSet join(LoanSet S1, LoanSet S2) {
688-
if (S1.getHeight() < S2.getHeight())
689-
std::swap(S1, S2);
690-
for (LoanID L : S2)
691-
S1 = Factory.LoanSetFact.add(S1, L);
692-
return S1;
716+
LoanSet join(LoanSet A, LoanSet B) {
717+
if (A.getHeight() < B.getHeight())
718+
std::swap(A, B);
719+
for (LoanID L : B)
720+
A = Factory.LoanSetFact.add(A, L);
721+
return A;
693722
}
694723

695-
// Overloads for specific fact types this transferer cares about.
724+
/// A new loan is issued to the origin. Old loans are erased.
696725
Lattice transfer(Lattice In, const IssueFact &F) {
697726
OriginID OID = F.getOriginID();
698727
LoanID LID = F.getLoanID();
699-
return LifetimeLattice(Factory.OriginMapFactory.add(
728+
return LoanPropagationLattice(Factory.OriginMapFactory.add(
700729
In.Origins, OID, Factory.createLoanSet(LID)));
701730
}
702731

732+
/// The destination origin's loan set is replaced by the source's.
733+
/// This implicitly "resets" the old loans of the destination.
703734
Lattice transfer(Lattice In, const AssignOriginFact &F) {
704735
OriginID DestOID = F.getDestOriginID();
705736
OriginID SrcOID = F.getSrcOriginID();
706737
LoanSet SrcLoans = getLoans(In, SrcOID);
707-
return LifetimeLattice(
738+
return LoanPropagationLattice(
708739
Factory.OriginMapFactory.add(In.Origins, DestOID, SrcLoans));
709740
}
710741

@@ -715,65 +746,6 @@ class LoanPropagationAnalysis
715746
return Factory.LoanSetFact.getEmptySet();
716747
}
717748
};
718-
719-
// ========================================================================= //
720-
// Expired Loans Analysis
721-
// ========================================================================= //
722-
723-
/// The lattice for tracking expired loans. It is a set of loan IDs.
724-
struct ExpiredLattice {
725-
LoanSet Expired;
726-
727-
ExpiredLattice() : Expired(nullptr) {};
728-
explicit ExpiredLattice(LoanSet S) : Expired(S) {}
729-
730-
bool operator==(const ExpiredLattice &Other) const {
731-
return Expired == Other.Expired;
732-
}
733-
bool operator!=(const ExpiredLattice &Other) const {
734-
return !(*this == Other);
735-
}
736-
737-
void dump(llvm::raw_ostream &OS) const {
738-
OS << "ExpiredLattice State:\n";
739-
if (Expired.isEmpty())
740-
OS << " <empty>\n";
741-
for (const LoanID &LID : Expired)
742-
OS << " Loan " << LID << " is expired\n";
743-
}
744-
};
745-
746-
/// Transfer function for the expired loans analysis.
747-
class ExpiredLoansAnalysis
748-
: public DataflowAnalysis<ExpiredLoansAnalysis, ExpiredLattice> {
749-
750-
LoanSet::Factory &SetFactory;
751-
752-
public:
753-
ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
754-
LoanSet::Factory &SF)
755-
: DataflowAnalysis(C, AC, F), SetFactory(SF) {}
756-
757-
using DataflowAnalysis<ExpiredLoansAnalysis, Lattice>::transfer;
758-
759-
Lattice getInitialState() { return Lattice(SetFactory.getEmptySet()); }
760-
761-
Lattice join(Lattice L1, Lattice L2) const {
762-
LoanSet JoinedSet = L1.Expired;
763-
for (LoanID LID : L2.Expired)
764-
JoinedSet = SetFactory.add(JoinedSet, LID);
765-
return Lattice(JoinedSet);
766-
}
767-
768-
// Overloads for specific fact types this transferer cares about.
769-
Lattice transfer(Lattice In, const ExpireFact &F) {
770-
return Lattice(SetFactory.add(In.Expired, F.getLoanID()));
771-
}
772-
773-
Lattice transfer(Lattice In, const IssueFact &F) {
774-
return Lattice(SetFactory.remove(In.Expired, F.getLoanID()));
775-
}
776-
};
777749
} // anonymous namespace
778750

779751
void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
@@ -786,20 +758,18 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
786758
FactGen.run();
787759
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
788760

789-
// Run Loan Propagation Analysis
761+
/// TODO(opt): Consider optimizing individual blocks before running the
762+
/// dataflow analysis.
763+
/// 1. Expression Origins: These are assigned once and read at most once,
764+
/// forming simple chains. These chains can be compressed into a single
765+
/// assignment.
766+
/// 2. Block-Local Loans: Origins of expressions are never read by other
767+
/// blocks; only Decls are visible. Therefore, loans in a block that
768+
/// never reach an Origin associated with a Decl can be safely dropped by
769+
/// the analysis.
790770
LifetimeFactory LifetimeFact;
791771
LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, LifetimeFact);
792772
LoanPropagation.run();
793-
DEBUG_WITH_TYPE(
794-
"LifetimeDataflow",
795-
LoanPropagation.getExitState(&Cfg.getExit()).dump(llvm::dbgs()));
796-
797-
// Run Expired Loans Analysis
798-
ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr,
799-
LifetimeFact.LoanSetFact);
800-
ExpiredAnalysis.run();
801-
DEBUG_WITH_TYPE(
802-
"ExpiredLoans",
803-
ExpiredAnalysis.getExitState(&Cfg.getExit()).dump(llvm::dbgs()));
773+
DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump());
804774
}
805775
} // namespace clang

0 commit comments

Comments
 (0)