@@ -26,6 +26,41 @@ using namespace swift;
2626
2727namespace {
2828
29+ class PrettyStackTracePerformanceDiagnostics
30+ : public llvm::PrettyStackTraceEntry {
31+ const SILNode *node;
32+ const char *action;
33+
34+ public:
35+ PrettyStackTracePerformanceDiagnostics (const char *action, SILNodePointer node)
36+ : node(node), action(action) {}
37+
38+ virtual void print (llvm::raw_ostream &OS) const override {
39+ OS << " While " << action << " -- visiting node " ;
40+ node->print (OS);
41+
42+ if (auto inst = dyn_cast<SILInstruction>(node)) {
43+ OS << " While visiting instruction in function " ;
44+ inst->getFunction ()->print (OS);
45+ }
46+ }
47+ };
48+
49+ class PrettyStackTraceSILGlobal
50+ : public llvm::PrettyStackTraceEntry {
51+ const SILGlobalVariable *node;
52+ const char *action;
53+
54+ public:
55+ PrettyStackTraceSILGlobal (const char *action, SILGlobalVariable *node)
56+ : node(node), action(action) {}
57+
58+ virtual void print (llvm::raw_ostream &OS) const override {
59+ OS << " While " << action << " -- visiting node " ;
60+ node->print (OS);
61+ }
62+ };
63+
2964// / Issues performance diagnostics for functions which are annotated with
3065// / performance annotations, like @_noLocks, @_noAllocation.
3166// /
@@ -156,6 +191,9 @@ bool PerformanceDiagnostics::visitFunction(SILFunction *function,
156191 if (visitCallee (&inst, bca->getCalleeList (as), perfConstr, parentLoc))
157192 return true ;
158193 } else if (auto *bi = dyn_cast<BuiltinInst>(&inst)) {
194+ PrettyStackTracePerformanceDiagnostics stackTrace (
195+ " visitFunction::BuiltinInst (once, once with context)" , &inst);
196+
159197 switch (bi->getBuiltinInfo ().ID ) {
160198 case BuiltinValueKind::Once:
161199 case BuiltinValueKind::OnceWithContext:
@@ -226,6 +264,9 @@ bool PerformanceDiagnostics::checkClosureValue(SILValue closure,
226264 // the call site.
227265 return false ;
228266 } else {
267+ PrettyStackTracePerformanceDiagnostics stackTrace (
268+ " validating closure (function ref, callee) - unkown callee" , callInst);
269+
229270 diagnose (LocWithParent (callInst->getLoc ().getSourceLoc (), parentLoc), diag::performance_unknown_callees);
230271 return true ;
231272 }
@@ -249,6 +290,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
249290 loc = parentLoc;
250291
251292 if (callees.isIncomplete ()) {
293+ PrettyStackTracePerformanceDiagnostics stackTrace (" incomplete" , callInst);
294+
252295 diagnose (*loc, diag::performance_unknown_callees);
253296 return true ;
254297 }
@@ -263,6 +306,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
263306 return false ;
264307
265308 if (!callee->isDefinition ()) {
309+ PrettyStackTracePerformanceDiagnostics stackTrace (" incomplete" , callInst);
310+
266311 diagnose (*loc, diag::performance_callee_unavailable);
267312 return true ;
268313 }
@@ -310,6 +355,8 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
310355 if (impact & RuntimeEffect::Casting) {
311356 // TODO: be more specific on casting.
312357 // E.g. distinguish locking and allocating dynamic casts, etc.
358+ PrettyStackTracePerformanceDiagnostics stackTrace (" bad cast" , inst);
359+
313360 diagnose (loc, diag::performance_dynamic_casting);
314361 return true ;
315362 }
@@ -319,21 +366,30 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
319366
320367 // Try to give a good error message by looking which type of code it is.
321368 switch (inst->getKind ()) {
322- case SILInstructionKind::KeyPathInst:
369+ case SILInstructionKind::KeyPathInst: {
370+ PrettyStackTracePerformanceDiagnostics stackTrace (" key path" , inst);
323371 diagnose (loc, diag::performance_metadata, " using KeyPath" );
324372 break ;
373+ }
325374 case SILInstructionKind::AllocGlobalInst:
326- case SILInstructionKind::GlobalValueInst:
375+ case SILInstructionKind::GlobalValueInst: {
376+ PrettyStackTracePerformanceDiagnostics stackTrace (
377+ " AllocGlobalInst | GlobalValueInst" , inst);
327378 diagnose (loc, diag::performance_metadata, " global or static variables" );
328379 break ;
380+ }
329381 case SILInstructionKind::PartialApplyInst: {
382+ PrettyStackTracePerformanceDiagnostics stackTrace (
383+ " PartialApplyInst" , inst);
330384 diagnose (loc, diag::performance_metadata,
331385 " generic closures or local functions" );
332386 break ;
333387 }
334388 case SILInstructionKind::ApplyInst:
335389 case SILInstructionKind::TryApplyInst:
336390 case SILInstructionKind::BeginApplyInst: {
391+ PrettyStackTracePerformanceDiagnostics stackTrace (
392+ " ApplyInst | TryApplyInst | BeginApplyInst" , inst);
337393 diagnose (loc, diag::performance_metadata, " generic function calls" );
338394 break ;
339395 }
@@ -345,16 +401,23 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
345401 // We didn't recognize the instruction, so try to give an error message
346402 // based on the involved type.
347403 if (impactType) {
404+ PrettyStackTracePerformanceDiagnostics stackTrace (
405+ " impactType (unrecognized instruction)" , inst);
348406 diagnose (loc, diag::performance_metadata_type, impactType.getASTType ());
349407 break ;
350408 }
351409 // The default error message.
410+ PrettyStackTracePerformanceDiagnostics stackTrace (
411+ " default error (fallthrough, unkown inst)" , inst);
352412 diagnose (loc, diag::performance_metadata, " this code pattern" );
353413 break ;
354414 }
355415 return true ;
356416 }
357417 if (impact & RuntimeEffect::Allocating) {
418+ PrettyStackTracePerformanceDiagnostics stackTrace (
419+ " found allocation effect" , inst);
420+
358421 switch (inst->getKind ()) {
359422 case SILInstructionKind::BeginApplyInst:
360423 // Not all begin_applys necessarily allocate. But it's difficult to
@@ -375,6 +438,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
375438 return true ;
376439 }
377440 if (impact & RuntimeEffect::Deallocating) {
441+ PrettyStackTracePerformanceDiagnostics stackTrace (
442+ " found deallocation effect" , inst);
443+
378444 if (impactType) {
379445 switch (inst->getKind ()) {
380446 case SILInstructionKind::StoreInst:
@@ -395,6 +461,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
395461 return true ;
396462 }
397463 if (impact & RuntimeEffect::ObjectiveC) {
464+ PrettyStackTracePerformanceDiagnostics stackTrace (
465+ " found objc effect" , inst);
466+
398467 diagnose (loc, diag::performance_objectivec);
399468 return true ;
400469 }
@@ -403,6 +472,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
403472 return false ;
404473
405474 // Handle locking-only effects.
475+
476+ PrettyStackTracePerformanceDiagnostics stackTrace (
477+ " found locking or ref counting effect" , inst);
406478
407479 if (impact & RuntimeEffect::Locking) {
408480 if (inst->getFunction ()->isGlobalInit ()) {
@@ -447,7 +519,7 @@ void PerformanceDiagnostics::checkNonAnnotatedFunction(SILFunction *function) {
447519 }
448520}
449521
450- void PerformanceDiagnostics::diagnose (LocWithParent loc, Diagnostic &&D) {
522+ void PerformanceDiagnostics::diagnose (LocWithParent loc, Diagnostic &&D) {
451523 // Start with a valid location in the call tree.
452524 LocWithParent *validLoc = &loc;
453525 while (!validLoc->loc .isValid () && validLoc->parent ) {
@@ -484,6 +556,9 @@ class PerformanceDiagnosticsPass : public SILModuleTransform {
484556 // Check that @_section, @_silgen_name is only on constant globals
485557 for (SILGlobalVariable &g : module ->getSILGlobals ()) {
486558 if (!g.getStaticInitializerValue () && g.mustBeInitializedStatically ()) {
559+ PrettyStackTraceSILGlobal stackTrace (
560+ " global inst" , &g);
561+
487562 auto *decl = g.getDecl ();
488563 if (g.getSectionAttr ()) {
489564 module ->getASTContext ().Diags .diagnose (
0 commit comments