22
22
#include " swift/AST/Expr.h"
23
23
#include " swift/AST/Stmt.h"
24
24
#include " swift/SIL/BasicBlockUtils.h"
25
+ #include " swift/SIL/CFG.h"
25
26
#include " swift/SIL/Dominance.h"
26
27
#include " swift/SILOptimizer/PassManager/Transforms.h"
28
+ #include " llvm/ADT/BreadthFirstIterator.h"
27
29
#include " llvm/ADT/DenseSet.h"
28
30
29
31
using namespace swift ;
@@ -48,32 +50,54 @@ class YieldOnceCheck : public SILFunctionTransform {
48
50
enum YieldState { BeforeYield, AfterYield, Conflict } yieldState;
49
51
50
52
private:
51
- // The following state is maintained for emitting diagnostics.
53
+ // The following states are maintained for emitting diagnostics.
52
54
53
55
// / For AfterYield and Conflict states, this field records the yield
54
56
// / instruction that was seen while propagating the state.
55
57
SILInstruction *yieldInst;
56
58
57
- BBState (YieldState yState, SILInstruction *yieldI)
58
- : yieldState(yState), yieldInst(yieldI) {}
59
+ // / For Conflict state, these fields record the basic blocks that
60
+ // / propagated the 'AfterYield' and 'BeforeYield' states which resulted
61
+ // / in the Conflict.
62
+ SILBasicBlock *yieldingPred;
63
+ SILBasicBlock *nonYieldingPred;
64
+
65
+ BBState (YieldState yState, SILInstruction *yieldI, SILBasicBlock *yieldPred,
66
+ SILBasicBlock *noYieldPred)
67
+ : yieldState(yState), yieldInst(yieldI), yieldingPred(yieldPred),
68
+ nonYieldingPred (noYieldPred) {}
59
69
60
70
public:
61
- static BBState getInitialState () { return BBState (BeforeYield, nullptr ); }
71
+ static BBState getInitialState () {
72
+ return BBState (BeforeYield, nullptr , nullptr , nullptr );
73
+ }
62
74
63
75
static BBState getAfterYieldState (SILInstruction *yieldI) {
64
76
assert (yieldI);
65
- return BBState (AfterYield, yieldI);
77
+ return BBState (AfterYield, yieldI, nullptr , nullptr );
66
78
}
67
79
68
- static BBState getConflictState (SILInstruction *yieldI) {
69
- assert (yieldI);
70
- return BBState (Conflict, yieldI);
80
+ static BBState getConflictState (SILInstruction *yieldI,
81
+ SILBasicBlock *yieldPred,
82
+ SILBasicBlock *noYieldPred) {
83
+ assert (yieldI && yieldPred && noYieldPred);
84
+ return BBState (Conflict, yieldI, yieldPred, noYieldPred);
71
85
}
72
86
73
87
SILInstruction *getYieldInstruction () const {
74
88
assert (yieldState == AfterYield || yieldState == Conflict);
75
89
return yieldInst;
76
90
}
91
+
92
+ SILBasicBlock *getYieldingPred () {
93
+ assert (yieldState == Conflict);
94
+ return yieldingPred;
95
+ }
96
+
97
+ SILBasicBlock *getNonYieldingPred () {
98
+ assert (yieldState == Conflict);
99
+ return nonYieldingPred;
100
+ }
77
101
};
78
102
79
103
// / A structure that records an error found during the analysis along with
@@ -157,9 +181,16 @@ class YieldOnceCheck : public SILFunctionTransform {
157
181
// / \param mergeBlock the basic block that is reached with two states
158
182
// / \param oldState the previous state at the entry of the basic block
159
183
// / \param newState the current state at the entry of the basic block
184
+ // / \param newStatePred the predecessor of 'mergeBlock' that has propagated
185
+ // / the 'newState'.
186
+ // / \param bbToStateMap a map from the basic blocks visited by the analysis
187
+ // / to the BBStates in which they were seen. This is used to identify
188
+ // / blocks that propagate conflicting states when the merge results
189
+ // / in a conflict.
160
190
// / \return the new state obtained by merging the oldState with the newState
161
191
static BBState merge (SILBasicBlock *mergeBlock, BBState oldState,
162
- BBState newState) {
192
+ BBState newState, SILBasicBlock *newStatePred,
193
+ llvm::DenseMap<SILBasicBlock *, BBState> &bbToStateMap) {
163
194
auto oldYieldState = oldState.yieldState ;
164
195
auto newYieldState = newState.yieldState ;
165
196
@@ -182,11 +213,27 @@ class YieldOnceCheck : public SILFunctionTransform {
182
213
(newYieldState == BBState::BeforeYield &&
183
214
oldYieldState == BBState::AfterYield));
184
215
185
- SILInstruction *yieldInst = (newYieldState == BBState::AfterYield)
186
- ? newState.getYieldInstruction ()
187
- : oldState.getYieldInstruction ();
188
-
189
- return BBState::getConflictState (yieldInst);
216
+ // For diagnostics, find another predecessor of 'mergeBlock' that was
217
+ // previously seen by the analysis. This predecessor would have
218
+ // propagated the 'oldState'.
219
+ SILBasicBlock *oldStatePred = nullptr ;
220
+ for (auto predBB : mergeBlock->getPredecessorBlocks ()) {
221
+ if (predBB != newStatePred && bbToStateMap.count (predBB)) {
222
+ oldStatePred = predBB;
223
+ break ;
224
+ }
225
+ }
226
+ assert (oldStatePred);
227
+
228
+ if (oldState.yieldState == BBState::BeforeYield) {
229
+ return BBState::getConflictState (newState.getYieldInstruction (),
230
+ /* yieldPred */ newStatePred,
231
+ /* noYieldPred */ oldStatePred);
232
+ } else {
233
+ return BBState::getConflictState (oldState.getYieldInstruction (),
234
+ /* yieldPred */ oldStatePred,
235
+ /* noYieldPred */ newStatePred);
236
+ }
190
237
}
191
238
192
239
// / Perform a data-flow analysis to check whether there is exactly one
@@ -195,6 +242,7 @@ class YieldOnceCheck : public SILFunctionTransform {
195
242
// / the control-flow graph.
196
243
void diagnoseYieldOnceUsage (SILFunction &fun) {
197
244
llvm::DenseMap<SILBasicBlock *, BBState> bbToStateMap;
245
+
198
246
SmallVector<SILBasicBlock *, 16 > worklist;
199
247
200
248
auto *entryBB = fun.getEntryBlock ();
@@ -234,7 +282,7 @@ class YieldOnceCheck : public SILFunctionTransform {
234
282
continue ;
235
283
}
236
284
237
- emitDiagnostics (error, fun);
285
+ emitDiagnostics (error, fun, bbToStateMap );
238
286
return ;
239
287
}
240
288
@@ -255,7 +303,7 @@ class YieldOnceCheck : public SILFunctionTransform {
255
303
// previous states and propagate it if it is different from the
256
304
// old state.
257
305
const auto &oldState = insertResult.first ->second ;
258
- auto mergedState = merge (succBB, oldState, nextState);
306
+ auto mergedState = merge (succBB, oldState, nextState, bb, bbToStateMap );
259
307
260
308
if (mergedState.yieldState == oldState.yieldState )
261
309
continue ;
@@ -271,11 +319,12 @@ class YieldOnceCheck : public SILFunctionTransform {
271
319
}
272
320
273
321
if (returnBeforeYieldError.hasValue ()) {
274
- emitDiagnostics (returnBeforeYieldError.getValue (), fun);
322
+ emitDiagnostics (returnBeforeYieldError.getValue (), fun, bbToStateMap );
275
323
}
276
324
}
277
325
278
- void emitDiagnostics (YieldError &error, SILFunction &fun) {
326
+ void emitDiagnostics (YieldError &error, SILFunction &fun,
327
+ llvm::DenseMap<SILBasicBlock *, BBState> &visitedBBs) {
279
328
ASTContext &astCtx = fun.getModule ().getASTContext ();
280
329
281
330
switch (error.errorKind ) {
@@ -299,9 +348,162 @@ class YieldOnceCheck : public SILFunctionTransform {
299
348
diagnose (astCtx, error.termInst ->getLoc ().getSourceLoc (),
300
349
diag::possible_return_before_yield);
301
350
302
- // Add a note that points to the yield instruction found.
303
- auto *yieldInst = error.inState .getYieldInstruction ();
304
- diagnose (astCtx, yieldInst->getLoc ().getSourceLoc (), diag::one_yield);
351
+ // Here, the yield state of 'error' is Conflict.
352
+ auto &conflictState = error.inState ;
353
+
354
+ // Emit a note that pin points the branch construct that resulted in
355
+ // this conflict. Note that a conflict state is created at a merge block
356
+ // when along one incoming edge the analysis sees a BeforeYield state
357
+ // and along another it sees an AfterYield state.
358
+ // Also note that, by the definition of the merge operation,
359
+ // 'error.yieldingPred()' is the immediate predecessor of the merge block
360
+ // that propagates AfterYield state, and 'error.nonYieldingPred()' is
361
+ // the immediate predecessor of the merge block that propagates a
362
+ // BeforeYield state.
363
+ auto yieldPred = conflictState.getYieldingPred ();
364
+ auto noYieldPred = conflictState.getNonYieldingPred ();
365
+
366
+ // Step 1: find a branching SIL instruction where one branch has
367
+ // 'yieldPred' and another branch has 'noYieldPred'. For instance,
368
+ // in the following example, cond_br is the instruction to find.
369
+ // cond_br bb1, bb2
370
+ // bb1:
371
+ // yield resume yieldPred, unwind err
372
+ // bb2:
373
+ // br noYieldPred
374
+ // yieldPred:
375
+ // br mergePoint
376
+ // noYieldPred:
377
+ // br mergePoint
378
+ // mergePoint:
379
+ // ...
380
+ // Intuitively, the conflicting branch is the instruction where
381
+ // 'yieldPred' and 'noYieldPred' meet when traversing the CFG in the
382
+ // reverse order. More formally, the branching instruction is a
383
+ // "lowest common ancestor" of 'yieldPred' and 'noYieldPred' in the
384
+ // the DAG obtained from the CFG by ignoring back edges of loops.
385
+ //
386
+ // Note that the lowest common ancestor may not be unique in a DAG.
387
+ // But, any such ancestor could be considered as the conflicting branch as
388
+ // 'yieldPred' and 'noYieldPred' will belong to two different branches of
389
+ // every such ancestor.
390
+
391
+ // Find all transitive predecessors of 'yieldPred' that were visited
392
+ // during the analysis
393
+ SmallPtrSet<SILBasicBlock *, 8 > predecessorsOfYieldPred;
394
+ for (auto *predBB :
395
+ llvm::breadth_first<llvm::Inverse<SILBasicBlock *>>(yieldPred)) {
396
+ if (visitedBBs.count (predBB)) {
397
+ predecessorsOfYieldPred.insert (predBB);
398
+ }
399
+ }
400
+
401
+ // Find the first predecessor of 'noYieldPred' that is also a predecessor
402
+ // of 'yieldPred', in the breadth-first search order of the reversed CFG.
403
+ SILBasicBlock *lowestCommonAncestorBB = nullptr ;
404
+ SmallPtrSet<SILBasicBlock *, 8 > predecessorsOfNoYieldPred;
405
+ for (auto *pred :
406
+ llvm::breadth_first<llvm::Inverse<SILBasicBlock *>>(noYieldPred)) {
407
+ if (!visitedBBs.count (pred)) {
408
+ continue ;
409
+ }
410
+ if (predecessorsOfYieldPred.count (pred)) {
411
+ lowestCommonAncestorBB = pred;
412
+ break ;
413
+ }
414
+ predecessorsOfNoYieldPred.insert (pred);
415
+ }
416
+ assert (lowestCommonAncestorBB);
417
+
418
+ auto *conflictingBranch = lowestCommonAncestorBB->getTerminator ();
419
+
420
+ // Step 2: Find the target basic block of the 'conflictingBranch' that
421
+ // doesn't yield.
422
+ SILBasicBlock *noYieldTarget = nullptr ;
423
+ for (auto *succ : lowestCommonAncestorBB->getSuccessorBlocks ()) {
424
+ if (predecessorsOfNoYieldPred.count (succ)) {
425
+ noYieldTarget = succ;
426
+ break ;
427
+ }
428
+ }
429
+ assert (noYieldTarget);
430
+
431
+ // Step 3: Report specialized diagnostics for each kind of conflicting
432
+ // branch.
433
+
434
+ // For conditional-branch instructions, which correspond to the
435
+ // conditions of 'if', 'where' or 'guard' statements, report for what
436
+ // truth value the branch doesn't yield.
437
+ if (auto *condbr = dyn_cast<CondBranchInst>(conflictingBranch)) {
438
+ diagnose (astCtx, condbr->getLoc ().getSourceLoc (),
439
+ diag::branch_doesnt_yield,
440
+ /* non-yielding branch*/ condbr->getTrueBB () == noYieldTarget);
441
+ return ;
442
+ }
443
+
444
+ // For switch_enum instructions, report the case that doesn't yield.
445
+ enum SwitchCaseKind { Default, OptionNil, OptionSome };
446
+
447
+ if (auto *switchEnum = dyn_cast<SwitchEnumInstBase>(conflictingBranch)) {
448
+ auto enumCaseLoc = noYieldTarget->begin ()->getLoc ().getSourceLoc ();
449
+
450
+ if (switchEnum->hasDefault () &&
451
+ switchEnum->getDefaultBB () == noYieldTarget) {
452
+ diagnose (astCtx, enumCaseLoc, diag::case_doesnt_yield, Default);
453
+ return ;
454
+ }
455
+
456
+ // Find the case identifier that doesn't yield.
457
+ NullablePtr<EnumElementDecl> enumElemDecl =
458
+ switchEnum->getUniqueCaseForDestination (noYieldTarget);
459
+ assert (enumElemDecl.isNonNull ());
460
+
461
+ // Specialize diagnostics for cases of an optional.
462
+ if (enumElemDecl.get () == astCtx.getOptionalNoneDecl ()) {
463
+ diagnose (astCtx, enumCaseLoc, diag::case_doesnt_yield, OptionNil);
464
+ } else if (enumElemDecl.get () == astCtx.getOptionalSomeDecl ()) {
465
+ diagnose (astCtx, enumCaseLoc, diag::case_doesnt_yield, OptionSome);
466
+ } else {
467
+ diagnose (astCtx, enumCaseLoc, diag::named_case_doesnt_yield,
468
+ enumElemDecl.get ()->getName ());
469
+ }
470
+ return ;
471
+ }
472
+
473
+ // For switch_value instructions, report the case number that doesn't
474
+ // yield.
475
+ if (auto *switchValue = dyn_cast<SwitchValueInst>(conflictingBranch)) {
476
+ auto enumCaseLoc = noYieldTarget->begin ()->getLoc ().getSourceLoc ();
477
+
478
+ if (switchValue->hasDefault () &&
479
+ switchValue->getDefaultBB () == noYieldTarget) {
480
+ diagnose (astCtx, enumCaseLoc, diag::case_doesnt_yield, Default);
481
+ return ;
482
+ }
483
+ // Find the case that doesn't yield.
484
+ Optional<unsigned > caseNumberOpt =
485
+ switchValue->getUniqueCaseForDestination (noYieldTarget);
486
+ assert (caseNumberOpt.hasValue ());
487
+
488
+ auto caseNumber = caseNumberOpt.getValue ();
489
+ diagnose (
490
+ astCtx, enumCaseLoc, diag::switch_value_case_doesnt_yield,
491
+ (Twine (caseNumber) + llvm::getOrdinalSuffix (caseNumber)).str ());
492
+ return ;
493
+ }
494
+
495
+ // For try-apply instructions, report whether throwing or non-throwing
496
+ // case doesn't yield.
497
+ if (auto *tryApply = dyn_cast<TryApplyInst>(conflictingBranch)) {
498
+ diagnose (astCtx, tryApply->getLoc ().getSourceLoc (),
499
+ diag::try_branch_doesnt_yield,
500
+ /* does error case not yield?*/ tryApply->getErrorBB () ==
501
+ noYieldTarget);
502
+ return ;
503
+ }
504
+
505
+ llvm_unreachable (" unexpected branch resulting in conflicting yield "
506
+ " states found in generalized accessor" );
305
507
}
306
508
}
307
509
}
0 commit comments