| //===--- OwnershipUtils.h ------------------------------------*- C++ -*----===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SIL_OWNERSHIPUTILS_H |
| #define SWIFT_SIL_OWNERSHIPUTILS_H |
| |
| #include "swift/Basic/LLVM.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/SIL/SILInstruction.h" |
| #include "swift/SIL/SILValue.h" |
| #include "llvm/ADT/SmallPtrSet.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| namespace swift { |
| |
| class SILBasicBlock; |
| class SILInstruction; |
| class SILModule; |
| class SILValue; |
| class DeadEndBlocks; |
| class BranchPropagatedUser; |
| |
| namespace ownership { |
| |
| struct ErrorBehaviorKind { |
| enum inner_t { |
| Invalid = 0, |
| ReturnFalse = 1, |
| PrintMessage = 2, |
| Assert = 4, |
| ReturnFalseOnLeak = 8, |
| PrintMessageAndReturnFalse = PrintMessage | ReturnFalse, |
| PrintMessageAndAssert = PrintMessage | Assert, |
| ReturnFalseOnLeakAssertOtherwise = ReturnFalseOnLeak | Assert, |
| } Value; |
| |
| ErrorBehaviorKind() : Value(Invalid) {} |
| ErrorBehaviorKind(inner_t Inner) : Value(Inner) { assert(Value != Invalid); } |
| |
| bool shouldAssert() const { |
| assert(Value != Invalid); |
| return Value & Assert; |
| } |
| |
| bool shouldReturnFalseOnLeak() const { |
| assert(Value != Invalid); |
| return Value & ReturnFalseOnLeak; |
| } |
| |
| bool shouldPrintMessage() const { |
| assert(Value != Invalid); |
| return Value & PrintMessage; |
| } |
| |
| bool shouldReturnFalse() const { |
| assert(Value != Invalid); |
| return Value & ReturnFalse; |
| } |
| }; |
| |
| } // end namespace ownership |
| |
| class LinearLifetimeError { |
| ownership::ErrorBehaviorKind errorBehavior; |
| bool foundUseAfterFree = false; |
| bool foundLeak = false; |
| bool foundOverConsume = false; |
| |
| public: |
| LinearLifetimeError(ownership::ErrorBehaviorKind errorBehavior) |
| : errorBehavior(errorBehavior) {} |
| |
| bool getFoundError() const { |
| return foundUseAfterFree || foundLeak || foundOverConsume; |
| } |
| |
| bool getFoundLeak() const { return foundLeak; } |
| |
| bool getFoundUseAfterFree() const { return foundUseAfterFree; } |
| |
| bool getFoundOverConsume() const { return foundOverConsume; } |
| |
| void handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) { |
| foundLeak = true; |
| |
| if (errorBehavior.shouldPrintMessage()) |
| messagePrinterFunc(); |
| |
| if (errorBehavior.shouldReturnFalseOnLeak()) |
| return; |
| |
| // We already printed out our error if we needed to, so don't pass it along. |
| handleError([]() {}); |
| } |
| |
| void handleOverConsume(llvm::function_ref<void()> &&messagePrinterFunc) { |
| foundOverConsume = true; |
| handleError(std::move(messagePrinterFunc)); |
| } |
| |
| void handleUseAfterFree(llvm::function_ref<void()> &&messagePrinterFunc) { |
| foundUseAfterFree = true; |
| handleError(std::move(messagePrinterFunc)); |
| } |
| |
| private: |
| void handleError(llvm::function_ref<void()> &&messagePrinterFunc) { |
| if (errorBehavior.shouldPrintMessage()) |
| messagePrinterFunc(); |
| |
| if (errorBehavior.shouldReturnFalse()) { |
| return; |
| } |
| |
| assert(errorBehavior.shouldAssert() && "At this point, we should assert"); |
| llvm_unreachable("triggering standard assertion failure routine"); |
| } |
| }; |
| |
| struct UseToEndBorrow { |
| Optional<EndBorrowInst *> operator()(Operand *use) const { |
| if (auto *ebi = dyn_cast<EndBorrowInst>(use->getUser())) { |
| return ebi; |
| } |
| return None; |
| } |
| }; |
| |
| using EndBorrowRange = |
| OptionalTransformRange<ValueBase::use_range, UseToEndBorrow, |
| ValueBase::use_iterator>; |
| |
| /// Given a value \p v that is a "borrow" introducer, return its associated |
| /// end_borrow users. |
| inline auto makeEndBorrowRange(SILValue v) -> EndBorrowRange { |
| assert((isa<BeginBorrowInst>(v) || isa<LoadBorrowInst>(v)) && |
| "Unhandled borrow introducer"); |
| return EndBorrowRange(v->getUses(), UseToEndBorrow()); |
| } |
| |
| /// Returns true if: |
| /// |
| /// 1. No consuming uses are reachable from any other consuming use, from any |
| /// non-consuming uses, or from the producer instruction. |
| /// 2. The consuming use set jointly post dominates producers and all non |
| /// consuming uses. |
| /// |
| /// \p value The value whose lifetime we are checking. |
| /// \p consumingUses the array of users that destroy or consume a value. |
| /// \p nonConsumingUses regular uses |
| /// \p deadEndBlocks a cache for the dead end block computation |
| /// \p errorBehavior If we detect an error, should we return false or hard |
| /// error. |
| /// \p leakingBlocks If non-null a list of blocks where the value was detected |
| /// to leak. Can be used to insert missing destroys. |
| LinearLifetimeError valueHasLinearLifetime( |
| SILValue value, ArrayRef<BranchPropagatedUser> consumingUses, |
| ArrayRef<BranchPropagatedUser> nonConsumingUses, |
| SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks, |
| DeadEndBlocks &deadEndBlocks, ownership::ErrorBehaviorKind errorBehavior, |
| SmallVectorImpl<SILBasicBlock *> *leakingBlocks = nullptr); |
| |
| /// Returns true if v is an address or trivial. |
| bool isValueAddressOrTrivial(SILValue v); |
| |
| /// These operations forward both owned and guaranteed ownership. |
| bool isOwnershipForwardingValueKind(SILNodeKind kind); |
| |
| /// These operations forward guaranteed ownership, but don't necessarily forward |
| /// owned values. |
| bool isGuaranteedForwardingValueKind(SILNodeKind kind); |
| |
| bool isGuaranteedForwardingValue(SILValue value); |
| |
| bool isOwnershipForwardingInst(SILInstruction *i); |
| |
| bool isGuaranteedForwardingInst(SILInstruction *i); |
| |
| /// Look up through the def-use chain of \p inputValue, recording any "borrow" |
| /// introducers that we find into \p out. |
| bool getUnderlyingBorrowIntroducers(SILValue inputValue, |
| SmallVectorImpl<SILValue> &out); |
| |
| } // namespace swift |
| |
| #endif |