mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
a closure expression, then don't actually do it. The long term plan is to actually do this, which should just be a matter of taking some of the code out of reabstraction thunk emission and using it in prolog/epilog/return emission. In the short term, the goal is just to get the conversion information down to the closure emitter so that we can see that we're erasing into an `@isolated(any)` type and then actually erase the closure's isolation properly instead of relying on type-based erasure, which can't handle parameter/capture isolation correctly.
180 lines
6.2 KiB
C++
180 lines
6.2 KiB
C++
//===--- SGFContext.h - Expression emission context -------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILGEN_SGFCONTEXT_H
|
|
#define SWIFT_SILGEN_SGFCONTEXT_H
|
|
|
|
#include "Initialization.h"
|
|
|
|
namespace swift {
|
|
namespace Lowering {
|
|
|
|
/// Internal context information for the SILGenFunction visitor.
|
|
///
|
|
/// In general, emission methods which take an SGFContext indicate
|
|
/// that they've initialized the emit-into buffer (if they have) by
|
|
/// returning a "isInContext()" ManagedValue of whatever type. Callers who
|
|
/// propagate down an SGFContext that might have an emit-into buffer must be
|
|
/// aware of this.
|
|
///
|
|
/// Clients of emission routines that take an SGFContext can also specify that
|
|
/// they are ok getting back an RValue at +0 instead of requiring it to be at
|
|
/// +1. The client is then responsible for checking the ManagedValue to see if
|
|
/// it got back a ManagedValue at +0 or +1.
|
|
class SGFContext {
|
|
enum DesiredTransfer {
|
|
PlusOne,
|
|
ImmediatePlusZero,
|
|
GuaranteedPlusZero,
|
|
};
|
|
llvm::PointerIntPair<Initialization *, 2, DesiredTransfer> state;
|
|
public:
|
|
SGFContext() = default;
|
|
|
|
enum AllowImmediatePlusZero_t {
|
|
/// The client is okay with getting a +0 value and plans to use it
|
|
/// immediately.
|
|
///
|
|
/// For example, in this context, it would be okay to return +0
|
|
/// even for a load from a mutable variable, because the only way
|
|
/// the value could be invalidated before it's used is a race
|
|
/// condition.
|
|
AllowImmediatePlusZero
|
|
};
|
|
|
|
enum AllowGuaranteedPlusZero_t {
|
|
/// The client is okay with getting a +0 value as long as it's
|
|
/// guaranteed to last at least as long as the current evaluation.
|
|
/// (For expression evaluation, this generally means at least
|
|
/// until the end of the current statement.)
|
|
///
|
|
/// For example, in this context, it would be okay to return +0
|
|
/// for a reference to a local 'let' because that will last until
|
|
/// the 'let' goes out of scope. However, it would not be okay to
|
|
/// return +0 for a load from a mutable 'var', because that could
|
|
/// be mutated before the end of the statement.
|
|
AllowGuaranteedPlusZero
|
|
};
|
|
|
|
/// Creates an emitInto context that will store the result of the visited expr
|
|
/// into the given Initialization.
|
|
explicit SGFContext(Initialization *emitInto) : state(emitInto, PlusOne) {
|
|
}
|
|
|
|
/*implicit*/
|
|
SGFContext(AllowImmediatePlusZero_t) : state(nullptr, ImmediatePlusZero) {
|
|
}
|
|
|
|
/*implicit*/
|
|
SGFContext(AllowGuaranteedPlusZero_t) : state(nullptr, GuaranteedPlusZero) {
|
|
}
|
|
|
|
/// Returns a pointer to the Initialization that the current expression should
|
|
/// store its result to, or null if the expression should allocate temporary
|
|
/// storage for its result.
|
|
Initialization *getEmitInto() const {
|
|
return state.getPointer();
|
|
}
|
|
|
|
/// Try to get the address of the emit-into initialization if we can.
|
|
/// Otherwise, return an empty SILValue.
|
|
///
|
|
/// Note that, if this returns a non-empty address, the caller must
|
|
/// finish the emit-into initialization.
|
|
SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
|
|
SILLocation loc) const {
|
|
if (auto *init = getEmitInto()) {
|
|
if (init->canPerformInPlaceInitialization())
|
|
return init->getAddressForInPlaceInitialization(SGF, loc);
|
|
}
|
|
return SILValue();
|
|
}
|
|
|
|
/// If getAddressForInPlaceInitialization did (or would have)
|
|
/// returned a non-null address, finish the initialization and
|
|
/// return true. Otherwise, return false.
|
|
bool finishInPlaceInitialization(SILGenFunction &SGF) const {
|
|
if (auto *init = getEmitInto()) {
|
|
if (init->canPerformInPlaceInitialization()) {
|
|
init->finishInitialization(SGF);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Try to get this context as a conversion initialization.
|
|
///
|
|
/// This does not commit the caller to anything, whether it succeeds
|
|
/// or fails.
|
|
ConvertingInitialization *getAsConversion() const {
|
|
if (auto init = getEmitInto())
|
|
return init->getAsConversion();
|
|
return nullptr;
|
|
}
|
|
|
|
/// Return true if a ManagedValue producer is allowed to return at
|
|
/// +0, given that it cannot guarantee that the value will be valid
|
|
/// until the end of the current evaluation.
|
|
bool isImmediatePlusZeroOk() const {
|
|
return state.getInt() == ImmediatePlusZero;
|
|
}
|
|
|
|
/// Return true if a ManagedValue producer is allowed to return at
|
|
/// +0 if it can guarantee that the value will be valid until the
|
|
/// end of the current evaluation.
|
|
bool isGuaranteedPlusZeroOk() const {
|
|
// Either ImmediatePlusZero or GuaranteedPlusZero is fine.
|
|
return state.getInt() >= ImmediatePlusZero;
|
|
}
|
|
|
|
/// Get a context for a sub-expression given that arbitrary side
|
|
/// effects may follow the subevaluation.
|
|
SGFContext withFollowingSideEffects() const {
|
|
SGFContext copy = *this;
|
|
if (copy.state.getInt() == ImmediatePlusZero) {
|
|
copy.state.setInt(GuaranteedPlusZero);
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
/// Get a context for a sub-expression where we plan to project out
|
|
/// a value. The Initialization is not okay to propagate down, but
|
|
/// the +0/+1-ness is.
|
|
SGFContext withFollowingProjection() const {
|
|
SGFContext result;
|
|
result.state.setInt(state.getInt());
|
|
return result;
|
|
}
|
|
|
|
/// Get a context for a sub-expression where we plan to evaluate arbitrary
|
|
/// side-effects. This means we propagate down the initialization, but
|
|
/// eliminates the +0/+1-ness.
|
|
SGFContext withSubExprSideEffects() const {
|
|
if (auto *init = getEmitInto()) {
|
|
return SGFContext(init);
|
|
}
|
|
|
|
return SGFContext();
|
|
}
|
|
};
|
|
|
|
using ValueProducerRef =
|
|
llvm::function_ref<ManagedValue(SILGenFunction &SGF, SILLocation loc,
|
|
SGFContext context)>;
|
|
|
|
} // end namespace Lowering
|
|
} // end namespace swift
|
|
|
|
#endif
|