Skip to content

Commit 4d26434

Browse files
authored
Merge pull request #61580 from hamishknight/level-up
2 parents 67abbd2 + 350e28b commit 4d26434

12 files changed

+229
-137
lines changed

include/swift/SIL/SILDeclRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,11 @@ struct SILDeclRef {
565565
/// subclassed.
566566
SubclassScope getSubclassScope() const;
567567

568+
/// For a SILDeclRef that describes a variable initializer or backing
569+
/// initializer, retrieves the expression that will be emitted for that
570+
/// initialization. Otherwise, returns \c nullptr.
571+
Expr *getInitializationExpr() const;
572+
568573
bool isDynamicallyReplaceable() const;
569574

570575
bool canBeDynamicReplacement() const;

include/swift/SIL/SILFunction.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,7 @@ class SILFunction
576576
Profiler = InheritedProfiler;
577577
}
578578

579-
void createProfiler(ASTNode Root, SILDeclRef Ref);
580-
581-
void discardProfiler() { Profiler = nullptr; }
579+
void createProfiler(SILDeclRef Ref);
582580

583581
ProfileCounter getEntryCount() const { return EntryCount; }
584582

include/swift/SIL/SILProfiler.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ class SILProfiler : public SILAllocated<SILProfiler> {
8383
private:
8484
SILModule &M;
8585

86-
ASTNode Root;
87-
8886
SILDeclRef forDecl;
8987

9088
bool EmitCoverageMapping;
@@ -107,13 +105,11 @@ class SILProfiler : public SILAllocated<SILProfiler> {
107105

108106
std::vector<std::tuple<std::string, uint64_t, std::string>> CoverageData;
109107

110-
SILProfiler(SILModule &M, ASTNode Root, SILDeclRef forDecl,
111-
bool EmitCoverageMapping)
112-
: M(M), Root(Root), forDecl(forDecl),
113-
EmitCoverageMapping(EmitCoverageMapping) {}
108+
SILProfiler(SILModule &M, SILDeclRef forDecl, bool EmitCoverageMapping)
109+
: M(M), forDecl(forDecl), EmitCoverageMapping(EmitCoverageMapping) {}
114110

115111
public:
116-
static SILProfiler *create(SILModule &M, ASTNode N, SILDeclRef Ref);
112+
static SILProfiler *create(SILModule &M, SILDeclRef Ref);
117113

118114
/// Check if the function is set up for profiling.
119115
bool hasRegionCounters() const { return NumRegionCounters != 0; }

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/AnyFunctionRef.h"
1717
#include "swift/AST/Initializer.h"
1818
#include "swift/AST/ParameterList.h"
19+
#include "swift/AST/PropertyWrappers.h"
1920
#include "swift/AST/SourceFile.h"
2021
#include "swift/ClangImporter/ClangImporter.h"
2122
#include "swift/ClangImporter/ClangModule.h"
@@ -1497,6 +1498,45 @@ SubclassScope SILDeclRef::getSubclassScope() const {
14971498
llvm_unreachable("Unhandled access level in switch.");
14981499
}
14991500

1501+
Expr *SILDeclRef::getInitializationExpr() const {
1502+
switch (kind) {
1503+
case Kind::StoredPropertyInitializer: {
1504+
auto *var = cast<VarDecl>(getDecl());
1505+
auto *pbd = var->getParentPatternBinding();
1506+
unsigned idx = pbd->getPatternEntryIndexForVarDecl(var);
1507+
auto *init = pbd->getInit(idx);
1508+
assert(!pbd->isInitializerSubsumed(idx));
1509+
1510+
// If this is the backing storage for a property with an attached wrapper
1511+
// that was initialized with `=`, use that expression as the initializer.
1512+
if (auto originalProperty = var->getOriginalWrappedProperty()) {
1513+
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType()) {
1514+
auto wrapperInfo =
1515+
originalProperty->getPropertyWrapperInitializerInfo();
1516+
auto *placeholder = wrapperInfo.getWrappedValuePlaceholder();
1517+
init = placeholder->getOriginalWrappedValue();
1518+
assert(init);
1519+
}
1520+
}
1521+
return init;
1522+
}
1523+
case Kind::PropertyWrapperBackingInitializer: {
1524+
auto *var = cast<VarDecl>(getDecl());
1525+
auto wrapperInfo = var->getPropertyWrapperInitializerInfo();
1526+
assert(wrapperInfo.hasInitFromWrappedValue());
1527+
return wrapperInfo.getInitFromWrappedValue();
1528+
}
1529+
case Kind::PropertyWrapperInitFromProjectedValue: {
1530+
auto *var = cast<VarDecl>(getDecl());
1531+
auto wrapperInfo = var->getPropertyWrapperInitializerInfo();
1532+
assert(wrapperInfo.hasInitFromProjectedValue());
1533+
return wrapperInfo.getInitFromProjectedValue();
1534+
}
1535+
default:
1536+
return nullptr;
1537+
}
1538+
}
1539+
15001540
unsigned SILDeclRef::getParameterListCount() const {
15011541
// Only decls can introduce currying.
15021542
if (!hasDecl())

lib/SIL/IR/SILFunction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,12 +332,11 @@ void SILFunction::deleteSnapshot(int ID) {
332332
} while ((f = f->snapshots) != nullptr);
333333
}
334334

335-
void SILFunction::createProfiler(ASTNode Root, SILDeclRef Ref) {
335+
void SILFunction::createProfiler(SILDeclRef Ref) {
336336
assert(!Profiler && "Function already has a profiler");
337-
assert(Root && "Cannot profile a null ASTNode");
338337
assert(Ref && "Must have non-null SILDeclRef");
339338

340-
Profiler = SILProfiler::create(Module, Root, Ref);
339+
Profiler = SILProfiler::create(Module, Ref);
341340
if (!Profiler)
342341
return;
343342

lib/SIL/IR/SILProfiler.cpp

Lines changed: 97 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,75 @@
2525

2626
using namespace swift;
2727

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+
3090
// 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+
}
3597
}
3698

3799
// Do not profile AST nodes in unavailable contexts.
@@ -62,51 +124,17 @@ static Stmt *getProfilerStmtForCase(CaseStmt *caseStmt) {
62124
llvm_unreachable("invalid parent kind");
63125
}
64126

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) {
94128
// If profiling isn't enabled, don't profile anything.
95129
const auto &Opts = M.getOptions();
96130
if (!Opts.GenerateProfile && Opts.UseProfile.empty())
97131
return nullptr;
98132

99-
if (!shouldProfile(N, Ref))
133+
if (!shouldProfile(Ref))
100134
return nullptr;
101135

102-
if (!canCreateProfilerForAST(N, Ref)) {
103-
N.dump(llvm::errs());
104-
llvm_unreachable("Invalid AST node for profiling");
105-
}
106-
107136
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);
110138
SP->assignRegionCounters();
111139
return SP;
112140
}
@@ -163,6 +191,7 @@ namespace {
163191
template <typename F>
164192
ASTWalker::PreWalkAction
165193
visitFunctionDecl(ASTWalker &Walker, AbstractFunctionDecl *AFD, F Func) {
194+
assert(AFD->hasBody());
166195
if (Walker.Parent.isNull()) {
167196
Func();
168197
return ASTWalker::Action::Continue();
@@ -177,7 +206,9 @@ shouldWalkIntoExpr(Expr *E, ASTWalker::ParentTy Parent, SILDeclRef Constant) {
177206

178207
// Profiling for closures should be handled separately. Do not visit
179208
// closure expressions twice.
180-
if (isa<AbstractClosureExpr>(E)) {
209+
if (auto *CE = dyn_cast<AbstractClosureExpr>(E)) {
210+
assert(CE->hasBody());
211+
181212
// A non-null parent means we have a closure child, which we will visit
182213
// separately. Even if the parent is null, don't walk into a closure if the
183214
// SILDeclRef is not for a closure, as it could be for a property
@@ -1307,29 +1338,33 @@ static StringRef getCurrentFileName(SILDeclRef forDecl) {
13071338
return {};
13081339
}
13091340

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+
13101351
void SILProfiler::assignRegionCounters() {
13111352
const auto &SM = M.getASTContext().SourceMgr;
13121353

13131354
CurrentFileName = getCurrentFileName(forDecl);
13141355

13151356
MapRegionCounters Mapper(forDecl, RegionCounterMap);
13161357

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);
13291367
}
1330-
} else {
1331-
CurrentFuncName = forDecl.mangle();
1332-
CurrentFuncLinkage = FormalLinkage::HiddenUnique;
13331368
}
13341369

13351370
PGOFuncName = llvm::getPGOFuncName(
@@ -1341,15 +1376,15 @@ void SILProfiler::assignRegionCounters() {
13411376

13421377
LLVM_DEBUG(llvm::dbgs() << "Assigning counters to: " << CurrentFuncName
13431378
<< "\n");
1344-
Root.walk(Mapper);
1379+
walkNode(Root, Mapper);
13451380

13461381
NumRegionCounters = Mapper.NextCounter;
13471382
// TODO: Mapper needs to calculate a function hash as it goes.
13481383
PGOFuncHash = 0x0;
13491384

13501385
if (EmitCoverageMapping) {
13511386
CoverageMapping Coverage(SM, forDecl);
1352-
Root.walk(Coverage);
1387+
walkNode(Root, Coverage);
13531388
CovMap =
13541389
Coverage.emitSourceRegions(M, CurrentFuncName, PGOFuncName, PGOFuncHash,
13551390
RegionCounterMap, CurrentFileName);
@@ -1367,7 +1402,7 @@ void SILProfiler::assignRegionCounters() {
13671402
}
13681403
PGOMapping pgoMapper(forDecl, RegionCounterMap, LoadedCounts.get(),
13691404
RegionLoadedCounterMap, RegionCondToParentMap);
1370-
Root.walk(pgoMapper);
1405+
walkNode(Root, pgoMapper);
13711406
}
13721407
}
13731408

0 commit comments

Comments
 (0)