Skip to content

Commit bd8764c

Browse files
committed
Add opt remarks to Generic Specializer pass
Adds a combined API to output both debug message and optimization remarks. The previously added test partial_specialization_debug.sil ensures that it's an NFC for debug output.
1 parent 7ba352c commit bd8764c

File tree

7 files changed

+231
-19
lines changed

7 files changed

+231
-19
lines changed

include/swift/SIL/OptimizationRemark.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct Argument {
4040
SourceLoc Loc;
4141

4242
explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {}
43+
Argument(StringRef Key, StringRef Val) : Key(Key), Val(Val) {}
4344

4445
Argument(StringRef Key, int N);
4546
Argument(StringRef Key, long N);
@@ -54,6 +55,13 @@ struct Argument {
5455
/// Shorthand to insert named-value pairs.
5556
using NV = Argument;
5657

58+
/// Inserting this into a Remark indents the text when printed as a debug
59+
/// message.
60+
struct IndentDebug {
61+
explicit IndentDebug(unsigned Width) : Width(Width) {}
62+
unsigned Width;
63+
};
64+
5765
/// The base class for remarks. This can be created by optimization passed to
5866
/// report successful and unsuccessful optimizations. CRTP is used to preserve
5967
/// the underlying type encoding the remark kind in the insertion operator.
@@ -75,6 +83,9 @@ template <typename DerivedT> class Remark {
7583
/// The function for the diagnostics.
7684
SILFunction *Function;
7785

86+
/// Indentation used if this remarks is printed as a debug message.
87+
unsigned IndentDebugWidth = 0;
88+
7889
protected:
7990
Remark(StringRef Identifier, SILInstruction &I)
8091
: Identifier(Identifier), Location(I.getLoc().getSourceLoc()),
@@ -91,11 +102,17 @@ template <typename DerivedT> class Remark {
91102
return *static_cast<DerivedT *>(this);
92103
}
93104

105+
DerivedT &operator<<(IndentDebug ID) {
106+
IndentDebugWidth = ID.Width;
107+
return *static_cast<DerivedT *>(this);
108+
}
109+
94110
StringRef getPassName() const { return PassName; }
95111
StringRef getIdentifier() const { return Identifier; }
96112
SILFunction *getFunction() const { return Function; }
97113
SourceLoc getLocation() const { return Location; }
98114
std::string getMsg() const;
115+
std::string getDebugMsg() const;
99116
Remark<DerivedT> &getRemark() { return *this; }
100117
SmallVector<Argument, 4> &getArgs() { return Args; }
101118

@@ -119,8 +136,11 @@ class Emitter {
119136
bool PassedEnabled;
120137
bool MissedEnabled;
121138

139+
// Making these non-generic allows out-of-line definition.
122140
void emit(const RemarkPassed &R);
123141
void emit(const RemarkMissed &R);
142+
static void emitDebug(const RemarkPassed &R);
143+
static void emitDebug(const RemarkMissed &R);
124144

125145
template <typename RemarkT> bool isEnabled();
126146

@@ -140,8 +160,38 @@ class Emitter {
140160
emit(R);
141161
}
142162
}
163+
164+
/// Emit an optimization remark or debug message.
165+
template <typename T>
166+
static void emitOrDebug(const char *PassName, Emitter *ORE, T RemarkBuilder,
167+
decltype(RemarkBuilder()) * = nullptr) {
168+
using RemarkT = decltype(RemarkBuilder());
169+
// Avoid building the remark unless remarks are enabled.
170+
bool EmitRemark =
171+
ORE && (ORE->isEnabled<RemarkT>() || ORE->Module.getOptRecordStream());
172+
// Same for DEBUG.
173+
bool EmitDebug = false
174+
#ifndef _NDEBUG
175+
|| (llvm::DebugFlag && llvm::isCurrentDebugType(PassName));
176+
#endif // _NDEBUG
177+
178+
if (EmitRemark || EmitDebug) {
179+
auto R = RemarkBuilder();
180+
if (EmitDebug)
181+
emitDebug(R);
182+
if (EmitRemark) {
183+
// If we have ORE use the PassName that was set up with ORE. DEBUG_TYPE
184+
// may be different if a pass is calling other modules.
185+
R.setPassName(ORE->PassName);
186+
ORE->emit(R);
187+
}
188+
}
189+
}
143190
};
144191

192+
#define REMARK_OR_DEBUG(...) \
193+
OptRemark::Emitter::emitOrDebug(DEBUG_TYPE, __VA_ARGS__)
194+
145195
template <> inline bool Emitter::isEnabled<RemarkMissed>() {
146196
return MissedEnabled;
147197
}

include/swift/SILOptimizer/Utils/Generics.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ namespace swift {
2929

3030
class FunctionSignaturePartialSpecializer;
3131

32+
namespace OptRemark {
33+
class Emitter;
34+
} // namespace OptRemark
35+
3236
/// Tries to specialize an \p Apply of a generic function. It can be a full
3337
/// apply site or a partial apply.
3438
/// Replaced and now dead instructions are returned in \p DeadApplies.
@@ -38,7 +42,8 @@ class FunctionSignaturePartialSpecializer;
3842
/// This is the top-level entry point for specializing an existing call site.
3943
void trySpecializeApplyOfGeneric(
4044
ApplySite Apply, DeadInstructionSet &DeadApplies,
41-
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);
45+
llvm::SmallVectorImpl<SILFunction *> &NewFunctions,
46+
OptRemark::Emitter &ORE);
4247

4348
/// Helper class to describe re-abstraction of function parameters done during
4449
/// specialization.
@@ -117,7 +122,8 @@ class ReabstractionInfo {
117122

118123
void createSubstitutedAndSpecializedTypes();
119124
bool prepareAndCheck(ApplySite Apply, SILFunction *Callee,
120-
SubstitutionList ParamSubs);
125+
SubstitutionList ParamSubs,
126+
OptRemark::Emitter *ORE = nullptr);
121127
void performFullSpecializationPreparation(SILFunction *Callee,
122128
SubstitutionList ParamSubs);
123129
void performPartialSpecializationPreparation(SILFunction *Caller,
@@ -134,7 +140,8 @@ class ReabstractionInfo {
134140
/// invalid type.
135141
ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
136142
SubstitutionList ParamSubs,
137-
bool ConvertIndirectToDirect = true);
143+
bool ConvertIndirectToDirect = true,
144+
OptRemark::Emitter *ORE = nullptr);
138145

139146
/// Constructs the ReabstractionInfo for generic function \p Callee with
140147
/// additional requirements. Requirements may contain new layout,

lib/SIL/OptimizationRemark.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ template <typename DerivedT> std::string Remark<DerivedT>::getMsg() const {
6363
return OS.str();
6464
}
6565

66+
template <typename DerivedT> std::string Remark<DerivedT>::getDebugMsg() const {
67+
std::string Str;
68+
llvm::raw_string_ostream OS(Str);
69+
70+
if (IndentDebugWidth)
71+
OS << std::string(" ", IndentDebugWidth);
72+
73+
for (const Argument &Arg : Args)
74+
OS << Arg.Val;
75+
76+
OS << "\n";
77+
return OS.str();
78+
}
79+
6680
Emitter::Emitter(StringRef PassName, SILModule &M)
6781
: Module(M), PassName(PassName),
6882
PassedEnabled(
@@ -94,6 +108,14 @@ void Emitter::emit(const RemarkMissed &R) {
94108
emitRemark(Module, R, diag::opt_remark_missed, isEnabled<RemarkMissed>());
95109
}
96110

111+
void Emitter::emitDebug(const RemarkPassed &R) {
112+
llvm::dbgs() << R.getDebugMsg();
113+
}
114+
115+
void Emitter::emitDebug(const RemarkMissed &R) {
116+
llvm::dbgs() << R.getDebugMsg();
117+
}
118+
97119
namespace llvm {
98120
namespace yaml {
99121

lib/SILOptimizer/Transforms/GenericSpecializer.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#define DEBUG_TYPE "sil-generic-specializer"
1919

20+
#include "swift/SIL/OptimizationRemark.h"
2021
#include "swift/SIL/SILFunction.h"
2122
#include "swift/SIL/SILInstruction.h"
2223
#include "swift/SILOptimizer/Utils/Generics.h"
@@ -49,6 +50,7 @@ class GenericSpecializer : public SILFunctionTransform {
4950
bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
5051
DeadInstructionSet DeadApplies;
5152
llvm::SmallSetVector<SILInstruction *, 8> Applies;
53+
OptRemark::Emitter ORE(DEBUG_TYPE, F.getModule());
5254

5355
bool Changed = false;
5456
for (auto &BB : F) {
@@ -67,8 +69,17 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
6769
continue;
6870

6971
auto *Callee = Apply.getReferencedFunction();
70-
if (!Callee || !Callee->isDefinition())
72+
if (!Callee)
7173
continue;
74+
if (!Callee->isDefinition()) {
75+
ORE.emit([&]() {
76+
using namespace OptRemark;
77+
return RemarkMissed("NoDef", *I)
78+
<< "Unable to specialize generic function "
79+
<< NV("Callee", Callee) << " since definition is not visible";
80+
});
81+
continue;
82+
}
7283

7384
Applies.insert(Apply.getInstruction());
7485
}
@@ -87,7 +98,7 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
8798
// We have a call that can potentially be specialized, so
8899
// attempt to do so.
89100
llvm::SmallVector<SILFunction *, 2> NewFunctions;
90-
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions);
101+
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions, ORE);
91102

92103
// Remove all the now-dead applies. We must do this immediately
93104
// rather than defer it in order to avoid problems with cloning

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/TypeMatcher.h"
1919
#include "swift/Basic/Statistic.h"
2020
#include "swift/SIL/DebugUtils.h"
21+
#include "swift/SIL/OptimizationRemark.h"
2122
#include "swift/SILOptimizer/Utils/GenericCloner.h"
2223
#include "swift/SILOptimizer/Utils/Local.h"
2324
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
@@ -368,7 +369,8 @@ static bool shouldNotSpecializeCallee(SILFunction *Callee,
368369
/// Returns false, if the current function cannot be specialized.
369370
/// Returns true otherwise.
370371
bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
371-
SubstitutionList ParamSubs) {
372+
SubstitutionList ParamSubs,
373+
OptRemark::Emitter *ORE) {
372374
if (shouldNotSpecializeCallee(Callee))
373375
return false;
374376

@@ -387,6 +389,7 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
387389
if (CalleeGenericSig)
388390
InterfaceSubs = CalleeGenericSig->getSubstitutionMap(ParamSubs);
389391

392+
using namespace OptRemark;
390393
// We do not support partial specialization.
391394
if (!EnablePartialSpecialization && InterfaceSubs.hasArchetypes()) {
392395
DEBUG(llvm::dbgs() << " Partial specialization is not supported.\n");
@@ -396,7 +399,10 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
396399

397400
// Perform some checks to see if we need to bail.
398401
if (InterfaceSubs.hasDynamicSelf()) {
399-
DEBUG(llvm::dbgs() << " Cannot specialize with dynamic self.\n");
402+
REMARK_OR_DEBUG(ORE, [&]() {
403+
return RemarkMissed("DynamicSelf", *Apply.getInstruction())
404+
<< IndentDebug(4) << "Cannot specialize with dynamic self";
405+
});
400406
return false;
401407
}
402408

@@ -406,8 +412,11 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
406412
for (auto Sub : ParamSubs) {
407413
auto Replacement = Sub.getReplacement();
408414
if (isTypeTooComplex(Replacement)) {
409-
DEBUG(llvm::dbgs()
410-
<< " Cannot specialize because the generic type is too deep.\n");
415+
REMARK_OR_DEBUG(ORE, [&]() {
416+
return RemarkMissed("TypeTooDeep", *Apply.getInstruction())
417+
<< IndentDebug(4)
418+
<< "Cannot specialize because the generic type is too deep";
419+
});
411420
NumPreventedTooComplexGenericSpecializations++;
412421
return false;
413422
}
@@ -481,11 +490,14 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
481490
// Check if specializing this call site would create in an infinite generic
482491
// specialization loop.
483492
if (createsInfiniteSpecializationLoop(Apply)) {
484-
DEBUG(llvm::dbgs() << " Generic specialization is not supported if "
485-
"it would result in a generic specialization of "
486-
"infinite depth.\n");
487-
DEBUG(llvm::dbgs() << "Callee " << Callee->getName()
488-
<< " occurs multiple times on the call chain\n");
493+
REMARK_OR_DEBUG(ORE, [&]() {
494+
return RemarkMissed("SpecializationLoop", *Apply.getInstruction())
495+
<< IndentDebug(4)
496+
<< "Generic specialization is not supported if it would result in "
497+
"a generic specialization of infinite depth. Callee "
498+
<< NV("Callee", Callee)
499+
<< " occurs multiple times on the call chain";
500+
});
489501
if (PrintGenericSpecializationLoops)
490502
llvm::errs() << "Detected and prevented an infinite "
491503
"generic specialization loop for callee: "
@@ -505,8 +517,9 @@ bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee,
505517

506518
ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
507519
ArrayRef<Substitution> ParamSubs,
508-
bool ConvertIndirectToDirect) {
509-
if (!prepareAndCheck(Apply, Callee, ParamSubs))
520+
bool ConvertIndirectToDirect,
521+
OptRemark::Emitter *ORE) {
522+
if (!prepareAndCheck(Apply, Callee, ParamSubs, ORE))
510523
return;
511524

512525
this->ConvertIndirectToDirect = ConvertIndirectToDirect;
@@ -2252,7 +2265,8 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
22522265

22532266
void swift::trySpecializeApplyOfGeneric(
22542267
ApplySite Apply, DeadInstructionSet &DeadApplies,
2255-
llvm::SmallVectorImpl<SILFunction *> &NewFunctions) {
2268+
llvm::SmallVectorImpl<SILFunction *> &NewFunctions,
2269+
OptRemark::Emitter &ORE) {
22562270
assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!");
22572271
auto *F = Apply.getFunction();
22582272
auto *RefF = cast<FunctionRefInst>(Apply.getCallee())->getReferencedFunction();
@@ -2286,7 +2300,8 @@ void swift::trySpecializeApplyOfGeneric(
22862300
if (Apply.getModule().isOptimizedOnoneSupportModule())
22872301
Serialized = IsNotSerialized;
22882302

2289-
ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutions());
2303+
ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutions(),
2304+
/*ConvertIndirectToDirect=*/true, &ORE);
22902305
if (!ReInfo.canBeSpecialized())
22912306
return;
22922307

@@ -2348,6 +2363,18 @@ void swift::trySpecializeApplyOfGeneric(
23482363
NewFunctions.push_back(SpecializedF);
23492364
}
23502365

2366+
ORE.emit([&]() {
2367+
std::string Str;
2368+
llvm::raw_string_ostream OS(Str);
2369+
SpecializedF->getLoweredFunctionType().print(
2370+
OS, PrintOptions::printQuickHelpDeclaration());
2371+
2372+
using namespace OptRemark;
2373+
return RemarkPassed("Specialized", *Apply.getInstruction())
2374+
<< "Specialized function " << NV("Function", RefF) << " with type "
2375+
<< NV("FuncType", OS.str());
2376+
});
2377+
23512378
assert(ReInfo.getSpecializedType()
23522379
== SpecializedF->getLoweredFunctionType() &&
23532380
"Previously specialized function does not match expected type.");

0 commit comments

Comments
 (0)