Skip to content

Commit 91f6f34

Browse files
committed
Add debug info support for inlined and specialized generic variables.
This patch adds SIL-level debug info support for variables whose static type is rewritten by an optimizer transformation. When a function is (generic-)specialized or inlined, the static types of inlined variables my change as they are remapped into the generic environment of the inlined call site. With this patch all inlined SILDebugScopes that point to functions with a generic signature are recursively rewritten to point to clones of the original function with new unique mangled names. The new mangled names consist of the old mangled names plus the new substituions, similar (or exactly, respectively) to how generic specialization is handled. On libSwiftCore.dylib (x86_64), this yields a 17% increase in unique source vars and a ~24% increase in variables with a debug location. rdar://problem/28859432 rdar://problem/34526036
1 parent 296b9d1 commit 91f6f34

File tree

18 files changed

+282
-70
lines changed

18 files changed

+282
-70
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ Function Specializations
785785

786786
specialization ::= type '_' type* 'Tg' SPEC-INFO // Generic re-abstracted specialization
787787
specialization ::= type '_' type* 'TG' SPEC-INFO // Generic not re-abstracted specialization
788+
specialization ::= type '_' type* 'Ti' SPEC-INFO // Inlined function with generic substitutions.
788789

789790
The types are the replacement types of the substitution list.
790791

include/swift/AST/SubstitutionMap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class SubstitutionMap {
153153
/// existential.
154154
bool hasOpenedExistential() const;
155155

156-
/// Query whether any replacement type sin the map contain dynamic Self.
156+
/// Query whether any replacement types in the map contain dynamic Self.
157157
bool hasDynamicSelf() const;
158158

159159
/// Whether the replacement types are all canonical.

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ NODE(ResilientProtocolWitnessTable)
8787
NODE(GenericSpecialization)
8888
NODE(GenericSpecializationNotReAbstracted)
8989
NODE(GenericSpecializationParam)
90+
NODE(InlinedGenericFunction)
9091
NODE(GenericTypeMetadataPattern)
9192
CONTEXT_NODE(Getter)
9293
NODE(Global)

include/swift/SIL/TypeSubstCloner.h

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/SIL/SILCloner.h"
2525
#include "swift/SIL/DynamicCasts.h"
2626
#include "swift/SILOptimizer/Utils/Local.h"
27+
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
2728
#include "llvm/Support/Debug.h"
2829

2930
namespace swift {
@@ -279,6 +280,84 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
279280
super::visitDestroyValueInst(Destroy);
280281
}
281282

283+
/// One abstract function in the debug info can only have one set of variables
284+
/// and types. This function determines whether applying the substitutions in
285+
/// \p SubsMap on the generic signature \p Sig will change the generic type
286+
/// parameters in the signature. This is used to decide whether it's necessary
287+
/// to clone a unique copy of the function declaration with the substitutions
288+
/// applied for the debug info.
289+
static bool substitutionsChangeGenericTypeParameters(SubstitutionMap SubsMap,
290+
GenericSignature *Sig) {
291+
292+
// If there are no substitutions, just reuse
293+
// the original decl.
294+
if (SubsMap.empty())
295+
return false;
296+
297+
auto Params = Sig->getSubstitutableParams();
298+
return std::any_of(Params.begin(), Params.end(), [&](Type ParamType) {
299+
Type Substitution = Type(ParamType).subst(SubsMap);
300+
return !Substitution->isOpenedExistential() &&
301+
(Substitution->getCanonicalType() !=
302+
ParamType->getCanonicalType());
303+
});
304+
}
305+
306+
enum { ForInlining = true };
307+
/// Helper function to clone the parent function of a SILDebugScope if
308+
/// necessary when inlining said function into a new generic context.
309+
/// \param SubsMap - the substitutions of the inlining/specialization process.
310+
/// \param RemappedSig - the generic signature
311+
static SILFunction *remapParentFunction(SILModule &M,
312+
SILFunction *ParentFunction,
313+
SubstitutionMap SubsMap,
314+
GenericSignature *RemappedSig,
315+
bool ForInlining = false) {
316+
// If the original, non-inlined version of the function had no generic
317+
// environment, there is no need to remap it.
318+
auto *OriginalEnvironment = ParentFunction->getGenericEnvironment();
319+
if (!RemappedSig || !OriginalEnvironment)
320+
return ParentFunction;
321+
322+
if (SubsMap.hasArchetypes())
323+
SubsMap = SubsMap.mapReplacementTypesOutOfContext();
324+
325+
if (!substitutionsChangeGenericTypeParameters(SubsMap, RemappedSig))
326+
return ParentFunction;
327+
328+
// Clone the function with the substituted type for the debug info.
329+
Mangle::GenericSpecializationMangler Mangler(
330+
ParentFunction, SubsMap, IsNotSerialized, false, ForInlining);
331+
std::string MangledName = Mangler.mangle(RemappedSig);
332+
333+
if (ParentFunction->getName() == MangledName)
334+
return ParentFunction;
335+
if (auto *CachedFn = M.lookUpFunction(MangledName))
336+
ParentFunction = CachedFn;
337+
else {
338+
// Create a new function with this mangled name with an empty
339+
// body. There won't be any IR generated for it (hence the linkage),
340+
// but the symbol will be refered to by the debug info metadata.
341+
ParentFunction = M.getOrCreateFunction(
342+
ParentFunction->getLocation(), MangledName, SILLinkage::Shared,
343+
ParentFunction->getLoweredFunctionType(), ParentFunction->isBare(),
344+
ParentFunction->isTransparent(), ParentFunction->isSerialized(), 0,
345+
ParentFunction->isThunk(), ParentFunction->getClassSubclassScope());
346+
// Increment the ref count for the inlined function, so it doesn't
347+
// get deleted before we can emit abstract debug info for it.
348+
if (!ParentFunction->isZombie()) {
349+
ParentFunction->setInlined();
350+
// If the function was newly created with an empty body mark it as
351+
// undead.
352+
if (ParentFunction->empty()) {
353+
M.eraseFunction(ParentFunction);
354+
ParentFunction->setGenericEnvironment(OriginalEnvironment);
355+
}
356+
}
357+
}
358+
return ParentFunction;
359+
}
360+
282361
/// The Swift module that the cloned function belongs to.
283362
ModuleDecl *SwiftMod;
284363
/// The substitutions list for the specialization.
@@ -289,7 +368,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
289368
SILFunction &Original;
290369
/// True, if used for inlining.
291370
bool Inlining;
292-
};
371+
};
293372

294373
} // end namespace swift
295374

include/swift/SILOptimizer/Utils/GenericCloner.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {
3434
IsSerialized_t Serialized;
3535
const ReabstractionInfo &ReInfo;
3636
CloneCollector::CallbackType Callback;
37+
llvm::SmallDenseMap<const SILDebugScope *, const SILDebugScope *, 8>
38+
RemappedScopeCache;
3739

3840
public:
3941
friend class SILCloner<GenericCloner>;
@@ -90,6 +92,9 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {
9092
/// by initCloned.
9193
void populateCloned();
9294
SILFunction *getCloned() { return &getBuilder().getFunction(); }
95+
96+
const SILDebugScope *remapScope(const SILDebugScope *DS);
97+
9398
};
9499

95100
} // end namespace swift

include/swift/SILOptimizer/Utils/SpecializationMangler.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ class SpecializationMangler : public Mangle::ASTMangler {
4848
protected:
4949
SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized,
5050
SILFunction *F)
51-
: Pass(P), Serialized(Serialized), Function(F), ArgOpBuffer(ArgOpStorage) {}
51+
: Pass(P), Serialized(Serialized), Function(F),
52+
ArgOpBuffer(ArgOpStorage) {}
5253

5354
SILFunction *getFunction() const { return Function; }
5455

@@ -67,17 +68,17 @@ class GenericSpecializationMangler : public SpecializationMangler {
6768

6869
SubstitutionMap SubMap;
6970
bool isReAbstracted;
71+
bool isInlined;
7072

7173
public:
72-
73-
GenericSpecializationMangler(SILFunction *F,
74-
SubstitutionMap SubMap,
75-
IsSerialized_t Serialized,
76-
bool isReAbstracted)
77-
: SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F),
78-
SubMap(SubMap), isReAbstracted(isReAbstracted) {}
79-
80-
std::string mangle();
74+
GenericSpecializationMangler(SILFunction *F, SubstitutionMap SubMap,
75+
IsSerialized_t Serialized, bool isReAbstracted,
76+
bool isInlined = false)
77+
: SpecializationMangler(SpecializationPass::GenericSpecializer,
78+
Serialized, F),
79+
SubMap(SubMap), isReAbstracted(isReAbstracted), isInlined(isInlined) {}
80+
81+
std::string mangle(GenericSignature *Sig = nullptr);
8182
};
8283

8384
class PartialSpecializationMangler : public SpecializationMangler {
@@ -88,10 +89,10 @@ class PartialSpecializationMangler : public SpecializationMangler {
8889
public:
8990
PartialSpecializationMangler(SILFunction *F,
9091
CanSILFunctionType SpecializedFnTy,
91-
IsSerialized_t Serialized,
92-
bool isReAbstracted)
93-
: SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F),
94-
SpecializedFnTy(SpecializedFnTy), isReAbstracted(isReAbstracted) {}
92+
IsSerialized_t Serialized, bool isReAbstracted)
93+
: SpecializationMangler(SpecializationPass::GenericSpecializer,
94+
Serialized, F),
95+
SpecializedFnTy(SpecializedFnTy), isReAbstracted(isReAbstracted) {}
9596

9697
std::string mangle();
9798
};

lib/Demangling/Demangler.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,11 +1731,13 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
17311731
Thunk = addChild(Thunk, popNode(Node::Kind::Type));
17321732
return addChild(Thunk, Ty2);
17331733
}
1734-
case'g':
1734+
case 'g':
17351735
return demangleGenericSpecialization(Node::Kind::GenericSpecialization);
1736-
case'G':
1736+
case 'G':
17371737
return demangleGenericSpecialization(Node::Kind::
17381738
GenericSpecializationNotReAbstracted);
1739+
case 'i':
1740+
return demangleGenericSpecialization(Node::Kind::InlinedGenericFunction);
17391741
case'p': {
17401742
NodePointer Spec = demangleSpecAttributes(Node::Kind::
17411743
GenericPartialSpecialization);
@@ -1866,7 +1868,8 @@ NodePointer Demangler::demangleGenericSpecialization(Node::Kind SpecKind) {
18661868
if (!TyList)
18671869
return nullptr;
18681870
for (NodePointer Ty : *TyList) {
1869-
Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty), *this);
1871+
Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty),
1872+
*this);
18701873
}
18711874
return Spec;
18721875
}

lib/Demangling/NodePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class NodePrinter {
351351
case Node::Kind::GenericSpecialization:
352352
case Node::Kind::GenericSpecializationNotReAbstracted:
353353
case Node::Kind::GenericSpecializationParam:
354+
case Node::Kind::InlinedGenericFunction:
354355
case Node::Kind::GenericTypeMetadataPattern:
355356
case Node::Kind::Getter:
356357
case Node::Kind::Global:
@@ -1181,6 +1182,9 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
11811182
case Node::Kind::GenericSpecializationNotReAbstracted:
11821183
printSpecializationPrefix(Node, "generic not re-abstracted specialization");
11831184
return nullptr;
1185+
case Node::Kind::InlinedGenericFunction:
1186+
printSpecializationPrefix(Node, "inlined generic function");
1187+
return nullptr;
11841188
case Node::Kind::SpecializationIsFragile:
11851189
Printer << "preserving fragile attribute";
11861190
return nullptr;

lib/Demangling/OldRemangler.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ void Remangler::mangleGenericSpecialization(Node *node) {
534534
// Start another mangled name.
535535
Out << "__T";
536536
}
537+
537538
void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
538539
Out << "TSr";
539540
mangleChildNodes(node); // GenericSpecializationParams
@@ -545,6 +546,17 @@ void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
545546
Out << "__T";
546547
}
547548

549+
void Remangler::mangleInlinedGenericFunction(Node *node) {
550+
Out << "TSi";
551+
mangleChildNodes(node); // GenericSpecializationParams
552+
553+
// Specializations are just prepended to already-mangled names.
554+
resetSubstitutions();
555+
556+
// Start another mangled name.
557+
Out << "__T";
558+
}
559+
548560
void Remangler::mangleGenericPartialSpecialization(Node *node) {
549561
unreachable("todo");
550562
}

lib/Demangling/Remangler.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,8 +1122,20 @@ void Remangler::mangleGenericSpecialization(Node *node) {
11221122
}
11231123
assert(!FirstParam && "generic specialization with no substitutions");
11241124

1125-
Buffer << (node->getKind() ==
1126-
Node::Kind::GenericSpecializationNotReAbstracted ? "TG" : "Tg");
1125+
switch (node->getKind()) {
1126+
case Node::Kind::GenericSpecialization:
1127+
Buffer << "Tg";
1128+
break;
1129+
case Node::Kind::GenericSpecializationNotReAbstracted:
1130+
Buffer << "TG";
1131+
break;
1132+
case Node::Kind::InlinedGenericFunction:
1133+
Buffer << "Ti";
1134+
break;
1135+
default:
1136+
unreachable("unsupported node");
1137+
}
1138+
11271139
for (NodePointer Child : *node) {
11281140
if (Child->getKind() != Node::Kind::GenericSpecializationParam)
11291141
mangle(Child);
@@ -1134,6 +1146,11 @@ void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
11341146
mangleGenericSpecialization(node);
11351147
}
11361148

1149+
void Remangler::mangleInlinedGenericFunction(Node *node) {
1150+
mangleGenericSpecialization(node);
1151+
}
1152+
1153+
11371154
void Remangler::mangleGenericSpecializationParam(Node *node) {
11381155
unreachable("handled inline");
11391156
}
@@ -1161,6 +1178,7 @@ void Remangler::mangleGlobal(Node *node) {
11611178
case Node::Kind::FunctionSignatureSpecialization:
11621179
case Node::Kind::GenericSpecialization:
11631180
case Node::Kind::GenericSpecializationNotReAbstracted:
1181+
case Node::Kind::InlinedGenericFunction:
11641182
case Node::Kind::GenericPartialSpecialization:
11651183
case Node::Kind::GenericPartialSpecializationNotReAbstracted:
11661184
case Node::Kind::OutlinedBridgedMethod:

0 commit comments

Comments
 (0)