| //===--- RValue.h - Exploded RValue Representation --------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// |
| /// 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_RVALUE_H |
| #define SWIFT_LOWERING_RVALUE_H |
| |
| #include "ManagedValue.h" |
| #include "swift/Basic/NullablePtr.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| namespace swift { |
| namespace Lowering { |
| |
| class ArgumentSource; |
| class Initialization; |
| class Scope; |
| class SILGenFunction; |
| class TypeLowering; |
| class CleanupCloner; |
| |
| /// An "exploded" SIL rvalue, in which tuple values are recursively |
| /// destructured. |
| /// |
| /// In terms of implementation, an RValue is a collection of ManagedValues that |
| /// the RValue class allows to be worked with as if they were one tuple. This |
| /// allows for tuples to represent tuples without needing to canonicalize into |
| /// the actual tuple value. |
| /// |
| /// Once constructed, RValues obey the following invariants: |
| /// |
| /// 1. All non-trivially typed sub-ManagedValues must consistently have |
| /// cleanups. This is verified upon construction of an RValue. |
| /// |
| /// 2. All sub-ManagedValues with non-trivial ValueOwnershipKind must have the |
| /// same ValueOwnershipKind. There is a subtle thing occuring here. Since all |
| /// addresses are viewed from an ownership perspective as having trivial |
| /// ownership, this causes the verification to ignore address only |
| /// values. Once we transition to opaque values, the verification will |
| /// proceed. |
| /// |
| /// 3. All loadable sub-ManagedValues of an RValue must be of object |
| /// type. This means that if the lowered type of an RValue is loadable, then |
| /// the RValue's sub-parts must also be objects (i.e. not |
| /// addresses). Originally this was a hard invariant of RValue constructors, |
| /// but some parts of ArgEmission pass in addresses for loadable values. So |
| /// RValue loads them in the constructor. |
| /// |
| /// FIXME(opaque_values): Update invariant #2 once address only types are no |
| /// longer emitted by SILGen. |
| /// |
| /// *NOTE* In SILGen we don't try to explode structs, because doing so would |
| /// require considering resilience, a job we want to delegate to IRGen. |
| class RValue { |
| friend class swift::Lowering::Scope; |
| friend class swift::Lowering::ArgumentSource; |
| friend class swift::Lowering::CleanupCloner; |
| |
| std::vector<ManagedValue> values; |
| CanType type; |
| unsigned elementsToBeAdded; |
| |
| /// Flag value used to mark an rvalue as invalid. |
| /// |
| /// The reasons why this can be true is: |
| /// |
| /// 1. The RValue was consumed. |
| /// 2. The RValue was default-initialized. |
| /// 3. The RValue was emitted into an SGFContext initialization. |
| enum : unsigned { |
| Null = ~0U, |
| Used = Null - 1, |
| InContext = Used - 1, |
| }; |
| |
| bool isInSpecialState() const { |
| return elementsToBeAdded >= InContext; |
| } |
| |
| // Don't copy. |
| RValue(const RValue &) = delete; |
| RValue &operator=(const RValue &) = delete; |
| |
| void makeUsed() { |
| elementsToBeAdded = Used; |
| values = {}; |
| } |
| |
| /// Private constructor used by copy() and borrow(). |
| RValue(SILGenFunction &SGF, std::vector<ManagedValue> &&values, CanType type, |
| unsigned elementsToBeAdded) |
| : values(std::move(values)), type(type), |
| elementsToBeAdded(elementsToBeAdded) { |
| verify(SGF); |
| } |
| |
| /// Private constructor for RValue::extractElement and pre-exploded element |
| /// constructor. |
| /// |
| /// If SGF is nullptr, this constructor assumes that it is passed a |
| /// pre-exploded set of ManagedValues that have already been verified as being |
| /// RValue compatible since they once made up an RValue. If SGF is non-null, |
| /// then we verify as well that all objects of loadable type are actually |
| /// loaded (i.e. are objects). |
| /// |
| /// *NOTE* This constructor assumes that the constructed RValue is fully |
| /// formed and thus has elementsToBeAdded set to zero. |
| RValue(SILGenFunction *SGF, ArrayRef<ManagedValue> values, CanType type); |
| |
| RValue(unsigned state) : elementsToBeAdded(state) { |
| assert(isInSpecialState()); |
| } |
| |
| public: |
| RValue() : elementsToBeAdded(Null) {} |
| |
| RValue(RValue &&rv) : values(std::move(rv.values)), |
| type(rv.type), |
| elementsToBeAdded(rv.elementsToBeAdded) { |
| assert((rv.isComplete() || rv.isInSpecialState()) |
| && "moving rvalue that wasn't complete?!"); |
| rv.elementsToBeAdded = Used; |
| } |
| |
| RValue &operator=(RValue &&rv) { |
| assert((isNull() || isUsed()) && "reassigning an valid rvalue?!"); |
| |
| assert((rv.isComplete() || rv.isInSpecialState()) |
| && "moving rvalue that wasn't complete?!"); |
| values = std::move(rv.values); |
| type = rv.type; |
| elementsToBeAdded = rv.elementsToBeAdded; |
| rv.elementsToBeAdded = Used; |
| return *this; |
| } |
| |
| /// Create an RValue from a single value. If the value is of tuple type, it |
| /// will be exploded. |
| /// |
| /// \param expr - the expression which yielded this r-value; its type |
| /// will become the substituted formal type of this r-value |
| RValue(SILGenFunction &SGF, Expr *expr, ManagedValue v); |
| |
| /// Create an RValue from a single value. If the value is of tuple type, it |
| /// will be exploded. |
| RValue(SILGenFunction &SGF, SILLocation l, CanType type, ManagedValue v); |
| |
| /// Create a complete RValue from a pre-exploded set of elements. |
| /// |
| /// Since the RValue is assumed to be complete, no further values can be |
| /// added. |
| RValue(SILGenFunction &SGF, ArrayRef<ManagedValue> values, CanType type) |
| : RValue(&SGF, values, type) {} |
| |
| /// Creates an invalid RValue object, in an "in-context" state. |
| static RValue forInContext() { |
| return RValue(InContext); |
| } |
| |
| static unsigned getRValueSize(CanType substType); |
| static unsigned getRValueSize(AbstractionPattern origType, CanType substType); |
| |
| /// Create an RValue to which values will be subsequently added using |
| /// addElement(), with the level of tuple expansion in the input specified |
| /// by the abstraction pattern. The RValue will not be complete until all |
| /// the elements have been added. |
| explicit RValue(AbstractionPattern pattern, CanType type); |
| |
| /// Create an RValue to which values will be subsequently added using |
| /// addElement(). The RValue will not be complete until all the elements have |
| /// been added. |
| explicit RValue(CanType type); |
| |
| /// Return true if the rvalue was null-initialized. The intention is so one |
| /// can trampoline RValue results using if statements, i.e.: |
| /// |
| /// if (RValue rv = foo()) { |
| /// return rv; |
| /// } |
| operator bool() const & { return isComplete() || isInContext(); } |
| |
| /// True if the rvalue has been completely initialized by adding all its |
| /// elements. |
| bool isComplete() const & { return elementsToBeAdded == 0; } |
| |
| /// True if the rvalue was null-initialized. |
| bool isNull() const & { return elementsToBeAdded == Null; } |
| |
| /// True if this rvalue has been used. |
| bool isUsed() const & { return elementsToBeAdded == Used; } |
| |
| /// True if this rvalue was emitted into context. |
| bool isInContext() const & { return elementsToBeAdded == InContext; } |
| |
| /// Add an element to the rvalue. The rvalue must not yet be complete. |
| void addElement(RValue &&element) &; |
| |
| /// Add a ManagedValue element to the rvalue, exploding tuples if necessary. |
| /// The rvalue must not yet be complete. |
| void addElement(SILGenFunction &SGF, ManagedValue element, |
| CanType formalType, SILLocation l) &; |
| |
| /// Forward an rvalue into a single value, imploding tuples if necessary. |
| SILValue forwardAsSingleValue(SILGenFunction &SGF, SILLocation l) &&; |
| |
| /// Forward an rvalue into a single value, imploding tuples if necessary, and |
| /// introducing a potential conversion from semantic type to storage type. |
| SILValue forwardAsSingleStorageValue(SILGenFunction &SGF, |
| SILType storageType, |
| SILLocation l) &&; |
| |
| /// Get the rvalue as a single value, imploding tuples if necessary. |
| ManagedValue getAsSingleValue(SILGenFunction &SGF, SILLocation l) &&; |
| |
| /// Get the rvalue as a single unmanaged value, imploding tuples if necessary. |
| /// The values must not require any cleanups. |
| SILValue getUnmanagedSingleValue(SILGenFunction &SGF, SILLocation l) const &; |
| |
| ManagedValue getScalarValue() && { |
| assert(!isa<TupleType>(type) && "getScalarValue of a tuple rvalue"); |
| assert(values.size() == 1); |
| auto value = values[0]; |
| makeUsed(); |
| return value; |
| } |
| |
| /// Returns true if this is an rvalue that can be used safely as a +1 rvalue. |
| /// |
| /// This returns true iff: |
| /// |
| /// 1. All sub-values are trivially typed. |
| /// 2. There exists at least one non-trivial typed sub-value and all such |
| /// sub-values all have cleanups. |
| /// |
| /// *NOTE* Due to 1. isPlusOne and isPlusZero both return true for rvalues |
| /// consisting of only trivial values. |
| bool isPlusOne(SILGenFunction &SGF) const &; |
| |
| /// Returns true if this is an rvalue that can be used safely as a +0 rvalue. |
| /// |
| /// 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 rvalues |
| /// consisting of only trivial values. |
| bool isPlusZero(SILGenFunction &SGF) const &; |
| |
| /// Use this rvalue to initialize an Initialization. |
| void forwardInto(SILGenFunction &SGF, SILLocation loc, Initialization *I) &&; |
| |
| /// Copy this rvalue to initialize an Initialization without consuming the |
| /// rvalue. |
| void copyInto(SILGenFunction &SGF, SILLocation loc, Initialization *I) const&; |
| |
| /// Assign this r-value into the destination. |
| void assignInto(SILGenFunction &SGF, SILLocation loc, SILValue destAddr) &&; |
| |
| /// Forward the exploded SILValues into a SmallVector. |
| void forwardAll(SILGenFunction &SGF, |
| SmallVectorImpl<SILValue> &values) &&; |
| |
| ManagedValue materialize(SILGenFunction &SGF, SILLocation loc) &&; |
| |
| /// Take the ManagedValues from this RValue into a SmallVector. |
| void getAll(SmallVectorImpl<ManagedValue> &values) &&; |
| |
| /// Store the unmanaged SILValues into a SmallVector. The values must not |
| /// require any cleanups. |
| void getAllUnmanaged(SmallVectorImpl<SILValue> &values) const &; |
| |
| /// Extract a single tuple element from the rvalue. |
| RValue extractElement(unsigned element) &&; |
| |
| /// Extract the tuple elements from the rvalue. |
| void extractElements(SmallVectorImpl<RValue> &elements) &&; |
| |
| CanType getType() const & { return type; } |
| |
| /// Return the lowered type associated with the given CanType's type lowering. |
| SILType getLoweredType(SILGenFunction &SGF) const &; |
| |
| /// Return the type lowering of RValue::getType(). |
| const Lowering::TypeLowering &getTypeLowering(SILGenFunction &SGF) const &; |
| |
| /// Return the lowered SILType that would be used to implode the given RValue |
| /// into 1 tuple value. |
| /// |
| /// This means that if any sub-objects are address only, an address type will |
| /// be returned. Otherwise, an object will be returned. So this is a |
| /// convenient way to determine if an RValue needs an address. |
| SILType getLoweredImplodedTupleType(SILGenFunction &SGF) const &; |
| |
| /// Emit an equivalent value with independent ownership. |
| RValue copy(SILGenFunction &SGF, SILLocation loc) const &; |
| |
| /// If this RValue is a +0 value, copy the RValue and return. Otherwise, |
| /// return std::move(*this); |
| RValue ensurePlusOne(SILGenFunction &SGF, SILLocation loc) &&; |
| |
| /// Borrow all subvalues of the rvalue. |
| RValue borrow(SILGenFunction &SGF, SILLocation loc) const &; |
| |
| RValue copyForDiagnostics() const; |
| |
| static bool areObviouslySameValue(SILValue lhs, SILValue rhs); |
| bool isObviouslyEqual(const RValue &rhs) const; |
| |
| void dump() const; |
| void dump(raw_ostream &OS, unsigned indent = 0) const; |
| |
| /// Verify RValue invariants. |
| /// |
| /// This checks ownership invariants and also checks that all sub managed |
| /// values that are loadable are actually objects. |
| /// |
| /// *NOTE* This is a no-op in non-assert builds. |
| void verify(SILGenFunction &SGF) const &; |
| }; |
| |
| } // end namespace Lowering |
| } // end namespace swift |
| |
| #endif |