@@ -26,6 +26,41 @@ using namespace swift;
26
26
27
27
namespace {
28
28
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
+
29
64
// / Issues performance diagnostics for functions which are annotated with
30
65
// / performance annotations, like @_noLocks, @_noAllocation.
31
66
// /
@@ -156,6 +191,9 @@ bool PerformanceDiagnostics::visitFunction(SILFunction *function,
156
191
if (visitCallee (&inst, bca->getCalleeList (as), perfConstr, parentLoc))
157
192
return true ;
158
193
} else if (auto *bi = dyn_cast<BuiltinInst>(&inst)) {
194
+ PrettyStackTracePerformanceDiagnostics stackTrace (
195
+ " visitFunction::BuiltinInst (once, once with context)" , &inst);
196
+
159
197
switch (bi->getBuiltinInfo ().ID ) {
160
198
case BuiltinValueKind::Once:
161
199
case BuiltinValueKind::OnceWithContext:
@@ -226,6 +264,9 @@ bool PerformanceDiagnostics::checkClosureValue(SILValue closure,
226
264
// the call site.
227
265
return false ;
228
266
} else {
267
+ PrettyStackTracePerformanceDiagnostics stackTrace (
268
+ " validating closure (function ref, callee) - unkown callee" , callInst);
269
+
229
270
diagnose (LocWithParent (callInst->getLoc ().getSourceLoc (), parentLoc), diag::performance_unknown_callees);
230
271
return true ;
231
272
}
@@ -249,6 +290,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
249
290
loc = parentLoc;
250
291
251
292
if (callees.isIncomplete ()) {
293
+ PrettyStackTracePerformanceDiagnostics stackTrace (" incomplete" , callInst);
294
+
252
295
diagnose (*loc, diag::performance_unknown_callees);
253
296
return true ;
254
297
}
@@ -263,6 +306,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
263
306
return false ;
264
307
265
308
if (!callee->isDefinition ()) {
309
+ PrettyStackTracePerformanceDiagnostics stackTrace (" incomplete" , callInst);
310
+
266
311
diagnose (*loc, diag::performance_callee_unavailable);
267
312
return true ;
268
313
}
@@ -310,6 +355,8 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
310
355
if (impact & RuntimeEffect::Casting) {
311
356
// TODO: be more specific on casting.
312
357
// E.g. distinguish locking and allocating dynamic casts, etc.
358
+ PrettyStackTracePerformanceDiagnostics stackTrace (" bad cast" , inst);
359
+
313
360
diagnose (loc, diag::performance_dynamic_casting);
314
361
return true ;
315
362
}
@@ -319,21 +366,30 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
319
366
320
367
// Try to give a good error message by looking which type of code it is.
321
368
switch (inst->getKind ()) {
322
- case SILInstructionKind::KeyPathInst:
369
+ case SILInstructionKind::KeyPathInst: {
370
+ PrettyStackTracePerformanceDiagnostics stackTrace (" key path" , inst);
323
371
diagnose (loc, diag::performance_metadata, " using KeyPath" );
324
372
break ;
373
+ }
325
374
case SILInstructionKind::AllocGlobalInst:
326
- case SILInstructionKind::GlobalValueInst:
375
+ case SILInstructionKind::GlobalValueInst: {
376
+ PrettyStackTracePerformanceDiagnostics stackTrace (
377
+ " AllocGlobalInst | GlobalValueInst" , inst);
327
378
diagnose (loc, diag::performance_metadata, " global or static variables" );
328
379
break ;
380
+ }
329
381
case SILInstructionKind::PartialApplyInst: {
382
+ PrettyStackTracePerformanceDiagnostics stackTrace (
383
+ " PartialApplyInst" , inst);
330
384
diagnose (loc, diag::performance_metadata,
331
385
" generic closures or local functions" );
332
386
break ;
333
387
}
334
388
case SILInstructionKind::ApplyInst:
335
389
case SILInstructionKind::TryApplyInst:
336
390
case SILInstructionKind::BeginApplyInst: {
391
+ PrettyStackTracePerformanceDiagnostics stackTrace (
392
+ " ApplyInst | TryApplyInst | BeginApplyInst" , inst);
337
393
diagnose (loc, diag::performance_metadata, " generic function calls" );
338
394
break ;
339
395
}
@@ -345,16 +401,23 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
345
401
// We didn't recognize the instruction, so try to give an error message
346
402
// based on the involved type.
347
403
if (impactType) {
404
+ PrettyStackTracePerformanceDiagnostics stackTrace (
405
+ " impactType (unrecognized instruction)" , inst);
348
406
diagnose (loc, diag::performance_metadata_type, impactType.getASTType ());
349
407
break ;
350
408
}
351
409
// The default error message.
410
+ PrettyStackTracePerformanceDiagnostics stackTrace (
411
+ " default error (fallthrough, unkown inst)" , inst);
352
412
diagnose (loc, diag::performance_metadata, " this code pattern" );
353
413
break ;
354
414
}
355
415
return true ;
356
416
}
357
417
if (impact & RuntimeEffect::Allocating) {
418
+ PrettyStackTracePerformanceDiagnostics stackTrace (
419
+ " found allocation effect" , inst);
420
+
358
421
switch (inst->getKind ()) {
359
422
case SILInstructionKind::BeginApplyInst:
360
423
// Not all begin_applys necessarily allocate. But it's difficult to
@@ -375,6 +438,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
375
438
return true ;
376
439
}
377
440
if (impact & RuntimeEffect::Deallocating) {
441
+ PrettyStackTracePerformanceDiagnostics stackTrace (
442
+ " found deallocation effect" , inst);
443
+
378
444
if (impactType) {
379
445
switch (inst->getKind ()) {
380
446
case SILInstructionKind::StoreInst:
@@ -395,6 +461,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
395
461
return true ;
396
462
}
397
463
if (impact & RuntimeEffect::ObjectiveC) {
464
+ PrettyStackTracePerformanceDiagnostics stackTrace (
465
+ " found objc effect" , inst);
466
+
398
467
diagnose (loc, diag::performance_objectivec);
399
468
return true ;
400
469
}
@@ -403,6 +472,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
403
472
return false ;
404
473
405
474
// Handle locking-only effects.
475
+
476
+ PrettyStackTracePerformanceDiagnostics stackTrace (
477
+ " found locking or ref counting effect" , inst);
406
478
407
479
if (impact & RuntimeEffect::Locking) {
408
480
if (inst->getFunction ()->isGlobalInit ()) {
@@ -447,7 +519,7 @@ void PerformanceDiagnostics::checkNonAnnotatedFunction(SILFunction *function) {
447
519
}
448
520
}
449
521
450
- void PerformanceDiagnostics::diagnose (LocWithParent loc, Diagnostic &&D) {
522
+ void PerformanceDiagnostics::diagnose (LocWithParent loc, Diagnostic &&D) {
451
523
// Start with a valid location in the call tree.
452
524
LocWithParent *validLoc = &loc;
453
525
while (!validLoc->loc .isValid () && validLoc->parent ) {
@@ -484,6 +556,9 @@ class PerformanceDiagnosticsPass : public SILModuleTransform {
484
556
// Check that @_section, @_silgen_name is only on constant globals
485
557
for (SILGlobalVariable &g : module ->getSILGlobals ()) {
486
558
if (!g.getStaticInitializerValue () && g.mustBeInitializedStatically ()) {
559
+ PrettyStackTraceSILGlobal stackTrace (
560
+ " global inst" , &g);
561
+
487
562
auto *decl = g.getDecl ();
488
563
if (g.getSectionAttr ()) {
489
564
module ->getASTContext ().Diags .diagnose (
0 commit comments