43
43
#include " swift/SIL/SILInstruction.h"
44
44
#include " swift/SIL/ApplySite.h"
45
45
#include " swift/SIL/MemAccessUtils.h"
46
+ #include " swift/SIL/BasicBlockData.h"
46
47
#include " swift/SILOptimizer/PassManager/Transforms.h"
47
48
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
48
49
#include " swift/SILOptimizer/Utils/Devirtualize.h"
@@ -302,11 +303,6 @@ struct BlockInfo {
302
303
// / recursive call.
303
304
bool reachableFromEntry;
304
305
305
- // Make DenseMap<...,BlockInfo> compilable.
306
- BlockInfo () {
307
- llvm_unreachable (" DenseMap should not construct an empty BlockInfo" );
308
- }
309
-
310
306
// / Get block information with expected \p invariants.
311
307
BlockInfo (SILBasicBlock *block, Invariants invariants) :
312
308
recursiveCall (nullptr ),
@@ -380,35 +376,31 @@ struct BlockInfo {
380
376
// / }
381
377
// /
382
378
class InfiniteRecursionAnalysis {
383
- SILFunction *function;
384
- llvm::DenseMap<SILBasicBlock *, BlockInfo> blockInfos;
385
-
386
- InfiniteRecursionAnalysis (SILFunction *function) :
387
- function (function),
388
- // Reserve enough space in the map. Though, SILFunction::size() iterates
389
- // over all blocks. But this is still better than to risk multiple mallocs.
390
- blockInfos (function->size ()) { }
379
+ Invariants invariants;
380
+ BasicBlockData<BlockInfo> blockInfos;
391
381
392
- BlockInfo &info (SILBasicBlock *block) { return blockInfos[block]; }
382
+ InfiniteRecursionAnalysis (SILFunction *function, Invariants invariants) :
383
+ invariants (invariants), blockInfos(function,
384
+ [&](SILBasicBlock *block) -> BlockInfo {
385
+ return BlockInfo (block, invariants);
386
+ }) { }
393
387
394
388
// / Propagates the `reachesReturn` flags up the control flow and returns true
395
389
// / if the flag reaches the entry block.
396
- bool isEntryReachableFromReturn (Invariants invariants ) {
390
+ bool isEntryReachableFromReturn () {
397
391
// Contains blocks for which the `reachesReturn` flag is set.
398
392
SmallVector<SILBasicBlock *, 32 > workList;
399
393
400
- // First, initialize the block infos.
401
- for (SILBasicBlock &block : *function) {
402
- BlockInfo blockInfo (&block, invariants);
403
- blockInfos.insert ({&block, blockInfo});
404
- if (blockInfo.reachesReturn )
405
- workList.push_back (&block);
394
+ // Initialize the workList with all function-return blocks.
395
+ for (auto bd : blockInfos) {
396
+ if (bd.data .reachesReturn )
397
+ workList.push_back (&bd.block );
406
398
}
407
399
408
400
while (!workList.empty ()) {
409
401
SILBasicBlock *block = workList.pop_back_val ();
410
402
for (auto *pred : block->getPredecessorBlocks ()) {
411
- BlockInfo &predInfo = info ( pred) ;
403
+ BlockInfo &predInfo = blockInfos[ pred] ;
412
404
if (predInfo.reachesReturn ||
413
405
// Recursive calls block the flag propagation.
414
406
predInfo.recursiveCall != nullptr )
@@ -432,30 +424,30 @@ class InfiniteRecursionAnalysis {
432
424
workList.push_back (pred);
433
425
}
434
426
}
435
- return info (function-> getEntryBlock ()) .reachesReturn ;
427
+ return blockInfos. entry (). data .reachesReturn ;
436
428
}
437
429
438
430
// / Propagates the `reachableFromEntry` flags down the control flow and
439
431
// / issues a warning if it reaches a recursive call.
440
432
// / Returns true, if at least one recursive call is found.
441
433
bool findRecursiveCallsAndDiagnose () {
442
434
SmallVector<SILBasicBlock *, 32 > workList;
443
- SILBasicBlock *entryBlock = function-> getEntryBlock ();
444
- info (entryBlock) .reachableFromEntry = true ;
445
- workList.push_back (entryBlock );
435
+ auto entry = blockInfos. entry ();
436
+ entry. data .reachableFromEntry = true ;
437
+ workList.push_back (&entry. block );
446
438
447
439
bool foundInfiniteRecursion = false ;
448
440
while (!workList.empty ()) {
449
441
SILBasicBlock *block = workList.pop_back_val ();
450
- if (auto *recursiveCall = info ( block) .recursiveCall ) {
451
- function ->getModule ().getASTContext ().Diags .diagnose (
442
+ if (auto *recursiveCall = blockInfos[ block] .recursiveCall ) {
443
+ blockInfos. getFunction () ->getModule ().getASTContext ().Diags .diagnose (
452
444
recursiveCall->getLoc ().getSourceLoc (),
453
445
diag::warn_infinite_recursive_call);
454
446
foundInfiniteRecursion = true ;
455
447
continue ;
456
448
}
457
449
for (auto *succ : block->getSuccessorBlocks ()) {
458
- BlockInfo &succInfo = info ( succ) ;
450
+ BlockInfo &succInfo = blockInfos[ succ] ;
459
451
if (!succInfo.reachesReturn && !succInfo.reachableFromEntry ) {
460
452
succInfo.reachableFromEntry = true ;
461
453
workList.push_back (succ);
@@ -468,17 +460,16 @@ class InfiniteRecursionAnalysis {
468
460
public:
469
461
470
462
LLVM_ATTRIBUTE_USED void dump () {
471
- for (SILBasicBlock &block : *function) {
472
- BlockInfo &blockInfo = info (&block);
473
- llvm::dbgs () << " bb" << block.getDebugID ()
474
- << " : numSuccs= " << blockInfo.numSuccsNotReachingReturn ;
475
- if (blockInfo.recursiveCall )
463
+ for (auto bd : blockInfos) {
464
+ llvm::dbgs () << " bb" << bd.block .getDebugID ()
465
+ << " : numSuccs= " << bd.data .numSuccsNotReachingReturn ;
466
+ if (bd.data .recursiveCall )
476
467
llvm::dbgs () << " hasRecursiveCall" ;
477
- if (blockInfo .hasInvariantCondition )
468
+ if (bd. data .hasInvariantCondition )
478
469
llvm::dbgs () << " hasInvariantCondition" ;
479
- if (blockInfo .reachesReturn )
470
+ if (bd. data .reachesReturn )
480
471
llvm::dbgs () << " reachesReturn" ;
481
- if (blockInfo .reachableFromEntry )
472
+ if (bd. data .reachableFromEntry )
482
473
llvm::dbgs () << " reachesRecursiveCall" ;
483
474
llvm::dbgs () << ' \n ' ;
484
475
}
@@ -487,8 +478,8 @@ class InfiniteRecursionAnalysis {
487
478
// / Performs the analysis and issues a warnings for recursive calls.
488
479
// / Returns true, if at least one recursive call is found.
489
480
static bool analyzeAndDiagnose (SILFunction *function, Invariants invariants) {
490
- InfiniteRecursionAnalysis analysis (function);
491
- if (analysis.isEntryReachableFromReturn (invariants ))
481
+ InfiniteRecursionAnalysis analysis (function, invariants );
482
+ if (analysis.isEntryReachableFromReturn ())
492
483
return false ;
493
484
494
485
// Now we know that the function never returns.
0 commit comments