2525
2626using namespace swift ;
2727
28- static bool isClosureWithBody (AbstractClosureExpr *ACE) {
28+ // / Check if a closure has a body.
29+ static bool doesClosureHaveBody (AbstractClosureExpr *ACE) {
2930 if (auto *CE = dyn_cast<ClosureExpr>(ACE))
3031 return CE->getBody ();
3132 if (auto *autoCE = dyn_cast<AutoClosureExpr>(ACE))
3233 return autoCE->getBody ();
3334 return false ;
3435}
3536
37+ // / Check whether a root AST node is unmapped, i.e not profiled.
3638static bool isUnmapped (ASTNode N) {
3739 if (auto *E = N.dyn_cast <Expr *>()) {
3840 auto *CE = dyn_cast<AbstractClosureExpr>(E);
39- return !CE || (!isa<AutoClosureExpr>(CE) && CE->isImplicit ()) ||
40- !isClosureWithBody (CE);
41+
42+ // Only map closure expressions with bodies.
43+ if (!CE || !doesClosureHaveBody (CE))
44+ return true ;
45+
46+ // Don't map implicit closures, unless they're autoclosures.
47+ if (!isa<AutoClosureExpr>(CE) && CE->isImplicit ())
48+ return true ;
49+
50+ return false ;
4151 }
4252
4353 auto *D = N.get <Decl *>();
4454 if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
55+ // Don't map functions without bodies.
4556 if (!AFD->getBody ())
4657 return true ;
4758
59+ // Map all *structors, even if they are implicit.
60+ if (isa<ConstructorDecl>(D) || isa<DestructorDecl>(D))
61+ return false ;
62+
63+ // Map implicit getters.
4864 if (auto *accessor = dyn_cast<AccessorDecl>(AFD))
4965 if (accessor->isImplicit () && accessor->isGetter ())
5066 return false ;
5167 }
5268
53- if (isa<ConstructorDecl>(D) || isa<DestructorDecl>(D))
54- return false ;
55-
56- return D->isImplicit () || isa<EnumCaseDecl>(D);
57- }
58-
59- // / A simple heuristic to determine whether \p E contains a definition of a
60- // / closure. This is not complete, but it suffices to cheaply filter away some
61- // / redundant coverage mappings.
62- static bool containsClosure (Expr *E) {
63- Expr *candidateExpr = E;
64- if (auto *ce = dyn_cast<CallExpr>(E))
65- candidateExpr = ce->getDirectCallee ();
66- return dyn_cast_or_null<AbstractClosureExpr>(candidateExpr);
67- }
68-
69- // / Walk the non-static initializers in \p PBD.
70- static void walkPatternForProfiling (PatternBindingDecl *PBD, ASTWalker &Walker,
71- bool AllowClosures = true ) {
72- if (PBD && !PBD->isStatic ())
73- for (auto E : PBD->getPatternList ())
74- if (E.getInit ())
75- if (AllowClosures || !containsClosure (E.getInit ()))
76- E.getInit ()->walk (Walker);
77- }
78-
79- // / Walk the AST of \c Root and related nodes that are relevant for profiling.
80- static void walkFunctionForProfiling (AbstractFunctionDecl *Root,
81- ASTWalker &Walker) {
82- Root->walk (Walker);
83-
84- // We treat non-closure member initializers as part of the constructor for
85- // profiling.
86- if (auto *CD = dyn_cast<ConstructorDecl>(Root)) {
87- auto *NominalType =
88- CD->getDeclContext ()->getAsNominalTypeOrNominalTypeExtensionContext ();
89- for (auto *Member : NominalType->getMembers ()) {
90- // Find pattern binding declarations that have initializers.
91- if (auto *PBD = dyn_cast<PatternBindingDecl>(Member))
92- walkPatternForProfiling (PBD, Walker, /* AllowClosures=*/ false );
93- }
94- }
95- }
69+ // Skip any remaining implicit, or otherwise unsupported decls.
70+ if (D->isImplicit () || isa<EnumCaseDecl>(D))
71+ return true ;
9672
97- // / Walk \p D for profiling.
98- static void walkForProfiling (ASTNode N, ASTWalker &Walker) {
99- if (auto *D = N.dyn_cast <Decl *>()) {
100- if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
101- walkFunctionForProfiling (AFD, Walker);
102- else if (auto *PBD = dyn_cast<PatternBindingDecl>(D))
103- walkPatternForProfiling (PBD, Walker);
104- else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
105- TLCD->walk (Walker);
106- } else if (auto *E = N.dyn_cast <Expr *>()) {
107- cast<AbstractClosureExpr>(E)->walk (Walker);
108- }
73+ return false ;
10974}
11075
11176namespace swift {
@@ -122,27 +87,43 @@ static bool hasASTBeenTypeChecked(ASTNode N) {
12287 return !SF || SF->ASTStage >= SourceFile::TypeChecked;
12388}
12489
90+ // / Check whether a mapped AST node requires a new profiler.
91+ static bool canCreateProfilerForAST (ASTNode N) {
92+ assert (hasASTBeenTypeChecked (N) && " Cannot use this AST for profiling" );
93+
94+ if (auto *D = N.dyn_cast <Decl *>()) {
95+ // Any mapped function may be profiled. There's an exception for
96+ // constructors because all of the constructors for a type share a single
97+ // profiler.
98+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
99+ return !isa<ConstructorDecl>(AFD);
100+
101+ if (isa<TopLevelCodeDecl>(D))
102+ return true ;
103+
104+ if (isa<NominalTypeDecl>(D))
105+ return true ;
106+ } else {
107+ auto *E = N.get <Expr *>();
108+ if (isa<AbstractClosureExpr>(E))
109+ return true ;
110+ }
111+ return false ;
112+ }
113+
125114SILProfiler *SILProfiler::create (SILModule &M, ForDefinition_t forDefinition,
126115 ASTNode N) {
127116 // Avoid generating profiling state for declarations.
128117 if (!forDefinition)
129118 return nullptr ;
130119
131- assert (hasASTBeenTypeChecked (N) && " Cannot use this AST for code coverage" );
132-
133- if (auto *D = N.dyn_cast <Decl *>()) {
134- assert (isa<AbstractFunctionDecl>(D) ||
135- isa<TopLevelCodeDecl>(D) && " Cannot create profiler" );
136- } else if (auto *E = N.dyn_cast <Expr *>()) {
137- assert (isa<AbstractClosureExpr>(E) && " Cannot create profiler" );
138- } else {
139- llvm_unreachable (" Invalid AST node for profiling" );
140- }
141-
142120 const auto &Opts = M.getOptions ();
143121 if (!doesASTRequireProfiling (M, N) && Opts.UseProfile .empty ())
144122 return nullptr ;
145123
124+ if (!canCreateProfilerForAST (N))
125+ llvm_unreachable (" Invalid AST node for profiling" );
126+
146127 auto *Buf = M.allocate <SILProfiler>(1 );
147128 auto *SP = ::new (Buf) SILProfiler (M, N, Opts.EmitProfileCoverageMapping );
148129 SP->assignRegionCounters ();
@@ -151,6 +132,15 @@ SILProfiler *SILProfiler::create(SILModule &M, ForDefinition_t forDefinition,
151132
152133namespace {
153134
135+ // / Walk the non-static initializers in \p PBD.
136+ static void walkPatternForProfiling (PatternBindingDecl *PBD,
137+ ASTWalker &Walker) {
138+ if (PBD && !PBD->isStatic ())
139+ for (auto E : PBD->getPatternList ())
140+ if (E.getInit ())
141+ E.getInit ()->walk (Walker);
142+ }
143+
154144// / Special logic for handling closure visitation.
155145// /
156146// / To prevent a closure from being mapped twice, avoid recursively walking
@@ -169,25 +159,35 @@ std::pair<bool, Expr *> visitClosureExpr(ASTWalker &Walker,
169159// / An ASTWalker that maps ASTNodes to profiling counters.
170160struct MapRegionCounters : public ASTWalker {
171161 // / The next counter value to assign.
172- unsigned NextCounter;
162+ unsigned NextCounter = 0 ;
173163
174164 // / The map of statements to counters.
175165 llvm::DenseMap<ASTNode, unsigned > &CounterMap;
176166
167+ // / A flag indicating whether we're walking a nominal type.
168+ bool WithinNominalType = false ;
169+
177170 MapRegionCounters (llvm::DenseMap<ASTNode, unsigned > &CounterMap)
178- : NextCounter( 0 ), CounterMap(CounterMap) {}
171+ : CounterMap(CounterMap) {}
179172
180173 bool walkToDeclPre (Decl *D) override {
181174 if (isUnmapped (D))
182175 return false ;
176+
183177 if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
184- bool FirstDecl = Parent.isNull ();
185- if (FirstDecl)
178+ // Don't map a nested function unless it's a constructor.
179+ bool continueWalk = Parent.isNull () || isa<ConstructorDecl>(AFD);
180+ if (continueWalk)
186181 CounterMap[AFD->getBody ()] = NextCounter++;
187- return FirstDecl;
188- }
189- if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
182+ return continueWalk;
183+ } else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
190184 CounterMap[TLCD->getBody ()] = NextCounter++;
185+ } else if (isa<NominalTypeDecl>(D)) {
186+ bool continueWalk = Parent.isNull ();
187+ if (continueWalk)
188+ WithinNominalType = true ;
189+ return continueWalk;
190+ }
191191 return true ;
192192 }
193193
@@ -559,7 +559,11 @@ struct CoverageMapping : public ASTWalker {
559559 // / \brief A stack of active repeat-while loops.
560560 std::vector<RepeatWhileStmt *> RepeatWhileStack;
561561
562- CounterExpr *ExitCounter;
562+ CounterExpr *ExitCounter = nullptr ;
563+
564+ Stmt *ImplicitTopLevelBody = nullptr ;
565+
566+ NominalTypeDecl *ParentNominalType = nullptr ;
563567
564568 // / \brief Return true if \c Node has an associated counter.
565569 bool hasCounter (ASTNode Node) { return CounterMap.count (Node); }
@@ -761,19 +765,40 @@ struct CoverageMapping : public ASTWalker {
761765 bool walkToDeclPre (Decl *D) override {
762766 if (isUnmapped (D))
763767 return false ;
768+
764769 if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
765- bool FirstDecl = Parent.isNull ();
766- if (FirstDecl)
767- assignCounter (AFD->getBody ());
768- return FirstDecl;
769- }
770- else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
770+ // Don't map a nested function unless it's a constructor.
771+ bool continueWalk = Parent.isNull () || isa<ConstructorDecl>(AFD);
772+ if (continueWalk) {
773+ CounterExpr &funcCounter = assignCounter (AFD->getBody ());
774+
775+ if (isa<ConstructorDecl>(AFD))
776+ addToCounter (ParentNominalType, funcCounter);
777+ }
778+ return continueWalk;
779+ } else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
771780 assignCounter (TLCD->getBody ());
781+ ImplicitTopLevelBody = TLCD->getBody ();
782+ } else if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
783+ bool continueWalk = Parent.isNull ();
784+ if (continueWalk) {
785+ ParentNominalType = NTD;
786+ assignCounter (NTD, CounterExpr::Zero ());
787+ pushRegion (NTD);
788+ }
789+ return continueWalk;
790+ }
791+ return true ;
792+ }
793+
794+ bool walkToDeclPost (Decl *D) override {
795+ if (isa<TopLevelCodeDecl>(D))
796+ ImplicitTopLevelBody = nullptr ;
772797 return true ;
773798 }
774799
775800 std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
776- if (S->isImplicit ())
801+ if (S->isImplicit () && S != ImplicitTopLevelBody )
777802 return {true , S};
778803
779804 if (!RegionStack.empty ())
@@ -834,7 +859,7 @@ struct CoverageMapping : public ASTWalker {
834859 }
835860
836861 Stmt *walkToStmtPost (Stmt *S) override {
837- if (S->isImplicit ())
862+ if (S->isImplicit () && S != ImplicitTopLevelBody )
838863 return S;
839864
840865 if (isa<BraceStmt>(S)) {
@@ -906,11 +931,8 @@ struct CoverageMapping : public ASTWalker {
906931 return Result;
907932 } else if (auto *IE = dyn_cast<IfExpr>(E)) {
908933 CounterExpr &ThenCounter = assignCounter (IE->getThenExpr ());
909- if (RegionStack.empty ())
910- assignCounter (IE->getElseExpr ());
911- else
912- assignCounter (IE->getElseExpr (),
913- CounterExpr::Sub (getCurrentCounter (), ThenCounter));
934+ assignCounter (IE->getElseExpr (),
935+ CounterExpr::Sub (getCurrentCounter (), ThenCounter));
914936 }
915937
916938 if (hasCounter (E))
@@ -951,6 +973,16 @@ static StringRef getCurrentFileName(ASTNode Root) {
951973 return {};
952974}
953975
976+ static void walkTopLevelNodeForProfiling (ASTNode Root, ASTWalker &Walker) {
977+ Root.walk (Walker);
978+
979+ // Visit extensions when walking through a nominal type.
980+ auto *NTD = dyn_cast_or_null<NominalTypeDecl>(Root.dyn_cast <Decl *>());
981+ if (NTD)
982+ for (ExtensionDecl *ED : NTD->getExtensions ())
983+ ED->walk (Walker);
984+ }
985+
954986void SILProfiler::assignRegionCounters () {
955987 const auto &SM = M.getASTContext ().SourceMgr ;
956988
@@ -970,31 +1002,31 @@ void SILProfiler::assignRegionCounters() {
9701002 TLCD->getStartLoc ().printLineAndColumn (OS, SM);
9711003 CurrentFuncLinkage = FormalLinkage::HiddenUnique;
9721004 } else {
973- llvm_unreachable (" Unsupported decl" );
974- }
975- } else {
976- auto *E = Root.get <Expr *>();
977- if (auto *CE = dyn_cast<AbstractClosureExpr>(E)) {
978- CurrentFuncName = SILDeclRef (CE).mangle ();
1005+ auto *NTD = cast<NominalTypeDecl>(D);
1006+ llvm::raw_string_ostream OS{CurrentFuncName};
1007+ OS << " __ntd_" << NTD->getNameStr () << " _" ;
1008+ NTD->getStartLoc ().printLineAndColumn (OS, SM);
9791009 CurrentFuncLinkage = FormalLinkage::HiddenUnique;
980- } else {
981- llvm_unreachable (" Unsupported expr" );
9821010 }
1011+ } else {
1012+ auto *CE = cast<AbstractClosureExpr>(Root.get <Expr *>());
1013+ CurrentFuncName = SILDeclRef (CE).mangle ();
1014+ CurrentFuncLinkage = FormalLinkage::HiddenUnique;
9831015 }
9841016
9851017 PGOFuncName = llvm::getPGOFuncName (
9861018 CurrentFuncName, getEquivalentPGOLinkage (CurrentFuncLinkage),
9871019 CurrentFileName);
9881020
989- walkForProfiling (Root, Mapper);
1021+ walkTopLevelNodeForProfiling (Root, Mapper);
9901022
9911023 NumRegionCounters = Mapper.NextCounter ;
9921024 // TODO: Mapper needs to calculate a function hash as it goes.
9931025 PGOFuncHash = 0x0 ;
9941026
9951027 if (EmitCoverageMapping) {
9961028 CoverageMapping Coverage (SM);
997- walkForProfiling (Root, Coverage);
1029+ walkTopLevelNodeForProfiling (Root, Coverage);
9981030 CovMap =
9991031 Coverage.emitSourceRegions (M, CurrentFuncName, PGOFuncName, PGOFuncHash,
10001032 RegionCounterMap, CurrentFileName);
@@ -1012,7 +1044,7 @@ void SILProfiler::assignRegionCounters() {
10121044 }
10131045 PGOMapping pgoMapper (RegionLoadedCounterMap, LoadedCounts,
10141046 RegionCondToParentMap);
1015- walkForProfiling (Root, pgoMapper);
1047+ walkTopLevelNodeForProfiling (Root, pgoMapper);
10161048 }
10171049}
10181050
0 commit comments