//===--- RValue.h - Exploded RValue Representation --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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_RVALUE_H #define SWIFT_LOWERING_RVALUE_H #include "ManagedValue.h" #include "SILGenFunction.h" #include "llvm/ADT/SmallVector.h" namespace swift { namespace Lowering { class Initialization; /// An "exploded" SIL rvalue, in which tuple values are recursively /// destructured. (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 { std::vector values; CanType type; unsigned elementsToBeAdded; /// Flag value used to mark an rvalue as invalid, because it was /// consumed or it was default-initialized. enum : unsigned { Used = ~0U }; // Don't copy. RValue(const RValue &) = delete; RValue &operator=(const RValue &) = delete; void makeUsed() { elementsToBeAdded = Used; values = {}; } /// Private constructor used by copy(). RValue(const RValue &copied, SILGenFunction &gen, SILLocation l); public: /// Creates an invalid RValue object, in a "used" state. RValue() : elementsToBeAdded(Used) {} RValue(RValue &&rv) : values(std::move(rv.values)), type(rv.type), elementsToBeAdded(rv.elementsToBeAdded) { assert((rv.isComplete() || rv.isUsed()) && "moving rvalue that wasn't complete?!"); rv.elementsToBeAdded = Used; } RValue &operator=(RValue &&rv) { assert(isUsed() && "reassigning an unused rvalue?!"); assert((rv.isComplete() || rv.isUsed()) && "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 &gen, Expr *expr, ManagedValue v); /// Create an RValue from a single value. If the value is of tuple type, it /// will be exploded. RValue(SILGenFunction &gen, SILLocation l, CanType type, ManagedValue v); /// Construct an RValue from a pre-exploded set of /// ManagedValues. Used to implement the extractElement* methods. RValue(ArrayRef values, CanType type); /// 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); /// True if the rvalue has been completely initialized by adding all its /// elements. bool isComplete() const & { return elementsToBeAdded == 0; } /// True if this rvalue has been used. bool isUsed() const & { return elementsToBeAdded == Used; } explicit operator bool() const & { return !isUsed(); } /// True if this rvalue was emitted into context. bool isInContext() const & { return isUsed(); } /// True if this represents an lvalue. bool isLValue() const & { return isa(type); } /// 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 &gen, ManagedValue element, CanType formalType, SILLocation l) &; /// Forward an rvalue into a single value, imploding tuples if necessary. SILValue forwardAsSingleValue(SILGenFunction &gen, 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 &gen, SILType storageType, SILLocation l) &&; /// Get the rvalue as a single value, imploding tuples if necessary. ManagedValue getAsSingleValue(SILGenFunction &gen, SILLocation l) &&; /// Get the rvalue as a single unmanaged value, imploding tuples if necessary. /// The values must not require any cleanups. SILValue getUnmanagedSingleValue(SILGenFunction &gen, SILLocation l) const &; /// Peek at the single scalar value backing this rvalue without consuming it. /// The rvalue must not be of a tuple type. SILValue peekScalarValue() const & { assert(!isa(type) && "peekScalarValue of a tuple rvalue"); assert(values.size() == 1 && "exploded scalar value?!"); return values[0].getValue(); } /// Peek at the single ManagedValue backing this rvalue without consuming it /// and return true if the value is not at +1. bool peekIsPlusZeroRValueOrTrivial() const & { assert(!isa(type) && "peekScalarValue of a tuple rvalue"); assert(values.size() == 1 && "exploded scalar value?!"); return values[0].isPlusZeroRValueOrTrivial(); } ManagedValue getScalarValue() && { assert(!isa(type) && "getScalarValue of a tuple rvalue"); assert(values.size() == 1); auto value = values[0]; makeUsed(); return value; } /// Use this rvalue to initialize an Initialization. void forwardInto(SILGenFunction &gen, SILLocation loc, Initialization *I) &&; /// Copy this rvalue to initialize an Initialization without consuming the /// rvalue. void copyInto(SILGenFunction &gen, SILLocation loc, Initialization *I) const&; /// Assign this r-value into the destination. void assignInto(SILGenFunction &gen, SILLocation loc, SILValue destAddr) &&; /// Forward the exploded SILValues into a SmallVector. void forwardAll(SILGenFunction &gen, SmallVectorImpl &values) &&; ManagedValue materialize(SILGenFunction &gen, SILLocation loc) &&; /// Take the ManagedValues from this RValue into a SmallVector. void getAll(SmallVectorImpl &values) &&; /// Store the unmanaged SILValues into a SmallVector. The values must not /// require any cleanups. void getAllUnmanaged(SmallVectorImpl &values) const &; /// Extract a single tuple element from the rvalue. RValue extractElement(unsigned element) &&; /// Extract the tuple elements from the rvalue. void extractElements(SmallVectorImpl &elements) &&; CanType getType() const & { return type; } /// Rewrite the type of this r-value. void rewriteType(CanType newType) & { // We only allow a very modest set of changes to a type. assert(newType == type || (isa(newType) && cast(newType)->getNumElements() == 1 && cast(newType).getElementType(0) == type)); type = newType; } /// Emit an equivalent value with independent ownership. RValue copy(SILGenFunction &gen, SILLocation l) const & { return RValue(*this, gen, l); } bool isObviouslyEqual(const RValue &rhs) const { assert(isComplete() && rhs.isComplete() && "Comparing incomplete rvalues"); // Compare the count of elements instead of the type. if (values.size() != rhs.values.size()) return false; return std::equal(values.begin(), values.end(), rhs.values.begin(), [](const ManagedValue &lhs, const ManagedValue &rhs) -> bool { return lhs.getValue() == rhs.getValue() && lhs.getCleanup() == rhs.getCleanup(); }); } }; } // end namespace Lowering } // end namespace swift #endif