1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
|
//===--- 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/Assertions.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 occurring 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 &;
SILType getTypeOfSingleValue() const & {
assert(isComplete() && values.size() == 1);
return values[0].getType();
}
ManagedValue getScalarValue() && {
if (isInContext()) {
makeUsed();
return ManagedValue::forInContext();
}
assert(!isa<TupleType>(type) && "getScalarValue of a tuple rvalue");
assert(values.size() == 1);
auto value = values[0];
makeUsed();
return value;
}
/// Returns true if this rvalue can be consumed.
///
/// This is true if each element either has a cleanup or is an SSA value
/// without ownership.
///
/// When an SSA value does not have ownership, it can be used by a consuming
/// operation without destroying it. Consuming a value by address, however,
/// deinitializes the memory regardless of whether the value has ownership.
bool isPlusOne(SILGenFunction &SGF) const &;
/// Returns true if this rvalue can be forwarded without necessarilly
/// destroying the original.
///
/// This is true if either isPlusOne is true or the value is trivial. A
/// trivial value in memory can be forwarded as a +1 value without
/// deinitializing the memory.
bool isPlusOneOrTrivial(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
|