@@ -114,12 +114,23 @@ static bool shouldProfile(SILDeclRef Constant) {
114
114
}
115
115
}
116
116
117
- // Do not profile AST nodes in unavailable contexts.
118
117
if (auto *D = DC->getInnermostDeclarationDeclContext ()) {
118
+ // Do not profile AST nodes in unavailable contexts.
119
119
if (D->getSemanticUnavailableAttr ()) {
120
120
LLVM_DEBUG (llvm::dbgs () << " Skipping ASTNode: unavailable context\n " );
121
121
return false ;
122
122
}
123
+
124
+ // Do not profile functions that have had their bodies replaced (e.g
125
+ // function body macros).
126
+ // TODO: If/when preamble macros become an official feature, we'll
127
+ // need to be more nuanced here.
128
+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
129
+ if (AFD->getOriginalBodySourceRange () != AFD->getBodySourceRange ()) {
130
+ LLVM_DEBUG (llvm::dbgs () << " Skipping function: body replaced\n " );
131
+ return false ;
132
+ }
133
+ }
123
134
}
124
135
125
136
// Do not profile code that hasn't been written by the user.
@@ -247,9 +258,12 @@ bool shouldSkipExpr(Expr *E) {
247
258
// / Whether the children of a decl that isn't explicitly handled should be
248
259
// / walked.
249
260
static bool shouldWalkIntoUnhandledDecl (const Decl *D) {
250
- // We want to walk into the initializer for a pattern binding decl. This
251
- // allows us to map LazyInitializerExprs.
252
- return isa<PatternBindingDecl>(D);
261
+ // We want to walk into initializers for bindings, and the expansions of
262
+ // MacroExpansionDecls, which will be nested within MacroExpansionExprs in
263
+ // local contexts. We won't record any regions within the macro expansion,
264
+ // but still need to walk to get accurate counter information in case e.g
265
+ // there's a throwing function call in the expansion.
266
+ return isa<PatternBindingDecl>(D) || isa<MacroExpansionDecl>(D);
253
267
}
254
268
255
269
// / Whether the expression \c E could potentially throw an error.
@@ -468,6 +482,10 @@ class SourceMappingRegion {
468
482
// / The region's ending location.
469
483
std::optional<SourceLoc> EndLoc;
470
484
485
+ // / Whether the region is within a macro expansion. Such regions do not
486
+ // / get recorded, but are needed to track the counters within the expansion.
487
+ bool IsInMacroExpansion = false ;
488
+
471
489
SourceMappingRegion (Kind RegionKind, std::optional<CounterExpr> Counter,
472
490
std::optional<SourceLoc> StartLoc)
473
491
: RegionKind(RegionKind), Counter(Counter), StartLoc(StartLoc) {
@@ -516,6 +534,14 @@ class SourceMappingRegion {
516
534
SourceMappingRegion (SourceMappingRegion &&Region) = default ;
517
535
SourceMappingRegion &operator =(SourceMappingRegion &&RHS) = default ;
518
536
537
+ bool isInMacroExpansion () const {
538
+ return IsInMacroExpansion;
539
+ }
540
+
541
+ void setIsInMacroExpansion () {
542
+ IsInMacroExpansion = true ;
543
+ }
544
+
519
545
// / Whether this region is for scoping only.
520
546
bool isForScopingOnly () const { return RegionKind == Kind::ScopingOnly; }
521
547
@@ -810,6 +836,7 @@ struct PGOMapping : public ASTWalker {
810
836
struct CoverageMapping : public ASTWalker {
811
837
private:
812
838
const SourceManager &SM;
839
+ SourceFile *SF;
813
840
814
841
// / The SIL function being profiled.
815
842
SILDeclRef Constant;
@@ -836,6 +863,12 @@ struct CoverageMapping : public ASTWalker {
836
863
837
864
Stmt *ImplicitTopLevelBody = nullptr ;
838
865
866
+ // / The number of parent MacroExpansionExprs.
867
+ unsigned MacroDepth = 0 ;
868
+
869
+ // / Whether the current walk is within a macro expansion.
870
+ bool isInMacroExpansion () const { return MacroDepth > 0 ; }
871
+
839
872
// / Return true if \c Ref has an associated counter.
840
873
bool hasCounter (ProfileCounterRef Ref) { return CounterExprs.count (Ref); }
841
874
@@ -992,6 +1025,10 @@ struct CoverageMapping : public ASTWalker {
992
1025
993
1026
// / Push a region onto the stack.
994
1027
void pushRegion (SourceMappingRegion Region) {
1028
+ // Note on the region whether we're currently in a macro expansion.
1029
+ if (isInMacroExpansion ())
1030
+ Region.setIsInMacroExpansion ();
1031
+
995
1032
LLVM_DEBUG ({
996
1033
llvm::dbgs () << " Pushed region: " ;
997
1034
Region.print (llvm::dbgs (), SM);
@@ -1026,6 +1063,11 @@ struct CoverageMapping : public ASTWalker {
1026
1063
llvm::dbgs () << " \n " ;
1027
1064
});
1028
1065
1066
+ // Don't record regions in macro expansions, they don't have source
1067
+ // locations that can be meaningfully mapped to source code.
1068
+ if (Region.isInMacroExpansion ())
1069
+ return ;
1070
+
1029
1071
// Don't bother recording regions that are only present for scoping.
1030
1072
if (Region.isForScopingOnly ())
1031
1073
return ;
@@ -1111,9 +1153,10 @@ struct CoverageMapping : public ASTWalker {
1111
1153
1112
1154
public:
1113
1155
CoverageMapping (
1114
- const SourceManager &SM , SILDeclRef Constant,
1156
+ SourceFile *SF , SILDeclRef Constant,
1115
1157
const llvm::DenseMap<ProfileCounterRef, unsigned > &ConcreteCounters)
1116
- : SM(SM), Constant(Constant), ConcreteCounters(ConcreteCounters) {}
1158
+ : SM(SF->getASTContext ().SourceMgr), SF(SF), Constant(Constant),
1159
+ ConcreteCounters(ConcreteCounters) {}
1117
1160
1118
1161
LazyInitializerWalking getLazyInitializerWalkingBehavior () override {
1119
1162
// We want to walk lazy initializers present in the synthesized getter for
@@ -1135,20 +1178,33 @@ struct CoverageMapping : public ASTWalker {
1135
1178
// / source regions.
1136
1179
SILCoverageMap *emitSourceRegions (SILModule &M, StringRef Name,
1137
1180
StringRef PGOFuncName, uint64_t Hash,
1138
- SourceFile *SF, StringRef Filename) {
1181
+ StringRef Filename) {
1139
1182
if (SourceRegions.empty ())
1140
1183
return nullptr ;
1141
1184
1142
- using MappedRegion = SILCoverageMap::MappedRegion;
1185
+ auto FileSourceRange = SM.getRangeForBuffer (*SF->getBufferID ());
1186
+ auto isLocInFile = [&](SourceLoc Loc) {
1187
+ return FileSourceRange.contains (Loc) || FileSourceRange.getEnd () == Loc;
1188
+ };
1143
1189
1190
+ using MappedRegion = SILCoverageMap::MappedRegion;
1144
1191
std::vector<MappedRegion> Regions;
1145
1192
SourceRange OuterRange;
1146
1193
for (const auto &Region : SourceRegions) {
1147
1194
assert (Region.hasStartLoc () && " invalid region" );
1148
1195
assert (Region.hasEndLoc () && " incomplete region" );
1149
1196
1150
- // Build up the outer range from the union of all coverage regions.
1151
1197
SourceRange Range (Region.getStartLoc (), Region.getEndLoc ());
1198
+
1199
+ // Make sure we haven't ended up with any source locations outside the
1200
+ // SourceFile (e.g for generated code such as macros), asserting in an
1201
+ // asserts build, dropping in a non-asserts build.
1202
+ if (!isLocInFile (Range.Start ) || !isLocInFile (Range.End )) {
1203
+ assert (false && " range outside of file" );
1204
+ continue ;
1205
+ }
1206
+
1207
+ // Build up the outer range from the union of all coverage regions.
1152
1208
if (!OuterRange) {
1153
1209
OuterRange = Range;
1154
1210
} else {
@@ -1520,10 +1576,14 @@ struct CoverageMapping : public ASTWalker {
1520
1576
1521
1577
if (hasCounter (E)) {
1522
1578
pushRegion (SourceMappingRegion::forNode (E, SM));
1523
- } else if (isa<OptionalTryExpr>(E)) {
1579
+ } else if (isa<OptionalTryExpr>(E) || isa<MacroExpansionExpr>(E) ) {
1524
1580
// If we have a `try?`, that doesn't already have a counter, record it
1525
1581
// as a scoping-only region. We need it to scope child error branches,
1526
1582
// but don't need it in the resulting set of regions.
1583
+ //
1584
+ // If we have a macro expansion, also push a scoping-only region. We'll
1585
+ // discard any regions recorded within the macro, but will adjust for any
1586
+ // control flow that may have happened within the macro.
1527
1587
assignCounter (E, getCurrentCounter ());
1528
1588
pushRegion (SourceMappingRegion::scopingOnly (E, SM));
1529
1589
}
@@ -1558,6 +1618,10 @@ struct CoverageMapping : public ASTWalker {
1558
1618
// Already visited the children.
1559
1619
return Action::SkipChildren (TE);
1560
1620
}
1621
+
1622
+ if (isa<MacroExpansionExpr>(E))
1623
+ MacroDepth += 1 ;
1624
+
1561
1625
return shouldWalkIntoExpr (E, Parent, Constant);
1562
1626
}
1563
1627
@@ -1574,6 +1638,11 @@ struct CoverageMapping : public ASTWalker {
1574
1638
Lexer::getLocForEndOfToken (SM, E->getEndLoc ()));
1575
1639
}
1576
1640
1641
+ if (isa<MacroExpansionExpr>(E)) {
1642
+ assert (isInMacroExpansion ());
1643
+ MacroDepth -= 1 ;
1644
+ }
1645
+
1577
1646
if (hasCounter (E))
1578
1647
exitRegion (E);
1579
1648
@@ -1610,7 +1679,6 @@ static void walkNode(NodeToProfile Node, ASTWalker &Walker) {
1610
1679
}
1611
1680
1612
1681
void SILProfiler::assignRegionCounters () {
1613
- const auto &SM = M.getASTContext ().SourceMgr ;
1614
1682
auto *DC = forDecl.getInnermostDeclContext ();
1615
1683
auto *SF = DC->getParentSourceFile ();
1616
1684
assert (SF && " Not within a SourceFile?" );
@@ -1647,10 +1715,10 @@ void SILProfiler::assignRegionCounters() {
1647
1715
PGOFuncHash = 0x0 ;
1648
1716
1649
1717
if (EmitCoverageMapping) {
1650
- CoverageMapping Coverage (SM , forDecl, RegionCounterMap);
1718
+ CoverageMapping Coverage (SF , forDecl, RegionCounterMap);
1651
1719
walkNode (Root, Coverage);
1652
1720
CovMap = Coverage.emitSourceRegions (M, CurrentFuncName, PGOFuncName,
1653
- PGOFuncHash, SF, CurrentFileName);
1721
+ PGOFuncHash, CurrentFileName);
1654
1722
}
1655
1723
1656
1724
if (llvm::IndexedInstrProfReader *IPR = M.getPGOReader ()) {
0 commit comments