24
24
#include " llvm/Support/TimeProfiler.h"
25
25
#include < cstdint>
26
26
27
- namespace clang ::lifetimes {
28
- namespace internal {
27
+ namespace clang {
29
28
namespace {
30
- template <typename Tag>
31
- inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
32
- return OS << ID.Value ;
33
- }
34
- } // namespace
35
29
36
30
// / Represents the storage location being borrowed, e.g., a specific stack
37
31
// / variable.
@@ -42,6 +36,32 @@ struct AccessPath {
42
36
AccessPath (const clang::ValueDecl *D) : D(D) {}
43
37
};
44
38
39
+ // / A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
40
+ // / Used for giving ID to loans and origins.
41
+ template <typename Tag> struct ID {
42
+ uint32_t Value = 0 ;
43
+
44
+ bool operator ==(const ID<Tag> &Other) const { return Value == Other.Value ; }
45
+ bool operator !=(const ID<Tag> &Other) const { return !(*this == Other); }
46
+ bool operator <(const ID<Tag> &Other) const { return Value < Other.Value ; }
47
+ ID<Tag> operator ++(int ) {
48
+ ID<Tag> Tmp = *this ;
49
+ ++Value;
50
+ return Tmp;
51
+ }
52
+ void Profile (llvm::FoldingSetNodeID &IDBuilder) const {
53
+ IDBuilder.AddInteger (Value);
54
+ }
55
+ };
56
+
57
+ template <typename Tag>
58
+ inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
59
+ return OS << ID.Value ;
60
+ }
61
+
62
+ using LoanID = ID<struct LoanTag >;
63
+ using OriginID = ID<struct OriginTag >;
64
+
45
65
// / Information about a single borrow, or "Loan". A loan is created when a
46
66
// / reference or pointer is created.
47
67
struct Loan {
@@ -203,9 +223,7 @@ class Fact {
203
223
// / An origin is propagated from a source to a destination (e.g., p = q).
204
224
AssignOrigin,
205
225
// / An origin escapes the function by flowing into the return value.
206
- ReturnOfOrigin,
207
- // / A marker for a specific point in the code, for testing.
208
- TestPoint,
226
+ ReturnOfOrigin
209
227
};
210
228
211
229
private:
@@ -292,24 +310,6 @@ class ReturnOfOriginFact : public Fact {
292
310
}
293
311
};
294
312
295
- // / A dummy-fact used to mark a specific point in the code for testing.
296
- // / It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
297
- class TestPointFact : public Fact {
298
- StringRef Annotation;
299
-
300
- public:
301
- static bool classof (const Fact *F) { return F->getKind () == Kind::TestPoint; }
302
-
303
- explicit TestPointFact (StringRef Annotation)
304
- : Fact(Kind::TestPoint), Annotation(Annotation) {}
305
-
306
- StringRef getAnnotation () const { return Annotation; }
307
-
308
- void dump (llvm::raw_ostream &OS) const override {
309
- OS << " TestPoint (Annotation: \" " << getAnnotation () << " \" )\n " ;
310
- }
311
- };
312
-
313
313
class FactManager {
314
314
public:
315
315
llvm::ArrayRef<const Fact *> getFacts (const CFGBlock *B) const {
@@ -363,7 +363,6 @@ class FactManager {
363
363
};
364
364
365
365
class FactGenerator : public ConstStmtVisitor <FactGenerator> {
366
- using Base = ConstStmtVisitor<FactGenerator>;
367
366
368
367
public:
369
368
FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
@@ -459,15 +458,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
459
458
}
460
459
}
461
460
462
- void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
463
- // Check if this is a test point marker. If so, we are done with this
464
- // expression.
465
- if (VisitTestPoint (FCE))
466
- return ;
467
- // Visit as normal otherwise.
468
- Base::VisitCXXFunctionalCastExpr (FCE);
469
- }
470
-
471
461
private:
472
462
// Check if a type has an origin.
473
463
bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
@@ -501,27 +491,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
501
491
}
502
492
}
503
493
504
- // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
505
- // / If so, creates a `TestPointFact` and returns true.
506
- bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
507
- if (!FCE->getType ()->isVoidType ())
508
- return false ;
509
-
510
- const auto *SubExpr = FCE->getSubExpr ()->IgnoreParenImpCasts ();
511
- if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
512
- llvm::StringRef LiteralValue = SL->getString ();
513
- const std::string Prefix = " __lifetime_test_point_" ;
514
-
515
- if (LiteralValue.starts_with (Prefix)) {
516
- StringRef Annotation = LiteralValue.drop_front (Prefix.length ());
517
- CurrentBlockFacts.push_back (
518
- FactMgr.createFact <TestPointFact>(Annotation));
519
- return true ;
520
- }
521
- }
522
- return false ;
523
- }
524
-
525
494
FactManager &FactMgr;
526
495
AnalysisDeclContext &AC;
527
496
llvm::SmallVector<Fact *> CurrentBlockFacts;
@@ -668,8 +637,6 @@ class DataflowAnalysis {
668
637
return D->transfer (In, *F->getAs <AssignOriginFact>());
669
638
case Fact::Kind::ReturnOfOrigin:
670
639
return D->transfer (In, *F->getAs <ReturnOfOriginFact>());
671
- case Fact::Kind::TestPoint:
672
- return D->transfer (In, *F->getAs <TestPointFact>());
673
640
}
674
641
llvm_unreachable (" Unknown fact kind" );
675
642
}
@@ -679,16 +646,14 @@ class DataflowAnalysis {
679
646
Lattice transfer (Lattice In, const ExpireFact &) { return In; }
680
647
Lattice transfer (Lattice In, const AssignOriginFact &) { return In; }
681
648
Lattice transfer (Lattice In, const ReturnOfOriginFact &) { return In; }
682
- Lattice transfer (Lattice In, const TestPointFact &) { return In; }
683
649
};
684
650
685
651
namespace utils {
686
652
687
653
// / Computes the union of two ImmutableSets.
688
654
template <typename T>
689
- static llvm::ImmutableSet<T> join (llvm::ImmutableSet<T> A,
690
- llvm::ImmutableSet<T> B,
691
- typename llvm::ImmutableSet<T>::Factory &F) {
655
+ llvm::ImmutableSet<T> join (llvm::ImmutableSet<T> A, llvm::ImmutableSet<T> B,
656
+ typename llvm::ImmutableSet<T>::Factory &F) {
692
657
if (A.getHeight () < B.getHeight ())
693
658
std::swap (A, B);
694
659
for (const T &E : B)
@@ -701,7 +666,7 @@ static llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A,
701
666
// efficient merge could be implemented using a Patricia Trie or HAMT
702
667
// instead of the current AVL-tree-based ImmutableMap.
703
668
template <typename K, typename V, typename Joiner>
704
- static llvm::ImmutableMap<K, V>
669
+ llvm::ImmutableMap<K, V>
705
670
join (llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
706
671
typename llvm::ImmutableMap<K, V>::Factory &F, Joiner joinValues) {
707
672
if (A.getHeight () < B.getHeight ())
@@ -725,6 +690,10 @@ join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
725
690
// Loan Propagation Analysis
726
691
// ========================================================================= //
727
692
693
+ // Using LLVM's immutable collections is efficient for dataflow analysis
694
+ // as it avoids deep copies during state transitions.
695
+ // TODO(opt): Consider using a bitset to represent the set of loans.
696
+ using LoanSet = llvm::ImmutableSet<LoanID>;
728
697
using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
729
698
730
699
// / An object to hold the factories for immutable collections, ensuring
@@ -838,28 +807,17 @@ class LoanPropagationAnalysis
838
807
// - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
839
808
// - Using the above three to perform the final error reporting.
840
809
// ========================================================================= //
810
+ } // anonymous namespace
841
811
842
- // ========================================================================= //
843
- // LifetimeSafetyAnalysis Class Implementation
844
- // ========================================================================= //
845
-
846
- // We need this here for unique_ptr with forward declared class.
847
- LifetimeSafetyAnalysis::~LifetimeSafetyAnalysis () = default ;
848
-
849
- LifetimeSafetyAnalysis::LifetimeSafetyAnalysis (AnalysisDeclContext &AC)
850
- : AC(AC), Factory(std::make_unique<LifetimeFactory>()),
851
- FactMgr (std::make_unique<FactManager>()) {}
852
-
853
- void LifetimeSafetyAnalysis::run () {
812
+ void runLifetimeSafetyAnalysis (const DeclContext &DC, const CFG &Cfg,
813
+ AnalysisDeclContext &AC) {
854
814
llvm::TimeTraceScope TimeProfile (" LifetimeSafetyAnalysis" );
855
-
856
- const CFG &Cfg = *AC.getCFG ();
857
815
DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
858
816
/* ShowColors=*/ true ));
859
-
860
- FactGenerator FactGen (* FactMgr, AC);
817
+ FactManager FactMgr;
818
+ FactGenerator FactGen (FactMgr, AC);
861
819
FactGen.run ();
862
- DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr-> dump (Cfg, AC));
820
+ DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr. dump (Cfg, AC));
863
821
864
822
// / TODO(opt): Consider optimizing individual blocks before running the
865
823
// / dataflow analysis.
@@ -870,56 +828,9 @@ void LifetimeSafetyAnalysis::run() {
870
828
// / blocks; only Decls are visible. Therefore, loans in a block that
871
829
// / never reach an Origin associated with a Decl can be safely dropped by
872
830
// / the analysis.
873
- LoanPropagation =
874
- std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
875
- LoanPropagation->run ();
876
- }
877
-
878
- LoanSet LifetimeSafetyAnalysis::getLoansAtPoint (OriginID OID,
879
- ProgramPoint PP) const {
880
- assert (LoanPropagation && " Analysis has not been run." );
881
- return LoanPropagation->getLoans (OID, PP);
882
- }
883
-
884
- std::optional<OriginID>
885
- LifetimeSafetyAnalysis::getOriginIDForDecl (const ValueDecl *D) const {
886
- assert (FactMgr && " FactManager not initialized" );
887
- // This assumes the OriginManager's `get` can find an existing origin.
888
- // We might need a `find` method on OriginManager to avoid `getOrCreate` logic
889
- // in a const-query context if that becomes an issue.
890
- return FactMgr->getOriginMgr ().get (*D);
891
- }
892
-
893
- std::vector<LoanID>
894
- LifetimeSafetyAnalysis::getLoanIDForVar (const VarDecl *VD) const {
895
- assert (FactMgr && " FactManager not initialized" );
896
- std::vector<LoanID> Result;
897
- for (const Loan &L : FactMgr->getLoanMgr ().getLoans ())
898
- if (L.Path .D == VD)
899
- Result.push_back (L.ID );
900
- return Result;
901
- }
902
-
903
- llvm::StringMap<ProgramPoint> LifetimeSafetyAnalysis::getTestPoints () const {
904
- assert (FactMgr && " FactManager not initialized" );
905
- llvm::StringMap<ProgramPoint> AnnotationToPointMap;
906
- for (const CFGBlock *Block : *AC.getCFG ()) {
907
- for (const Fact *F : FactMgr->getFacts (Block)) {
908
- if (const auto *TPF = F->getAs <TestPointFact>()) {
909
- StringRef PointName = TPF->getAnnotation ();
910
- assert (AnnotationToPointMap.find (PointName) ==
911
- AnnotationToPointMap.end () &&
912
- " more than one test points with the same name" );
913
- AnnotationToPointMap[PointName] = F;
914
- }
915
- }
916
- }
917
- return AnnotationToPointMap;
918
- }
919
- } // namespace internal
920
-
921
- void runLifetimeSafetyAnalysis (AnalysisDeclContext &AC) {
922
- internal::LifetimeSafetyAnalysis Analysis (AC);
923
- Analysis.run ();
831
+ LifetimeFactory Factory;
832
+ LoanPropagationAnalysis LoanPropagation (Cfg, AC, FactMgr, Factory);
833
+ LoanPropagation.run ();
834
+ DEBUG_WITH_TYPE (" LifetimeLoanPropagation" , LoanPropagation.dump ());
924
835
}
925
- } // namespace clang::lifetimes
836
+ } // namespace clang
0 commit comments