25
25
26
26
using namespace swift ;
27
27
28
- // / Check whether a root AST node should be profiled.
29
- static bool shouldProfile (ASTNode N, SILDeclRef Constant) {
28
+ // / Unfortunately this is needed as ASTNode can't currently represent a
29
+ // / SourceFile.
30
+ class NodeToProfile final {
31
+ // / For a direct ASTNode, this stores the node itself. For a main SourceFile,
32
+ // / it stores the corresponding ModuleDecl.
33
+ ASTNode Storage;
34
+
35
+ explicit NodeToProfile (ASTNode Node) : Storage(Node) {}
36
+
37
+ public:
38
+ static NodeToProfile node (ASTNode Node) {
39
+ assert (!isa_and_nonnull<ModuleDecl>(Node.dyn_cast <Decl *>()));
40
+ return NodeToProfile (Node);
41
+ }
42
+ static NodeToProfile mainSourceFile (SourceFile *SF) {
43
+ assert (SF->isScriptMode ());
44
+ auto N = NodeToProfile (SF->getParentModule ());
45
+ assert (N.getAsSourceFile () == SF);
46
+ return N;
47
+ }
48
+
49
+ // / If an ASTNode is being stored, returns it, otherwise \c nullptr.
50
+ ASTNode getAsNode () const {
51
+ return isSourceFile () ? nullptr : Storage;
52
+ }
53
+
54
+ // / Whether this is storing a main SourceFile.
55
+ bool isSourceFile () const {
56
+ return getAsSourceFile ();
57
+ }
58
+
59
+ // / If a main SourceFile is being stored, returns it, otherwise \c nullptr.
60
+ SourceFile *getAsSourceFile () const {
61
+ auto *M = dyn_cast_or_null<ModuleDecl>(Storage.dyn_cast <Decl *>());
62
+ return M ? &M->getMainSourceFile () : nullptr ;
63
+ }
64
+ };
65
+
66
+ static NodeToProfile getNodeToProfile (SILDeclRef Constant) {
67
+ // If we have an initialization expression, walk that instead of the variable.
68
+ if (auto *E = Constant.getInitializationExpr ())
69
+ return NodeToProfile::node (E);
70
+
71
+ // Otherwise, we walk the SILDeclRef's node directly.
72
+ using LocKind = SILDeclRef::LocKind;
73
+ switch (Constant.getLocKind ()) {
74
+ case LocKind::Decl:
75
+ return NodeToProfile::node (Constant.getDecl ());
76
+ case LocKind::Closure:
77
+ return NodeToProfile::node (Constant.getAbstractClosureExpr ());
78
+ case LocKind::File: {
79
+ auto *SF = cast<SourceFile>(Constant.getFileUnit ());
80
+ return NodeToProfile::mainSourceFile (SF);
81
+ }
82
+ }
83
+ llvm_unreachable (" Unhandled case in switch!" );
84
+ }
85
+
86
+ // / Check whether we should profile a given SILDeclRef.
87
+ static bool shouldProfile (SILDeclRef Constant) {
88
+ auto Root = getNodeToProfile (Constant);
89
+
30
90
// Do not profile AST nodes with invalid source locations.
31
- if (N.getStartLoc ().isInvalid () || N.getEndLoc ().isInvalid ()) {
32
- LLVM_DEBUG (llvm::dbgs ()
33
- << " Skipping ASTNode: invalid start/end locations\n " );
34
- return false ;
91
+ if (auto N = Root.getAsNode ()) {
92
+ if (N.getStartLoc ().isInvalid () || N.getEndLoc ().isInvalid ()) {
93
+ LLVM_DEBUG (llvm::dbgs ()
94
+ << " Skipping ASTNode: invalid start/end locations\n " );
95
+ return false ;
96
+ }
35
97
}
36
98
37
99
// Do not profile AST nodes in unavailable contexts.
@@ -62,51 +124,17 @@ static Stmt *getProfilerStmtForCase(CaseStmt *caseStmt) {
62
124
llvm_unreachable (" invalid parent kind" );
63
125
}
64
126
65
- // / Check that the input AST has at least been type-checked.
66
- LLVM_ATTRIBUTE_UNUSED
67
- static bool hasFileBeenTypeChecked (SILDeclRef forDecl) {
68
- auto *SF = forDecl.getInnermostDeclContext ()->getParentSourceFile ();
69
- return SF && SF->ASTStage >= SourceFile::TypeChecked;
70
- }
71
-
72
- // / Check whether a mapped AST node is valid for profiling.
73
- static bool canCreateProfilerForAST (ASTNode N, SILDeclRef forDecl) {
74
- assert (hasFileBeenTypeChecked (forDecl) &&
75
- " Cannot use this AST for profiling" );
76
-
77
- if (auto *D = N.dyn_cast <Decl *>()) {
78
- if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
79
- return AFD->hasBody ();
80
-
81
- if (isa<TopLevelCodeDecl>(D))
82
- return true ;
83
- } else if (N.get <Expr *>()) {
84
- if (auto *closure = forDecl.getAbstractClosureExpr ())
85
- return closure->hasBody ();
86
- if (forDecl.isStoredPropertyInitializer () ||
87
- forDecl.isPropertyWrapperBackingInitializer ())
88
- return true ;
89
- }
90
- return false ;
91
- }
92
-
93
- SILProfiler *SILProfiler::create (SILModule &M, ASTNode N, SILDeclRef Ref) {
127
+ SILProfiler *SILProfiler::create (SILModule &M, SILDeclRef Ref) {
94
128
// If profiling isn't enabled, don't profile anything.
95
129
const auto &Opts = M.getOptions ();
96
130
if (!Opts.GenerateProfile && Opts.UseProfile .empty ())
97
131
return nullptr ;
98
132
99
- if (!shouldProfile (N, Ref))
133
+ if (!shouldProfile (Ref))
100
134
return nullptr ;
101
135
102
- if (!canCreateProfilerForAST (N, Ref)) {
103
- N.dump (llvm::errs ());
104
- llvm_unreachable (" Invalid AST node for profiling" );
105
- }
106
-
107
136
auto *Buf = M.allocate <SILProfiler>(1 );
108
- auto *SP =
109
- ::new (Buf) SILProfiler (M, N, Ref, Opts.EmitProfileCoverageMapping );
137
+ auto *SP = ::new (Buf) SILProfiler (M, Ref, Opts.EmitProfileCoverageMapping );
110
138
SP->assignRegionCounters ();
111
139
return SP;
112
140
}
@@ -163,6 +191,7 @@ namespace {
163
191
template <typename F>
164
192
ASTWalker::PreWalkAction
165
193
visitFunctionDecl (ASTWalker &Walker, AbstractFunctionDecl *AFD, F Func) {
194
+ assert (AFD->hasBody ());
166
195
if (Walker.Parent .isNull ()) {
167
196
Func ();
168
197
return ASTWalker::Action::Continue ();
@@ -177,7 +206,9 @@ shouldWalkIntoExpr(Expr *E, ASTWalker::ParentTy Parent, SILDeclRef Constant) {
177
206
178
207
// Profiling for closures should be handled separately. Do not visit
179
208
// closure expressions twice.
180
- if (isa<AbstractClosureExpr>(E)) {
209
+ if (auto *CE = dyn_cast<AbstractClosureExpr>(E)) {
210
+ assert (CE->hasBody ());
211
+
181
212
// A non-null parent means we have a closure child, which we will visit
182
213
// separately. Even if the parent is null, don't walk into a closure if the
183
214
// SILDeclRef is not for a closure, as it could be for a property
@@ -1307,29 +1338,33 @@ static StringRef getCurrentFileName(SILDeclRef forDecl) {
1307
1338
return {};
1308
1339
}
1309
1340
1341
+ static void walkNode (NodeToProfile Node, ASTWalker &Walker) {
1342
+ if (auto N = Node.getAsNode ()) {
1343
+ N.walk (Walker);
1344
+ } else {
1345
+ // We want to walk the SourceFile for a top-level entry point. We will only
1346
+ // assign regions to TopLevelCodeDecls.
1347
+ Node.getAsSourceFile ()->walk (Walker);
1348
+ }
1349
+ }
1350
+
1310
1351
void SILProfiler::assignRegionCounters () {
1311
1352
const auto &SM = M.getASTContext ().SourceMgr ;
1312
1353
1313
1354
CurrentFileName = getCurrentFileName (forDecl);
1314
1355
1315
1356
MapRegionCounters Mapper (forDecl, RegionCounterMap);
1316
1357
1317
- std::string CurrentFuncName;
1318
- FormalLinkage CurrentFuncLinkage;
1319
- if (auto *D = Root.dyn_cast <Decl *>()) {
1320
- if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
1321
- CurrentFuncName = forDecl.mangle ();
1322
- CurrentFuncLinkage = getDeclLinkage (AFD);
1323
- } else {
1324
- auto *TLCD = cast<TopLevelCodeDecl>(D);
1325
- llvm::raw_string_ostream OS{CurrentFuncName};
1326
- OS << " __tlcd_" ;
1327
- TLCD->getStartLoc ().printLineAndColumn (OS, SM);
1328
- CurrentFuncLinkage = FormalLinkage::HiddenUnique;
1358
+ auto Root = getNodeToProfile (forDecl);
1359
+
1360
+ auto CurrentFuncName = forDecl.mangle ();
1361
+ auto CurrentFuncLinkage = FormalLinkage::HiddenUnique;
1362
+
1363
+ if (auto N = Root.getAsNode ()) {
1364
+ if (auto *D = N.dyn_cast <Decl *>()) {
1365
+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
1366
+ CurrentFuncLinkage = getDeclLinkage (AFD);
1329
1367
}
1330
- } else {
1331
- CurrentFuncName = forDecl.mangle ();
1332
- CurrentFuncLinkage = FormalLinkage::HiddenUnique;
1333
1368
}
1334
1369
1335
1370
PGOFuncName = llvm::getPGOFuncName (
@@ -1341,15 +1376,15 @@ void SILProfiler::assignRegionCounters() {
1341
1376
1342
1377
LLVM_DEBUG (llvm::dbgs () << " Assigning counters to: " << CurrentFuncName
1343
1378
<< " \n " );
1344
- Root. walk ( Mapper);
1379
+ walkNode (Root, Mapper);
1345
1380
1346
1381
NumRegionCounters = Mapper.NextCounter ;
1347
1382
// TODO: Mapper needs to calculate a function hash as it goes.
1348
1383
PGOFuncHash = 0x0 ;
1349
1384
1350
1385
if (EmitCoverageMapping) {
1351
1386
CoverageMapping Coverage (SM, forDecl);
1352
- Root. walk ( Coverage);
1387
+ walkNode (Root, Coverage);
1353
1388
CovMap =
1354
1389
Coverage.emitSourceRegions (M, CurrentFuncName, PGOFuncName, PGOFuncHash,
1355
1390
RegionCounterMap, CurrentFileName);
@@ -1367,7 +1402,7 @@ void SILProfiler::assignRegionCounters() {
1367
1402
}
1368
1403
PGOMapping pgoMapper (forDecl, RegionCounterMap, LoadedCounts.get (),
1369
1404
RegionLoadedCounterMap, RegionCondToParentMap);
1370
- Root. walk ( pgoMapper);
1405
+ walkNode (Root, pgoMapper);
1371
1406
}
1372
1407
}
1373
1408
0 commit comments