2222#include " swift/AST/Expr.h"
2323#include " swift/AST/Stmt.h"
2424#include " swift/SIL/BasicBlockUtils.h"
25+ #include " swift/SIL/CFG.h"
2526#include " swift/SIL/Dominance.h"
2627#include " swift/SILOptimizer/PassManager/Transforms.h"
28+ #include " llvm/ADT/BreadthFirstIterator.h"
2729#include " llvm/ADT/DenseSet.h"
2830
2931using namespace swift ;
@@ -48,32 +50,54 @@ class YieldOnceCheck : public SILFunctionTransform {
4850 enum YieldState { BeforeYield, AfterYield, Conflict } yieldState;
4951
5052 private:
51- // The following state is maintained for emitting diagnostics.
53+ // The following states are maintained for emitting diagnostics.
5254
5355 // / For AfterYield and Conflict states, this field records the yield
5456 // / instruction that was seen while propagating the state.
5557 SILInstruction *yieldInst;
5658
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) {}
5969
6070 public:
61- static BBState getInitialState () { return BBState (BeforeYield, nullptr ); }
71+ static BBState getInitialState () {
72+ return BBState (BeforeYield, nullptr , nullptr , nullptr );
73+ }
6274
6375 static BBState getAfterYieldState (SILInstruction *yieldI) {
6476 assert (yieldI);
65- return BBState (AfterYield, yieldI);
77+ return BBState (AfterYield, yieldI, nullptr , nullptr );
6678 }
6779
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);
7185 }
7286
7387 SILInstruction *getYieldInstruction () const {
7488 assert (yieldState == AfterYield || yieldState == Conflict);
7589 return yieldInst;
7690 }
91+
92+ SILBasicBlock *getYieldingPred () {
93+ assert (yieldState == Conflict);
94+ return yieldingPred;
95+ }
96+
97+ SILBasicBlock *getNonYieldingPred () {
98+ assert (yieldState == Conflict);
99+ return nonYieldingPred;
100+ }
77101 };
78102
79103 // / A structure that records an error found during the analysis along with
@@ -157,9 +181,16 @@ class YieldOnceCheck : public SILFunctionTransform {
157181 // / \param mergeBlock the basic block that is reached with two states
158182 // / \param oldState the previous state at the entry of the basic block
159183 // / \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.
160190 // / \return the new state obtained by merging the oldState with the newState
161191 static BBState merge (SILBasicBlock *mergeBlock, BBState oldState,
162- BBState newState) {
192+ BBState newState, SILBasicBlock *newStatePred,
193+ llvm::DenseMap<SILBasicBlock *, BBState> &bbToStateMap) {
163194 auto oldYieldState = oldState.yieldState ;
164195 auto newYieldState = newState.yieldState ;
165196
@@ -182,11 +213,27 @@ class YieldOnceCheck : public SILFunctionTransform {
182213 (newYieldState == BBState::BeforeYield &&
183214 oldYieldState == BBState::AfterYield));
184215
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+ }
190237 }
191238
192239 // / Perform a data-flow analysis to check whether there is exactly one
@@ -195,6 +242,7 @@ class YieldOnceCheck : public SILFunctionTransform {
195242 // / the control-flow graph.
196243 void diagnoseYieldOnceUsage (SILFunction &fun) {
197244 llvm::DenseMap<SILBasicBlock *, BBState> bbToStateMap;
245+
198246 SmallVector<SILBasicBlock *, 16 > worklist;
199247
200248 auto *entryBB = fun.getEntryBlock ();
@@ -234,7 +282,7 @@ class YieldOnceCheck : public SILFunctionTransform {
234282 continue ;
235283 }
236284
237- emitDiagnostics (error, fun);
285+ emitDiagnostics (error, fun, bbToStateMap );
238286 return ;
239287 }
240288
@@ -255,7 +303,7 @@ class YieldOnceCheck : public SILFunctionTransform {
255303 // previous states and propagate it if it is different from the
256304 // old state.
257305 const auto &oldState = insertResult.first ->second ;
258- auto mergedState = merge (succBB, oldState, nextState);
306+ auto mergedState = merge (succBB, oldState, nextState, bb, bbToStateMap );
259307
260308 if (mergedState.yieldState == oldState.yieldState )
261309 continue ;
@@ -271,11 +319,12 @@ class YieldOnceCheck : public SILFunctionTransform {
271319 }
272320
273321 if (returnBeforeYieldError.hasValue ()) {
274- emitDiagnostics (returnBeforeYieldError.getValue (), fun);
322+ emitDiagnostics (returnBeforeYieldError.getValue (), fun, bbToStateMap );
275323 }
276324 }
277325
278- void emitDiagnostics (YieldError &error, SILFunction &fun) {
326+ void emitDiagnostics (YieldError &error, SILFunction &fun,
327+ llvm::DenseMap<SILBasicBlock *, BBState> &visitedBBs) {
279328 ASTContext &astCtx = fun.getModule ().getASTContext ();
280329
281330 switch (error.errorKind ) {
@@ -299,9 +348,162 @@ class YieldOnceCheck : public SILFunctionTransform {
299348 diagnose (astCtx, error.termInst ->getLoc ().getSourceLoc (),
300349 diag::possible_return_before_yield);
301350
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" );
305507 }
306508 }
307509 }
0 commit comments