Skip to content

Commit 012cc4a

Browse files
authored
Merge pull request #12933 from anemet/opt-remark-generic-specialization
2 parents 925d6f6 + bd8764c commit 012cc4a

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
}
@@ -90,7 +101,7 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
90101
// We have a call that can potentially be specialized, so
91102
// attempt to do so.
92103
llvm::SmallVector<SILFunction *, 2> NewFunctions;
93-
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions);
104+
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions, ORE);
94105

95106
// Remove all the now-dead applies. We must do this immediately
96107
// 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"
@@ -362,7 +363,8 @@ static bool shouldNotSpecializeCallee(SILFunction *Callee,
362363
/// Returns false, if the current function cannot be specialized.
363364
/// Returns true otherwise.
364365
bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
365-
SubstitutionList ParamSubs) {
366+
SubstitutionList ParamSubs,
367+
OptRemark::Emitter *ORE) {
366368
if (shouldNotSpecializeCallee(Callee))
367369
return false;
368370

@@ -381,6 +383,7 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
381383
if (CalleeGenericSig)
382384
InterfaceSubs = CalleeGenericSig->getSubstitutionMap(ParamSubs);
383385

386+
using namespace OptRemark;
384387
// We do not support partial specialization.
385388
if (!EnablePartialSpecialization && InterfaceSubs.hasArchetypes()) {
386389
DEBUG(llvm::dbgs() << " Partial specialization is not supported.\n");
@@ -390,7 +393,10 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
390393

391394
// Perform some checks to see if we need to bail.
392395
if (InterfaceSubs.hasDynamicSelf()) {
393-
DEBUG(llvm::dbgs() << " Cannot specialize with dynamic self.\n");
396+
REMARK_OR_DEBUG(ORE, [&]() {
397+
return RemarkMissed("DynamicSelf", *Apply.getInstruction())
398+
<< IndentDebug(4) << "Cannot specialize with dynamic self";
399+
});
394400
return false;
395401
}
396402

@@ -400,8 +406,11 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
400406
for (auto Sub : ParamSubs) {
401407
auto Replacement = Sub.getReplacement();
402408
if (isTypeTooComplex(Replacement)) {
403-
DEBUG(llvm::dbgs()
404-
<< " Cannot specialize because the generic type is too deep.\n");
409+
REMARK_OR_DEBUG(ORE, [&]() {
410+
return RemarkMissed("TypeTooDeep", *Apply.getInstruction())
411+
<< IndentDebug(4)
412+
<< "Cannot specialize because the generic type is too deep";
413+
});
405414
NumPreventedTooComplexGenericSpecializations++;
406415
return false;
407416
}
@@ -475,11 +484,14 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
475484
// Check if specializing this call site would create in an infinite generic
476485
// specialization loop.
477486
if (createsInfiniteSpecializationLoop(Apply)) {
478-
DEBUG(llvm::dbgs() << " Generic specialization is not supported if "
479-
"it would result in a generic specialization of "
480-
"infinite depth.\n");
481-
DEBUG(llvm::dbgs() << "Callee " << Callee->getName()
482-
<< " occurs multiple times on the call chain\n");
487+
REMARK_OR_DEBUG(ORE, [&]() {
488+
return RemarkMissed("SpecializationLoop", *Apply.getInstruction())
489+
<< IndentDebug(4)
490+
<< "Generic specialization is not supported if it would result in "
491+
"a generic specialization of infinite depth. Callee "
492+
<< NV("Callee", Callee)
493+
<< " occurs multiple times on the call chain";
494+
});
483495
if (PrintGenericSpecializationLoops)
484496
llvm::errs() << "Detected and prevented an infinite "
485497
"generic specialization loop for callee: "
@@ -499,8 +511,9 @@ bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee,
499511

500512
ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
501513
ArrayRef<Substitution> ParamSubs,
502-
bool ConvertIndirectToDirect) {
503-
if (!prepareAndCheck(Apply, Callee, ParamSubs))
514+
bool ConvertIndirectToDirect,
515+
OptRemark::Emitter *ORE) {
516+
if (!prepareAndCheck(Apply, Callee, ParamSubs, ORE))
504517
return;
505518

506519
this->ConvertIndirectToDirect = ConvertIndirectToDirect;
@@ -2241,7 +2254,8 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
22412254

22422255
void swift::trySpecializeApplyOfGeneric(
22432256
ApplySite Apply, DeadInstructionSet &DeadApplies,
2244-
llvm::SmallVectorImpl<SILFunction *> &NewFunctions) {
2257+
llvm::SmallVectorImpl<SILFunction *> &NewFunctions,
2258+
OptRemark::Emitter &ORE) {
22452259
assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!");
22462260
auto *F = Apply.getFunction();
22472261
auto *RefF = cast<FunctionRefInst>(Apply.getCallee())->getReferencedFunction();
@@ -2275,7 +2289,8 @@ void swift::trySpecializeApplyOfGeneric(
22752289
if (Apply.getModule().isOptimizedOnoneSupportModule())
22762290
Serialized = IsNotSerialized;
22772291

2278-
ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutions());
2292+
ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutions(),
2293+
/*ConvertIndirectToDirect=*/true, &ORE);
22792294
if (!ReInfo.canBeSpecialized())
22802295
return;
22812296

@@ -2337,6 +2352,18 @@ void swift::trySpecializeApplyOfGeneric(
23372352
NewFunctions.push_back(SpecializedF);
23382353
}
23392354

2355+
ORE.emit([&]() {
2356+
std::string Str;
2357+
llvm::raw_string_ostream OS(Str);
2358+
SpecializedF->getLoweredFunctionType().print(
2359+
OS, PrintOptions::printQuickHelpDeclaration());
2360+
2361+
using namespace OptRemark;
2362+
return RemarkPassed("Specialized", *Apply.getInstruction())
2363+
<< "Specialized function " << NV("Function", RefF) << " with type "
2364+
<< NV("FuncType", OS.str());
2365+
});
2366+
23402367
assert(ReInfo.getSpecializedType()
23412368
== SpecializedF->getLoweredFunctionType() &&
23422369
"Previously specialized function does not match expected type.");

0 commit comments

Comments
 (0)