|
16 | 16 | #include "swift/SIL/SILArgument.h"
|
17 | 17 | #include "swift/SIL/SILValue.h"
|
18 | 18 | #include "swift/SIL/SILBasicBlock.h"
|
| 19 | +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" |
| 20 | +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" |
| 21 | +#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" |
| 22 | +#include "llvm/ADT/BitVector.h" |
19 | 23 | #include "llvm/ADT/SmallPtrSet.h"
|
20 | 24 | #include "llvm/ADT/MapVector.h"
|
21 | 25 | #include "llvm/ADT/SetVector.h"
|
@@ -386,4 +390,184 @@ SILInstruction *findReleaseToMatchUnsafeGuaranteedValue(
|
386 | 390 |
|
387 | 391 | } // end namespace swift
|
388 | 392 |
|
| 393 | + |
| 394 | +namespace swift { |
| 395 | + |
| 396 | +/// EpilogueARCBlockState - Keep track of whether a epilogue ARC instruction has |
| 397 | +/// been found. |
| 398 | +struct EpilogueARCBlockState { |
| 399 | + /// Keep track of whether a eplogue release has been found before and after |
| 400 | + /// this basic block. |
| 401 | + bool BBSetIn; |
| 402 | + /// The basic block local SILValue we are interested to find epilogue ARC in. |
| 403 | + SILValue LocalArg; |
| 404 | + /// Constructor, we only compute epilogue ARC instruction for 1 argument at |
| 405 | + /// a time. |
| 406 | + /// Optimistic data flow. |
| 407 | + EpilogueARCBlockState() { BBSetIn = true; LocalArg = SILValue(); } |
| 408 | +}; |
| 409 | + |
| 410 | +/// EpilogueARCContext - This class implements a data flow with which epilogue |
| 411 | +/// retains or releases for a SILValue are found. |
| 412 | +/// |
| 413 | +/// NOTE: |
| 414 | +/// In case of release finder, this function assumes the SILArgument has |
| 415 | +/// @owned semantic. |
| 416 | +/// In case of retain finder, this class assumes Arg is one of the return value |
| 417 | +/// of the function. |
| 418 | +class EpilogueARCContext { |
| 419 | +public: |
| 420 | + enum EpilogueARCKind { Retain = 0, Release = 1 }; |
| 421 | + |
| 422 | +private: |
| 423 | + // Are we finding retains or releases. |
| 424 | + EpilogueARCKind Kind; |
| 425 | + |
| 426 | + // The argument we are looking for epilogue ARC instruction for. |
| 427 | + SILValue Arg; |
| 428 | + |
| 429 | + /// The allocator we are currently using. |
| 430 | + llvm::SpecificBumpPtrAllocator<EpilogueARCBlockState> BPA; |
| 431 | + |
| 432 | + /// Current function we are analyzing. |
| 433 | + SILFunction *F; |
| 434 | + |
| 435 | + /// Current post-order we are using. |
| 436 | + PostOrderFunctionInfo *PO; |
| 437 | + |
| 438 | + /// Current alias analysis we are using. |
| 439 | + AliasAnalysis *AA; |
| 440 | + |
| 441 | + /// Current rc-identity we are using. |
| 442 | + RCIdentityFunctionInfo *RCFI; |
| 443 | + |
| 444 | + /// The epilogue retains or releases. |
| 445 | + llvm::SmallVector<SILInstruction *, 1> EpilogueARCInsts; |
| 446 | + |
| 447 | + /// All the retain/release block state for all the basic blocks in the function. |
| 448 | + llvm::DenseMap<SILBasicBlock *, EpilogueARCBlockState *> EpilogueARCBlockStates; |
| 449 | + |
| 450 | + /// The exit blocks of the function. |
| 451 | + llvm::SmallPtrSet<SILBasicBlock *, 2> ExitBlocks; |
| 452 | + |
| 453 | + /// Return true if this is a function exit block. |
| 454 | + bool isExitBlock(SILBasicBlock *BB) { |
| 455 | + return ExitBlocks.count(BB); |
| 456 | + } |
| 457 | + |
| 458 | + /// Return true if this is a retain instruction. |
| 459 | + bool isRetainInstruction(SILInstruction *II) { |
| 460 | + return isa<RetainValueInst>(II) || isa<StrongRetainInst>(II); |
| 461 | + } |
| 462 | + |
| 463 | + /// Return true if this is a release instruction. |
| 464 | + bool isReleaseInstruction(SILInstruction *II) { |
| 465 | + return isa<ReleaseValueInst>(II) || isa<StrongReleaseInst>(II); |
| 466 | + } |
| 467 | + |
| 468 | + SILValue getArg(SILBasicBlock *B) { |
| 469 | + SILValue A = EpilogueARCBlockStates[B]->LocalArg; |
| 470 | + if (A) |
| 471 | + return A; |
| 472 | + return Arg; |
| 473 | + } |
| 474 | + |
| 475 | +public: |
| 476 | + /// Constructor. |
| 477 | + EpilogueARCContext(EpilogueARCKind Kind, SILValue Arg, SILFunction *F, |
| 478 | + PostOrderFunctionInfo *PO, AliasAnalysis *AA, |
| 479 | + RCIdentityFunctionInfo *RCFI) |
| 480 | + : Kind(Kind), Arg(Arg), F(F), PO(PO), AA(AA), RCFI(RCFI) {} |
| 481 | + |
| 482 | + /// Run the data flow to find the epilogue retains or releases. |
| 483 | + bool run() { |
| 484 | + // Initialize the epilogue arc data flow context. |
| 485 | + initializeDataflow(); |
| 486 | + // Converge the data flow. |
| 487 | + convergeDataflow(); |
| 488 | + // Lastly, find the epilogue ARC instructions. |
| 489 | + return computeEpilogueARC(); |
| 490 | + } |
| 491 | + |
| 492 | + /// Reset the epilogue arc instructions. |
| 493 | + void resetEpilogueARCInsts() { EpilogueARCInsts.clear(); } |
| 494 | + llvm::SmallVector<SILInstruction *, 1> getEpilogueARCInsts() { |
| 495 | + return EpilogueARCInsts; |
| 496 | + } |
| 497 | + |
| 498 | + /// Initialize the data flow. |
| 499 | + void initializeDataflow(); |
| 500 | + |
| 501 | + /// Keep iterating until the data flow is converged. |
| 502 | + void convergeDataflow(); |
| 503 | + |
| 504 | + /// Find the epilogue ARC instructions. |
| 505 | + bool computeEpilogueARC(); |
| 506 | + |
| 507 | + /// This instruction prevents looking further for epilogue retains on the |
| 508 | + /// current path. |
| 509 | + bool mayBlockEpilogueRetain(SILInstruction *II, SILValue Ptr) { |
| 510 | + // reference decrementing instruction prevents any retain to be identified as |
| 511 | + // epilogue retains. |
| 512 | + if (mayDecrementRefCount(II, Ptr, AA)) |
| 513 | + return true; |
| 514 | + // Handle self-recursion. A self-recursion can be considered a +1 on the |
| 515 | + // current argument. |
| 516 | + if (ApplyInst *AI = dyn_cast<ApplyInst>(II)) |
| 517 | + if (AI->getCalleeFunction() == II->getParent()->getParent()) |
| 518 | + return true; |
| 519 | + return false; |
| 520 | + } |
| 521 | + |
| 522 | + /// This instruction prevents looking further for epilogue releases on the |
| 523 | + /// current path. |
| 524 | + bool mayBlockEpilogueRelease(SILInstruction *II, SILValue Ptr) { |
| 525 | + // Check whether this instruction read reference count, i.e. uniqueness |
| 526 | + // check. Moving release past that may result in additional COW. |
| 527 | + if (II->mayReleaseOrReadRefCount()) |
| 528 | + return true; |
| 529 | + return false; |
| 530 | + } |
| 531 | + |
| 532 | + /// Does this instruction block the interested ARC instruction ? |
| 533 | + bool mayBlockEpilogueARC(SILInstruction *II, SILValue Ptr) { |
| 534 | + if (Kind == EpilogueARCKind::Retain) |
| 535 | + return mayBlockEpilogueRetain(II, Ptr); |
| 536 | + return mayBlockEpilogueRelease(II, Ptr); |
| 537 | + } |
| 538 | + |
| 539 | + /// This is the type of instructions the data flow is interested in. |
| 540 | + bool isInterestedInstruction(SILInstruction *II) { |
| 541 | + // We are checking for release. |
| 542 | + if (Kind == EpilogueARCKind::Release) |
| 543 | + return isReleaseInstruction(II) && |
| 544 | + RCFI->getRCIdentityRoot(II->getOperand(0)) == |
| 545 | + RCFI->getRCIdentityRoot(getArg(II->getParent())); |
| 546 | + // We are checking for retain. If this is a self-recursion. call |
| 547 | + // to the function (which returns an owned value) can be treated as |
| 548 | + // the retain instruction. |
| 549 | + if (ApplyInst *AI = dyn_cast<ApplyInst>(II)) |
| 550 | + if (AI->getCalleeFunction() == II->getParent()->getParent()) |
| 551 | + return true; |
| 552 | + // Check whether this is a retain instruction and the argument it |
| 553 | + // retains. |
| 554 | + return isRetainInstruction(II) && |
| 555 | + RCFI->getRCIdentityRoot(II->getOperand(0)) == |
| 556 | + RCFI->getRCIdentityRoot(getArg(II->getParent())); |
| 557 | + } |
| 558 | +}; |
| 559 | + |
| 560 | +/// Compute the epilogue ARC instructions for a given SILValue. Return an |
| 561 | +/// empty set if no epilogue ARC instructions can be found. |
| 562 | +/// |
| 563 | +/// NOTE: This function assumes Arg is has @owned semantic. |
| 564 | +llvm::SmallVector<SILInstruction *, 1> |
| 565 | +computeEpilogueARCInstructions(EpilogueARCContext::EpilogueARCKind Kind, |
| 566 | + SILValue Arg, SILFunction *F, |
| 567 | + PostOrderFunctionInfo *PO, AliasAnalysis *AA, |
| 568 | + RCIdentityFunctionInfo *RCFI); |
| 569 | + |
| 570 | +} // end namespace swift |
| 571 | + |
| 572 | + |
389 | 573 | #endif
|
0 commit comments