//===--- ManagedValue.h - Exploded RValue Representation --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 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 // //===----------------------------------------------------------------------===// // // A storage structure for holding a destructured rvalue with an optional // cleanup(s). // Ownership of the rvalue can be "forwarded" to disable the associated // cleanup(s). // //===----------------------------------------------------------------------===// #ifndef SWIFT_LOWERING_MANAGEDVALUE_H #define SWIFT_LOWERING_MANAGEDVALUE_H #include "Cleanup.h" #include "llvm/ADT/PointerIntPair.h" #include "swift/Basic/Assertions.h" #include "swift/SIL/Consumption.h" #include "swift/SIL/SILValue.h" namespace swift { enum class CastConsumptionKind : unsigned char; namespace Lowering { class Initialization; class SILGenFunction; enum class SGFAccessKind : uint8_t; /// ManagedValue - represents a singular SIL value and an optional cleanup. /// Ownership of the ManagedValue can be "forwarded" to disable its cleanup when /// the rvalue is consumed. A ManagedValue can also represent an LValue used as /// a value, such as an inout function argument, and can be null. /// /// Interesting relevant cases include: /// LValue: the SILValue will always have an isAddress() SILType. LValues /// never have an associated cleanup. /// RValue, isAddress() type: an address-only RValue. /// RValue, !isAddress() type: a loadable RValue. /// "InContext": Represented with the lvalue flag set but with no SILValue, /// this represents a value that was emitted directly into an /// initialization stored by an SGFContext. /// /// The RValue cases may or may not have a cleanup associated with the value. A /// cleanup is associated with +1 values of non-trivial type and +0 values of /// non-trivial type. /// class ManagedValue { /// The value (or address of an address-only value) being managed, and /// whether it represents an lvalue. InContext is represented with the lvalue /// flag set but with a null SILValue. llvm::PointerIntPair valueAndFlag; /// A handle to the cleanup that destroys this value, or /// CleanupHandle::invalid() if the value has no cleanup. CleanupHandle cleanup; explicit ManagedValue(SILValue value, bool isLValue, CleanupHandle cleanup) : valueAndFlag(value, isLValue), cleanup(cleanup) { } /// Create a managed value for a +0 rvalue. /// /// Please do not introduce new uses of this method! Instead use one of the /// static constructors below! static ManagedValue forUnmanaged(SILValue value) { assert(value && "No value specified"); return ManagedValue(value, false, CleanupHandle::invalid()); } /// Create a managed value for a +1 rvalue. /// /// Please do not introduce new uses of this method! Instead use one of the /// static constructors below. explicit ManagedValue(SILValue value, CleanupHandle cleanup = CleanupHandle::invalid()) : valueAndFlag(value, false), cleanup(cleanup) { assert(value && "No value specified?!"); assert((!getType().isObject() || value->getOwnershipKind() != OwnershipKind::None || !hasCleanup()) && "Objects with trivial ownership should never have a cleanup"); } public: /// Constructs an invalid ManagedValue. ManagedValue() = default; /// Sometimes SILGen wants to represent an owned value or owned address /// without a cleanup as a +0 value that must be copied to be consumed. /// /// Please do not introduce new uses of this. /// /// DISCUSSION: We purposely provide a specific API for code paths that use /// owned values (and assert the values are owned) so that users do not /// attempt to use this for borrowed values. All borrowed values need to use /// the borrowed value APIs. static ManagedValue forUnmanagedOwnedValue(SILValue value) { assert(value); assert(!value->getType().isObject() || value->getOwnershipKind().isCompatibleWith(OwnershipKind::Owned)); return ManagedValue(value); } /// Wrap a value with OwnershipKind::Unowned in a ManagedValue. This must be /// copied before it is used. static ManagedValue forUnownedObjectValue(SILValue value) { assert(value); assert(value->getType().isObject()); assert(value->getOwnershipKind().isCompatibleWith(OwnershipKind::Unowned)); return ManagedValue(value); } enum class ScopeKind { Lexical, FormalAccess, }; /// Create a managed value for a SILValue whose ownership is /// forwarded. Creates a new cleanup for +1 values. Forwarded +0 values /// require no cleanup. /// /// Use this for values that do not introduce a new borrow scope. This is /// correct for casts and terminator results, not for phis. static ManagedValue forForwardedRValue(SILGenFunction &SGF, SILValue value); /// Create a managed value for a +1 rvalue object. static ManagedValue forOwnedObjectRValue(SILValue value, CleanupHandle cleanup) { assert(value && "No value specified"); assert(value->getType().isObject() && "Expected borrowed rvalues to be objects"); assert(value->getOwnershipKind() != OwnershipKind::None); return ManagedValue(value, false, cleanup); } /// Create a managed value for a +1 rvalue address. /// /// From a high level perspective, this consists of a temporary buffer. static ManagedValue forOwnedAddressRValue(SILValue value, CleanupHandle cleanup) { assert(value && "No value specified"); assert(value->getType().isAddress() && "Expected value to be an address"); assert(value->getOwnershipKind() == OwnershipKind::None && "Addresses always have any ownership"); return ManagedValue(value, false, cleanup); } /// Create a managed value for a +1 non-trivial rvalue. static ManagedValue forOwnedRValue(SILValue value, CleanupHandle cleanup) { if (value->getType().isAddress()) return ManagedValue::forOwnedAddressRValue(value, cleanup); return ManagedValue::forOwnedObjectRValue(value, cleanup); } static ManagedValue forExclusivelyBorrowedOwnedObjectRValue(SILValue value, CleanupHandle cleanup) { assert(value->getType().isObject()); return ManagedValue::forOwnedObjectRValue(value, cleanup); } /// Create a managed value for a +0 borrowed non-trivial rvalue object. static ManagedValue forBorrowedObjectRValue(SILValue value) { assert(value && "No value specified"); assert(value->getType().isObject() && "Expected borrowed rvalues to be objects"); if (value->getOwnershipKind() == OwnershipKind::None) { return forObjectRValueWithoutOwnership(value); } assert(value->getOwnershipKind() == OwnershipKind::Guaranteed); return ManagedValue(value, false, CleanupHandle::invalid()); } /// Create a managed value for a +0 borrowed non-trivial rvalue address. static ManagedValue forBorrowedAddressRValue(SILValue value) { assert(value && "No value specified"); assert(value->getType().isAddress() && "Expected value to be an address"); // We check for value->getFunction() here since we /could/ be passed // SILUndef here. assert(value->getOwnershipKind() == OwnershipKind::None && "Addresses always have trivial ownership"); return ManagedValue(value, false, CleanupHandle::invalid()); } /// Create a managed value for a +0 guaranteed rvalue. static ManagedValue forBorrowedRValue(SILValue value) { if (value->getType().isAddress()) return ManagedValue::forBorrowedAddressRValue(value); return ManagedValue::forBorrowedObjectRValue(value); } /// Create a managed value for a +0 trivial object rvalue. static ManagedValue forObjectRValueWithoutOwnership(SILValue value) { assert(value->getType().isObject() && "Expected an object"); assert(value->getOwnershipKind() == OwnershipKind::None); return ManagedValue(value, false, CleanupHandle::invalid()); } /// Create a managed value for a +0 trivial address rvalue. static ManagedValue forTrivialAddressRValue(SILValue value) { assert(value->getType().isAddress() && "Expected an address"); assert(value->getOwnershipKind() == OwnershipKind::None); // TODO: Add an assert that we have a trivial type here. // // DISCUSSION: We cannot do this today since we have problems along certain // materialization paths where we want to emit a borrow operation. To handle // those cases, we have loosened the rules of OSSA by allowing for store // [trivial] to take non-trivial .none parameters. This has hidden bugs // where SILGen emits a borrow to materialize a parameter for an @in // parameter. It just coincidently works since when we emit the // store_borrow, we use the store [trivial] instead. This should be fixed. return ManagedValue(value, false, CleanupHandle::invalid()); } /// Create a managed value for a trivial address rvalue or an object rvalue /// that has .none ownership. static ManagedValue forRValueWithoutOwnership(SILValue value) { if (value->getType().isObject()) return ManagedValue::forObjectRValueWithoutOwnership(value); return ManagedValue::forTrivialAddressRValue(value); } /// Create a managed value for an l-value. static ManagedValue forLValue(SILValue value) { assert(value && "No value specified"); assert(value->getType().isAddress() && "lvalues always have isAddress() type"); return ManagedValue(value, true, CleanupHandle::invalid()); } /// Create a managed value that indicates that the value you're looking for /// got stored into an initialization specified by an SGFContext, instead of /// being represented by this ManagedValue. static ManagedValue forInContext() { return ManagedValue(SILValue(), true, CleanupHandle::invalid()); } /// Creates a managed value for an address that is undergoing a formal /// access. This will be `forLValue` if the `accessKind` is a mutating /// (exclusive) access or `forBorrowedAddressRValue` if the /// `accessKind` is borrowing (shared). static ManagedValue forFormalAccessedAddress(SILValue address, SGFAccessKind accessKind); bool isValid() const { return valueAndFlag.getInt() || valueAndFlag.getPointer(); } bool isLValue() const { return valueAndFlag.getInt() && valueAndFlag.getPointer(); } bool isInContext() const { return valueAndFlag.getInt() && !valueAndFlag.getPointer(); } /// Return true if this is an +0 rvalue, or has trivial type. bool isPlusZeroRValueOrTrivial() const { // If this is an lvalue or isInContext() then it is not an RValue. if (isLValue() || isInContext()) return false; // If this has a cleanup attached, then it is +1 rvalue. If not, it is // either +0 or trivial (in which case +0 vs +1 doesn't matter). return !hasCleanup(); } /// Returns true if this managed value can be consumed. /// /// This is true if either this value has a cleanup or if it is a trivial /// object value. For address values, this returns true only if the value has /// a cleanup regardless of whether the type is trivial. /// /// When an object value is trivial, it can be passed to a consuming operation /// without destroying it. Consuming a value by address, however, always /// deinitializes the memory regardless of whether or not it is trivial. /// /// Use this before emitting an operation that "takes" this value or passing /// this value to a call that consumes the argument. bool isPlusOne(SILGenFunction &SGF) const; /// Returns true if this managed value can be forwarded without necessarilly /// destroying the original. /// /// This is true if either isPlusOne is true or the value is trivial. Unlike /// isPlusOne(), this returns true for trivial address values regardless of /// whether the value has a cleanup. A +1 value can be created from a trivial /// value without consuming the original. /// /// Use this when storing this value into a new location simply by forwarding /// the cleanup without destroying the original value. If it's necessary to /// "take" or otherwise immediately consume the original value, then use /// isPlusOne() instead. bool isPlusOneOrTrivial(SILGenFunction &SGF) const; /// Returns true if this is an ManagedValue that can be used safely as a +0 /// ManagedValue. /// /// Specifically, we return true if: /// /// 1. All sub-values are trivially typed. /// 2. At least 1 subvalue is non-trivial and all such non-trivial values do /// not have a cleanup. /// /// *NOTE* Due to 1. isPlusOne and isPlusZero both return true for /// ManagedValues consisting of only trivial values. bool isPlusZero() const; SILValue getLValueAddress() const { assert(isLValue() && "This isn't an lvalue"); return getValue(); } SILValue getUnmanagedValue() const { assert(!hasCleanup()); return getValue(); } /// Treat getValue() as used so that we can access the value directly when /// debugging without needing to interpret the flag field. LLVM_ATTRIBUTE_USED SILValue getValue() const { return valueAndFlag.getPointer(); } SILType getType() const { return getValue()->getType(); } ValueOwnershipKind getOwnershipKind() const { return getValue()->getOwnershipKind(); } /// Transform the given ManagedValue, replacing the underlying value, but /// keeping the same cleanup. /// /// For owned values, this is equivalent to forwarding the cleanup and /// creating a new cleanup of the same type on the new value. This is useful /// for forwarding sequences. /// /// For all other values, it is a move. ManagedValue transform(SILValue newValue) && { assert(getValue()->getOwnershipKind() == newValue->getOwnershipKind() && "New value and old value must have the same ownership kind"); ManagedValue M(newValue, isLValue(), getCleanup()); *this = ManagedValue(); return M; } /// Emit a copy of this value with independent ownership. ManagedValue copy(SILGenFunction &SGF, SILLocation loc) const; /// Returns an unmanaged copy of this value. /// WARNING: Callers of this API should manage the cleanup of this value! SILValue unmanagedCopy(SILGenFunction &SGF, SILLocation loc) const; /// Emit a copy of this value with independent ownership into the current /// formal evaluation scope. ManagedValue formalAccessCopy(SILGenFunction &SGF, SILLocation loc); /// This is the same operation as 'copy', but works on +0 values that don't /// have cleanups. It returns a +1 value with one. ManagedValue copyUnmanaged(SILGenFunction &SGF, SILLocation loc); /// This is the same operation as 'formalAccessCopy', but works on +0 values /// that don't have cleanups. It returns a +1 value with one. ManagedValue formalAccessCopyUnmanaged(SILGenFunction &SGF, SILLocation loc); bool hasCleanup() const { return cleanup.isValid(); } CleanupHandle getCleanup() const { return cleanup; } /// Return a "borrowed" version of this value. /// /// An l-value is borrowed as itself. A +1 r-value is borrowed as a /// +0 r-value, with the assumption that the original ManagedValue /// will not be forwarded until the borrowed value is fully used. ManagedValue borrow(SILGenFunction &SGF, SILLocation loc) const; /// Return a formally evaluated "borrowed" version of this value. ManagedValue formalAccessBorrow(SILGenFunction &SGF, SILLocation loc) const; ManagedValue unmanagedBorrow() const { return isLValue() ? *this : ManagedValue::forUnmanaged(getValue()); } /// If this managed value is a plus one value, return *this. If this is a plus /// zero value, return a copy instead. ManagedValue ensurePlusOne(SILGenFunction &SGF, SILLocation loc) const; /// Given a scalar value, materialize it into memory with the /// exact same level of cleanup it had before. ManagedValue materialize(SILGenFunction &SGF, SILLocation loc) const; ManagedValue formallyMaterialize(SILGenFunction &SGF, SILLocation loc) const; /// Disable the cleanup for this value. void forwardCleanup(SILGenFunction &SGF) const; /// Forward this value, deactivating the cleanup and returning the /// underlying value. SILValue forward(SILGenFunction &SGF) const; /// Forward this value into memory by storing it to the given address. /// /// \param SGF - The SILGenFunction. /// \param loc - the AST location to associate with emitted instructions. /// \param address - the address to assign to. void forwardInto(SILGenFunction &SGF, SILLocation loc, SILValue address); /// Forward this value into the given initialization. /// /// \param SGF - The SILGenFunction. /// \param loc - the AST location to associate with emitted instructions. /// \param dest - the destination to forward into void forwardInto(SILGenFunction &SGF, SILLocation loc, Initialization *dest); /// Assign this value into memory, destroying the existing /// value at the destination address. /// /// \param SGF - The SILGenFunction. /// \param loc - the AST location to associate with emitted instructions. /// \param address - the address to assign to. void assignInto(SILGenFunction &SGF, SILLocation loc, SILValue address); /// Store a copy of this value with independent ownership into the given /// uninitialized address. void copyInto(SILGenFunction &SGF, SILLocation loc, SILValue dest); /// Store a copy of this value with independent ownership into the given /// initialization \p dest. void copyInto(SILGenFunction &SGF, SILLocation loc, Initialization *dest); explicit operator bool() const { // "InContext" is not considered false. return bool(getValue()) || valueAndFlag.getInt(); } SILFunction *getFunction() const { assert(getValue()); return getValue()->getFunction(); } void dump() const; void dump(raw_ostream &os, unsigned indent = 0) const; void print(raw_ostream &os) const; }; /// A ManagedValue which may not be intended to be consumed. /// /// The invariant is that the cleanup on a ManagedValue that's not /// meant to be consumed should be free to clear. /// /// Code which gets a ManagedValue from a ConsumableManagedValue /// must be careful before handing the MV off to an API. Many /// SILGen APIs expect that an MV is +1, but ConsumableManagedValue /// often traffics in borrowed values. A value is only +1 if /// the associated consumption is TakeAlways, but conditional /// operation should turn TakeOnSuccess consumptions into TakeAlways /// consumptions on their success path. class ConsumableManagedValue { ManagedValue Value; CastConsumptionKind FinalConsumption; public: /// Create an invalid CMV. ConsumableManagedValue() = default; /// Create a CMV with a specific value and consumption rule. /*implicit*/ ConsumableManagedValue(ManagedValue value, CastConsumptionKind finalConsumption) : Value(value), FinalConsumption(finalConsumption) { assert((value.getType().isAddress() || finalConsumption != CastConsumptionKind::CopyOnSuccess) && "Can not copy on success a value."); } /// Create a CMV for a value of trivial type. static ConsumableManagedValue forUnmanaged(SILValue value) { return {ManagedValue::forObjectRValueWithoutOwnership(value), CastConsumptionKind::TakeAlways}; } /// Create a CMV for an owned value. static ConsumableManagedValue forOwned(ManagedValue value) { return { value, CastConsumptionKind::TakeAlways }; } /// Has this been filled in with meaningful data? bool isValid() const { return (bool) Value; } bool isOwned() const { assert(isValid()); return FinalConsumption == CastConsumptionKind::TakeAlways; } /// Return true if there's a cleanup associated with this value. bool hasCleanup() const { return Value.hasCleanup(); } CleanupHandle getCleanup() const { return Value.getCleanup(); } SILType getType() const { return Value.getType(); } SILValue getValue() const { return Value.getValue(); } ValueOwnershipKind getOwnershipKind() const { return Value.getOwnershipKind(); } /// Return a managed value appropriate for the final use of this CMV. ManagedValue getFinalManagedValue() const { return Value; } /// Get the value as an unmanaged ManagedValue. /// /// You probably should not be using this; it's here to make it easy /// to find code that is probably wrong. ManagedValue asUnmanagedOwnedValue() const { return ManagedValue::forUnmanagedOwnedValue(Value.getValue()); } /// Return the consumption rules appropriate for the final use of /// this CMV. CastConsumptionKind getFinalConsumption() const { return FinalConsumption; } /// Return a managed value that's appropriate for borrowing this /// value and promising not to consume it. /// /// TODO: Should be superseded by `asBorrowedOperand2` once existing code is /// updated to tolerate address-only values being borrowed. ConsumableManagedValue asBorrowedOperand(SILGenFunction &SGF, SILLocation loc) const { if (getType().isAddress()) return {asUnmanagedOwnedValue(), CastConsumptionKind::CopyOnSuccess}; if (Value.getOwnershipKind() == OwnershipKind::Guaranteed) return {Value, CastConsumptionKind::BorrowAlways}; return {asUnmanagedOwnedValue().borrow(SGF, loc), CastConsumptionKind::BorrowAlways}; } ConsumableManagedValue asBorrowedOperand2(SILGenFunction &SGF, SILLocation loc) const { if (getType().isAddress()) return {asUnmanagedOwnedValue(), CastConsumptionKind::BorrowAlways}; if (Value.getOwnershipKind() == OwnershipKind::Guaranteed) return {Value, CastConsumptionKind::BorrowAlways}; return {asUnmanagedOwnedValue().borrow(SGF, loc), CastConsumptionKind::BorrowAlways}; } /// Return a managed value that's appropriate for copying this value and /// always consuming it. ConsumableManagedValue copy(SILGenFunction &SGF, SILLocation loc) const { return ConsumableManagedValue::forOwned(Value.copy(SGF, loc)); } }; } // namespace Lowering } // namespace swift namespace swift { template inline bool isa(const Lowering::ManagedValue &M) { return isa(M.getValue()); } } // end namespace swift #endif