Skip to content

Commit d9f3047

Browse files
committed
[Profiler] Fix DoCatchStmt coverage handling
The logic here previously worked by computing the exit count by taking the parent count and subtracting any control flow that jumped out of the clauses. With `try` handling fixed, this no longer works correctly, since a `try` shouldn't be subtracted if the error is caught be one of the catches, as that's not actually leaving the statement. We could write the logic to determine where a `try` is jumping to, but the logic here is already pretty brittle, relying on being sprinkled in various different places. For now, let's take the more straightforward approach and handle do-catches the same way we handle switches, we initialize the exit counter to 0, and add on each exit count of each branch. This lets us re-use the existing CaseStmt handling logic. This doesn't necessarily produce the most optimal counter expressions, but I want to replace this all with a SILOptimizer pass anyway, which will be able to much more easily compute optimal counter expressions. rdar://100470244
1 parent 49ad980 commit d9f3047

File tree

4 files changed

+184
-88
lines changed

4 files changed

+184
-88
lines changed

lib/SIL/IR/SILProfiler.cpp

Lines changed: 54 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,6 @@ static bool shouldProfile(SILDeclRef Constant) {
131131
return true;
132132
}
133133

134-
static Stmt *getProfilerStmtForCase(CaseStmt *caseStmt) {
135-
switch (caseStmt->getParentKind()) {
136-
case CaseParentKind::Switch:
137-
return caseStmt;
138-
case CaseParentKind::DoCatch:
139-
return caseStmt->getBody();
140-
}
141-
llvm_unreachable("invalid parent kind");
142-
}
143-
144134
SILProfiler *SILProfiler::create(SILModule &M, SILDeclRef Ref) {
145135
// If profiling isn't enabled, don't profile anything.
146136
const auto &Opts = M.getOptions();
@@ -347,7 +337,7 @@ struct MapRegionCounters : public ASTWalker {
347337
} else if (auto *FES = dyn_cast<ForEachStmt>(S)) {
348338
mapRegion(FES->getBody());
349339
} else if (auto *CS = dyn_cast<CaseStmt>(S)) {
350-
mapRegion(getProfilerStmtForCase(CS));
340+
mapRegion(CS);
351341
}
352342
return Action::Continue(S);
353343
}
@@ -807,7 +797,7 @@ struct PGOMapping : public ASTWalker {
807797
setKnownExecutionCount(FES->getBody());
808798
setExecutionCount(FES, parentCount);
809799
} else if (auto *CS = dyn_cast<CaseStmt>(S)) {
810-
setKnownExecutionCount(getProfilerStmtForCase(CS));
800+
setKnownExecutionCount(CS);
811801
}
812802
return Action::Continue(S);
813803
}
@@ -898,9 +888,6 @@ struct CoverageMapping : public ASTWalker {
898888
/// A stack of active repeat-while loops.
899889
std::vector<RepeatWhileStmt *> RepeatWhileStack;
900890

901-
/// A stack of active do-catch statements.
902-
std::vector<DoCatchStmt *> DoCatchStack;
903-
904891
llvm::Optional<CounterExpr> ExitCounter;
905892

906893
Stmt *ImplicitTopLevelBody = nullptr;
@@ -1003,13 +990,16 @@ struct CoverageMapping : public ASTWalker {
1003990
return;
1004991

1005992
llvm::Optional<CounterExpr> JumpsToLabel;
1006-
Stmt *ParentStmt = Parent.getAsStmt();
1007-
if (ParentStmt) {
1008-
if (isa<DoCatchStmt>(ParentStmt))
1009-
return;
1010-
auto caseStmt = dyn_cast_or_null<CaseStmt>(ParentStmt);
1011-
if (caseStmt && caseStmt->getParentKind() == CaseParentKind::DoCatch)
993+
if (auto *ParentStmt = Parent.getAsStmt()) {
994+
if (auto *DCS = dyn_cast<DoCatchStmt>(ParentStmt)) {
995+
// We need to handle the brace of a DoCatchStmt here specially,
996+
// applying the same logic we apply to the catch clauses (handled by
997+
// the CaseStmt logic), we add on the exit count of the branch to the
998+
// statement's exit count.
999+
addToCounter(DCS, getExitCounter());
10121000
return;
1001+
}
1002+
10131003
if (auto *LS = dyn_cast<LabeledStmt>(ParentStmt))
10141004
JumpsToLabel = getCounter(LS);
10151005
}
@@ -1029,11 +1019,14 @@ struct CoverageMapping : public ASTWalker {
10291019
}
10301020

10311021
/// Push a region covering \c Node onto the stack.
1032-
void pushRegion(ASTNode Node) {
1022+
void pushRegion(ASTNode Node, SourceRange Range = SourceRange()) {
1023+
if (Range.isInvalid())
1024+
Range = Node.getSourceRange();
1025+
10331026
// Note we don't store counters for nodes, as we need to be able to fix
10341027
// them up later.
1035-
RegionStack.emplace_back(Node, /*Counter*/ llvm::None, Node.getStartLoc(),
1036-
getEndLoc(Node));
1028+
RegionStack.emplace_back(Node, /*Counter*/ llvm::None, Range.Start,
1029+
Lexer::getLocForEndOfToken(SM, Range.End));
10371030
LLVM_DEBUG({
10381031
llvm::dbgs() << "Pushed region: ";
10391032
RegionStack.back().print(llvm::dbgs(), SM);
@@ -1288,27 +1281,43 @@ struct CoverageMapping : public ASTWalker {
12881281
for (CaseStmt *Case : SS->getCases())
12891282
assignKnownCounter(Case);
12901283

1291-
} else if (auto caseStmt = dyn_cast<CaseStmt>(S)) {
1292-
if (caseStmt->getParentKind() == CaseParentKind::Switch)
1293-
pushRegion(S);
1284+
} else if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
1285+
// The counter for the do-catch statement itself tracks the number of
1286+
// jumps to it by break statements, including the implicit breaks at the
1287+
// end of body + catches.
1288+
assignCounter(DCS, CounterExpr::Zero());
1289+
1290+
// The do-catch body is visited the same number of times as its parent.
1291+
assignCounter(DCS->getBody(), getCurrentCounter());
1292+
1293+
// The catch clauses are CaseStmts that have their own mapped counters.
1294+
for (CaseStmt *Catch : DCS->getCatches())
1295+
assignKnownCounter(Catch);
1296+
12941297
} else if (auto *DS = dyn_cast<DoStmt>(S)) {
12951298
// The counter for the do statement itself tracks the number of jumps
12961299
// to it by break statements.
12971300
assignCounter(DS, CounterExpr::Zero());
12981301

1302+
// The do body is visited the same number of times as its parent.
12991303
assignCounter(DS->getBody(), getCurrentCounter());
13001304

1301-
} else if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
1302-
// The do-catch body is visited the same number of times as its parent.
1303-
assignCounter(DCS->getBody(), getCurrentCounter());
1304-
1305-
for (CaseStmt *Catch : DCS->getCatches())
1306-
assignKnownCounter(Catch->getBody());
1307-
1308-
// Initialize the exit count of the do-catch to the entry count, then
1309-
// subtract off non-local exits as they are visited.
1310-
assignCounter(DCS, getCurrentCounter());
1311-
DoCatchStack.push_back(DCS);
1305+
} else if (auto *CS = dyn_cast<CaseStmt>(S)) {
1306+
SourceRange Range;
1307+
switch (CS->getParentKind()) {
1308+
case CaseParentKind::DoCatch:
1309+
// For a catch clause, we only want the range to cover the brace.
1310+
Range = CS->getBody()->getSourceRange();
1311+
break;
1312+
case CaseParentKind::Switch:
1313+
// FIXME: We may want to reconsider using the full range here, as it
1314+
// implies the case pattern is evaluated the same number of times as
1315+
// the body, which is not true. We don't currently have a way of
1316+
// tracking the pattern evaluation count though.
1317+
Range = CS->getSourceRange();
1318+
break;
1319+
}
1320+
pushRegion(CS, Range);
13121321
}
13131322
return Action::Continue(S);
13141323
}
@@ -1354,39 +1363,28 @@ struct CoverageMapping : public ASTWalker {
13541363
addToCounter(BS->getTarget(), getCurrentCounter());
13551364
}
13561365

1357-
// The break also affects the exit counts of active do-catch statements.
1358-
for (auto *DCS : DoCatchStack)
1359-
subtractFromCounter(DCS, getCurrentCounter());
1360-
13611366
terminateRegion(S);
13621367

13631368
} else if (auto *FS = dyn_cast<FallthroughStmt>(S)) {
13641369
addToCounter(FS->getFallthroughDest(), getCurrentCounter());
13651370
terminateRegion(S);
13661371

1367-
} else if (isa<SwitchStmt>(S)) {
1372+
} else if (isa<SwitchStmt>(S) || isa<DoCatchStmt>(S)) {
1373+
// Replace the parent counter with the exit count of the statement.
13681374
replaceCount(getCounter(S), getEndLoc(S));
13691375

1370-
} else if (auto caseStmt = dyn_cast<CaseStmt>(S)) {
1371-
if (caseStmt->getParentKind() == CaseParentKind::Switch) {
1372-
// The end of a case block is an implicit break, update the exit
1373-
// counter to reflect this.
1374-
addToCounter(caseStmt->getParentStmt(), getCurrentCounter());
1375-
popRegions(S);
1376-
}
1377-
} else if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
1378-
assert(DoCatchStack.back() == DCS && "Malformed do-catch stack");
1379-
DoCatchStack.pop_back();
1380-
replaceCount(getCounter(S), getEndLoc(S));
1376+
} else if (auto *CS = dyn_cast<CaseStmt>(S)) {
1377+
// The end of a case/catch block is an implicit break, update the exit
1378+
// counter to reflect this.
1379+
addToCounter(CS->getParentStmt(), getCurrentCounter());
1380+
popRegions(S);
13811381

13821382
} else if (isa<ReturnStmt>(S) || isa<FailStmt>(S) || isa<ThrowStmt>(S)) {
13831383
// When we return, adjust loop condition counts and do-catch exit counts
13841384
// to reflect the early exit.
13851385
if (isa<ReturnStmt>(S) || isa<FailStmt>(S)) {
13861386
for (auto *RWS : RepeatWhileStack)
13871387
subtractFromCounter(RWS->getCond(), getCurrentCounter());
1388-
for (auto *DCS : DoCatchStack)
1389-
subtractFromCounter(DCS, getCurrentCounter());
13901388
}
13911389

13921390
terminateRegion(S);

lib/SILGen/SILGenPattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3045,7 +3045,7 @@ void SILGenFunction::emitCatchDispatch(DoCatchStmt *S, ManagedValue exn,
30453045
auto completionHandler = [&](PatternMatchEmission &emission,
30463046
ArgArray argArray, ClauseRow &row) {
30473047
auto clause = row.getClientData<CaseStmt>();
3048-
emitProfilerIncrement(clause->getBody());
3048+
emitProfilerIncrement(clause);
30493049

30503050
// Certain catch clauses can be entered along multiple paths because they
30513051
// have multiple labels. When we need multiple entrance path, we factor the

0 commit comments

Comments
 (0)