Skip to content

Commit 49ad980

Browse files
committed
[Profiler] Map regions for error-throwing AST nodes
Map a counter for the error branch of a given potentially-throwing expression, and subtract it from the following region count. rdar://34244637
1 parent 4e48db5 commit 49ad980

File tree

6 files changed

+523
-86
lines changed

6 files changed

+523
-86
lines changed

lib/SIL/IR/SILProfiler.cpp

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,28 @@ static bool shouldWalkIntoUnhandledDecl(const Decl *D) {
262262
return isa<PatternBindingDecl>(D);
263263
}
264264

265+
/// Whether the expression \c E could potentially throw an error.
266+
static bool mayExpressionThrow(const Expr *E) {
267+
if (auto *AE = dyn_cast<ApplyExpr>(E)) {
268+
// Throws if the function throws.
269+
return bool(AE->throws());
270+
}
271+
if (auto *S = dyn_cast<SubscriptExpr>(E)) {
272+
// Throws if subscript has a throwing getter.
273+
auto *SD = cast<SubscriptDecl>(S->getDecl().getDecl());
274+
if (auto *accessor = SD->getEffectfulGetAccessor())
275+
return accessor->hasThrows();
276+
}
277+
if (auto *DE = dyn_cast<DeclRefExpr>(E)) {
278+
if (auto *VD = dyn_cast<VarDecl>(DE->getDecl())) {
279+
// Throws if the getter throws.
280+
if (auto *accessor = VD->getEffectfulGetAccessor())
281+
return accessor->hasThrows();
282+
}
283+
}
284+
return false;
285+
}
286+
265287
/// An ASTWalker that maps ASTNodes to profiling counters.
266288
struct MapRegionCounters : public ASTWalker {
267289
/// The SIL function being profiled.
@@ -355,7 +377,26 @@ struct MapRegionCounters : public ASTWalker {
355377
if (isa<LazyInitializerExpr>(E))
356378
mapRegion(E);
357379

358-
return shouldWalkIntoExpr(E, Parent, Constant);
380+
auto WalkResult = shouldWalkIntoExpr(E, Parent, Constant);
381+
if (WalkResult.Action.Action == PreWalkAction::SkipChildren) {
382+
// We need to manually do the post-visit here since the ASTWalker will
383+
// skip it.
384+
// FIXME: The ASTWalker should do a post-visit.
385+
walkToExprPost(E);
386+
}
387+
return WalkResult;
388+
}
389+
390+
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
391+
if (shouldSkipExpr(E))
392+
return Action::Continue(E);
393+
394+
// If we have an expr that may throw an error, give it a counter for the
395+
// error branch.
396+
if (mayExpressionThrow(E))
397+
mapRegion(ProfileCounterRef::errorBranchOf(E));
398+
399+
return Action::Continue(E);
359400
}
360401
};
361402

@@ -809,7 +850,26 @@ struct PGOMapping : public ASTWalker {
809850
if (isa<LazyInitializerExpr>(E))
810851
setKnownExecutionCount(E);
811852

812-
return shouldWalkIntoExpr(E, Parent, Constant);
853+
auto WalkResult = shouldWalkIntoExpr(E, Parent, Constant);
854+
if (WalkResult.Action.Action == PreWalkAction::SkipChildren) {
855+
// We need to manually do the post-visit here since the ASTWalker will
856+
// skip it.
857+
// FIXME: The ASTWalker should do a post-visit.
858+
walkToExprPost(E);
859+
}
860+
return WalkResult;
861+
}
862+
863+
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
864+
if (shouldSkipExpr(E))
865+
return Action::Continue(E);
866+
867+
// If we have an expr that may throw an error, give it a counter for the
868+
// error branch.
869+
if (mayExpressionThrow(E))
870+
setKnownExecutionCount(ProfileCounterRef::errorBranchOf(E));
871+
872+
return Action::Continue(E);
813873
}
814874
};
815875

@@ -1379,11 +1439,10 @@ struct CoverageMapping : public ASTWalker {
13791439
}
13801440
auto WalkResult = shouldWalkIntoExpr(E, Parent, Constant);
13811441
if (WalkResult.Action.Action == PreWalkAction::SkipChildren) {
1382-
// We need to manually pop the region here as the ASTWalker won't call
1383-
// the post-visitation.
1442+
// We need to manually do the post-visit here since the ASTWalker will
1443+
// skip it.
13841444
// FIXME: The ASTWalker should do a post-visit.
1385-
if (hasCounter(E))
1386-
popRegions(E);
1445+
walkToExprPost(E);
13871446
}
13881447
return WalkResult;
13891448
}
@@ -1395,6 +1454,15 @@ struct CoverageMapping : public ASTWalker {
13951454
if (hasCounter(E))
13961455
popRegions(E);
13971456

1457+
// The region following the expression gets current counter minus the
1458+
// error branch counter, i.e the number of times we didn't throw an error.
1459+
if (!RegionStack.empty() && mayExpressionThrow(E)) {
1460+
auto ThrowCount = assignKnownCounter(ProfileCounterRef::errorBranchOf(E));
1461+
replaceCount(
1462+
CounterExpr::Sub(getCurrentCounter(), ThrowCount, CounterAlloc),
1463+
Lexer::getLocForEndOfToken(SM, E->getEndLoc()));
1464+
}
1465+
13981466
return Action::Continue(E);
13991467
}
14001468
};

lib/SILGen/SILGenStmt.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/SIL/BasicBlockUtils.h"
2727
#include "swift/SIL/AbstractionPatternGenerators.h"
2828
#include "swift/SIL/SILArgument.h"
29+
#include "swift/SIL/SILProfiler.h"
2930
#include "llvm/Support/SaveAndRestore.h"
3031

3132
using namespace swift;
@@ -1516,6 +1517,15 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15161517
return;
15171518
}
15181519

1520+
if (auto *E = loc.getAsASTNode<Expr>()) {
1521+
// Check to see whether we have a counter associated with the error branch
1522+
// of this node, and if so emit a counter increment.
1523+
auto *P = F.getProfiler();
1524+
auto ref = ProfileCounterRef::errorBranchOf(E);
1525+
if (P && P->hasCounterFor(ref))
1526+
emitProfilerIncrement(ref);
1527+
}
1528+
15191529
SmallVector<SILValue, 1> args;
15201530

15211531
auto indirectErrorAddr = ThrowDest.getThrownError().IndirectErrorResult;

0 commit comments

Comments
 (0)