mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1751 lines
68 KiB
C++
1751 lines
68 KiB
C++
//===--- SILGenProlog.cpp - Function prologue emission --------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ArgumentSource.h"
|
|
#include "ExecutorBreadcrumb.h"
|
|
#include "FunctionInputGenerator.h"
|
|
#include "Initialization.h"
|
|
#include "ManagedValue.h"
|
|
#include "SILGenFunction.h"
|
|
#include "Scope.h"
|
|
|
|
#include "swift/AST/CanTypeVisitor.h"
|
|
#include "swift/AST/DiagnosticsSIL.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/PropertyWrappers.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Defer.h"
|
|
#include "swift/Basic/Generators.h"
|
|
#include "swift/SIL/SILArgument.h"
|
|
#include "swift/SIL/SILArgumentConvention.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
template <typename... T, typename... U>
|
|
static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
|
|
U &&...args) {
|
|
Context.Diags.diagnose(loc, diag, std::forward<U>(args)...);
|
|
}
|
|
|
|
SILValue SILGenFunction::emitSelfDeclForDestructor(VarDecl *selfDecl) {
|
|
SILFunctionConventions conventions = F.getConventionsInContext();
|
|
|
|
// Emit the implicit 'self' argument.
|
|
SILType selfType = conventions.getSILArgumentType(
|
|
conventions.getNumSILArguments() - 1, F.getTypeExpansionContext());
|
|
selfType = F.mapTypeIntoContext(selfType);
|
|
SILValue selfValue = F.begin()->createFunctionArgument(selfType, selfDecl);
|
|
|
|
uint16_t ArgNo = 1; // Hardcoded for destructors.
|
|
auto dv = SILDebugVariable(selfDecl->isLet(), ArgNo);
|
|
|
|
// If we have a move only type, then mark it with
|
|
// mark_unresolved_non_copyable_value so we can't escape it.
|
|
//
|
|
// For now, we do not handle move only class deinits. This is because we need
|
|
// to do a bit more refactoring to handle the weird way that it deals with
|
|
// ownership. But for simple move only deinits (like struct/enum), that are
|
|
// owned, lets mark them as needing to be no implicit copy checked so they
|
|
// cannot escape.
|
|
if (selfType.isMoveOnly() && !selfType.isAnyClassReferenceType()) {
|
|
SILValue addr = B.createAllocStack(selfDecl, selfValue->getType(), dv);
|
|
addr = B.createMarkUnresolvedNonCopyableValueInst(
|
|
selfDecl, addr,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::ConsumableAndAssignable);
|
|
if (selfValue->getType().isObject()) {
|
|
B.createStore(selfDecl, selfValue, addr, StoreOwnershipQualifier::Init);
|
|
} else {
|
|
B.createCopyAddr(selfDecl, selfValue, addr, IsTake, IsInitialization);
|
|
}
|
|
// drop_deinit invalidates any user-defined struct/enum deinit
|
|
// before the individual members are destroyed.
|
|
addr = B.createDropDeinit(selfDecl, addr);
|
|
selfValue = addr;
|
|
}
|
|
|
|
VarLocs[selfDecl] = VarLoc(selfValue, SILAccessEnforcement::Unknown);
|
|
SILLocation PrologueLoc(selfDecl);
|
|
PrologueLoc.markAsPrologue();
|
|
B.emitDebugDescription(PrologueLoc, selfValue, dv);
|
|
return selfValue;
|
|
}
|
|
|
|
namespace {
|
|
struct LoweredParamGenerator {
|
|
SILGenFunction &SGF;
|
|
CanSILFunctionType fnTy;
|
|
ArrayRefGenerator<ArrayRef<SILParameterInfo>> parameterTypes;
|
|
|
|
LoweredParamGenerator(SILGenFunction &SGF,
|
|
unsigned numIgnoredTrailingParameters)
|
|
: SGF(SGF), fnTy(SGF.F.getLoweredFunctionType()),
|
|
parameterTypes(
|
|
SGF.F.getLoweredFunctionTypeInContext()
|
|
->getParameters().drop_back(numIgnoredTrailingParameters)) {}
|
|
|
|
ParamDecl *paramDecl = nullptr;
|
|
bool isNoImplicitCopy = false;
|
|
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None;
|
|
bool isImplicitParameter = false;
|
|
|
|
void configureParamData(ParamDecl *paramDecl, bool isNoImplicitCopy,
|
|
LifetimeAnnotation lifetimeAnnotation) {
|
|
this->paramDecl = paramDecl;
|
|
this->isNoImplicitCopy = isNoImplicitCopy;
|
|
this->lifetimeAnnotation = lifetimeAnnotation;
|
|
this->isImplicitParameter = false;
|
|
}
|
|
|
|
void configureParamDataForImplicitParam() { isImplicitParameter = true; }
|
|
|
|
void resetParamData() {
|
|
configureParamData(nullptr, false, LifetimeAnnotation::None);
|
|
}
|
|
|
|
ManagedValue claimNext() {
|
|
auto parameterInfo = parameterTypes.claimNext();
|
|
|
|
// We should only be called without a param decl when pulling pack
|
|
// parameters out for multiple formal parameters (or a single formal
|
|
// parameter pack) or if we have an implicit parameter.
|
|
//
|
|
// TODO: preserve the parameters captured by the pack into the SIL
|
|
// representation.
|
|
bool isFormalParameterPack = (paramDecl == nullptr) && !isImplicitParameter;
|
|
assert(!isFormalParameterPack || parameterInfo.isPack());
|
|
|
|
auto paramType =
|
|
SGF.F.mapTypeIntoContext(SGF.getSILType(parameterInfo, fnTy));
|
|
ManagedValue mv = SGF.B.createInputFunctionArgument(
|
|
paramType, paramDecl, isNoImplicitCopy, lifetimeAnnotation,
|
|
/*isClosureCapture*/ false, isFormalParameterPack, isImplicitParameter);
|
|
return mv;
|
|
}
|
|
|
|
std::optional<SILParameterInfo> peek() const {
|
|
if (isFinished())
|
|
return {};
|
|
return parameterTypes.get();
|
|
}
|
|
|
|
bool isFinished() const {
|
|
return parameterTypes.isFinished();
|
|
}
|
|
|
|
void advance() {
|
|
(void) claimNext();
|
|
}
|
|
|
|
void finish() {
|
|
parameterTypes.finish();
|
|
}
|
|
};
|
|
|
|
struct WritebackReabstractedInoutCleanup final : Cleanup {
|
|
SILValue OrigAddress, SubstAddress;
|
|
AbstractionPattern OrigTy;
|
|
CanType SubstTy;
|
|
WritebackReabstractedInoutCleanup(SILValue origAddress, SILValue substAddress,
|
|
AbstractionPattern origTy,
|
|
CanType substTy)
|
|
: OrigAddress(origAddress), SubstAddress(substAddress),
|
|
OrigTy(origTy), SubstTy(substTy)
|
|
{}
|
|
|
|
void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind)
|
|
override {
|
|
Scope s(SGF.Cleanups, l);
|
|
// Load the final local value coming in.
|
|
auto mv = SGF.emitLoad(l, SubstAddress,
|
|
SGF.getTypeLowering(SubstAddress->getType()),
|
|
SGFContext(), IsTake);
|
|
// Reabstract the value back to the original representation.
|
|
mv = SGF.emitSubstToOrigValue(l, mv.ensurePlusOne(SGF, l),
|
|
OrigTy, SubstTy);
|
|
// Write it back to the original inout parameter.
|
|
SGF.B.createStore(l, mv.forward(SGF), OrigAddress,
|
|
StoreOwnershipQualifier::Init);
|
|
}
|
|
|
|
void dump(SILGenFunction&) const override {
|
|
llvm::errs() << "WritebackReabstractedInoutCleanup\n";
|
|
OrigAddress->print(llvm::errs());
|
|
SubstAddress->print(llvm::errs());
|
|
}
|
|
};
|
|
|
|
class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
|
|
/*RetTy*/ ManagedValue,
|
|
/*ArgTys...*/ AbstractionPattern,
|
|
Initialization *>
|
|
{
|
|
public:
|
|
SILGenFunction &SGF;
|
|
SILLocation loc;
|
|
LoweredParamGenerator ¶meters;
|
|
|
|
EmitBBArguments(SILLocation l, LoweredParamGenerator ¶meters)
|
|
: SGF(parameters.SGF), loc(l), parameters(parameters) {}
|
|
|
|
ManagedValue claimNextParameter() {
|
|
return parameters.claimNext();
|
|
}
|
|
|
|
ManagedValue handleParam(AbstractionPattern origType, CanType substType,
|
|
ParamDecl *pd, bool isAddressable) {
|
|
// Note: inouts of tuples are not exploded, so we bypass visit().
|
|
if (pd->isInOut()) {
|
|
return handleInOut(origType, substType, pd->isAddressable());
|
|
}
|
|
// Addressability also suppresses exploding the parameter.
|
|
if (isAddressable) {
|
|
return handleScalar(claimNextParameter(),
|
|
AbstractionPattern::getOpaque(), substType,
|
|
/*emitInto*/ nullptr,
|
|
/*inout*/ false, /*addressable*/ true);
|
|
}
|
|
return visit(substType, origType, /*emitInto*/ nullptr);
|
|
}
|
|
|
|
ManagedValue handlePackComponent(FunctionInputGenerator &formalParam) {
|
|
auto origPatternType =
|
|
formalParam.getOrigType().getPackExpansionPatternType();
|
|
|
|
auto substParam = formalParam.getSubstParam();
|
|
CanType substType = substParam.getParameterType();
|
|
|
|
// Forward the pack cleanup and enter a new cleanup for the
|
|
// remaining components.
|
|
auto componentValue = formalParam.projectPackComponent(SGF, loc);
|
|
|
|
// Handle scalar components.
|
|
if (!isa<PackExpansionType>(substType)) {
|
|
return handleScalar(componentValue, origPatternType, substType,
|
|
/*emit into*/ nullptr,
|
|
substParam.isInOut(),
|
|
/*is addressable*/ false);
|
|
}
|
|
|
|
auto componentPackTy = componentValue.getType().castTo<SILPackType>();
|
|
|
|
// Handle pack expansion components.
|
|
auto formalPackType = formalParam.getFormalPackType();
|
|
auto componentIndex = formalParam.getPackComponentIndex();
|
|
|
|
auto expectedExpansionTy = SGF.getLoweredRValueType(substType);
|
|
auto expectedPackTy =
|
|
SILPackType::get(SGF.getASTContext(), componentPackTy->getExtInfo(),
|
|
{expectedExpansionTy});
|
|
|
|
// If we don't need a pack transformation, this is simple.
|
|
// This is simultaneously testing that we don't need a transformation
|
|
// and that we don't have other components in the pack.
|
|
if (componentPackTy == expectedPackTy) {
|
|
return componentValue;
|
|
}
|
|
|
|
// FIXME: perform this forwarding by just slicing the original pack.
|
|
bool canForward =
|
|
(expectedExpansionTy == componentPackTy->getElementType(componentIndex));
|
|
|
|
auto rawOutputPackAddr =
|
|
SGF.emitTemporaryPackAllocation(loc,
|
|
SILType::getPrimitiveObjectType(expectedPackTy));
|
|
auto outputFormalPackType =
|
|
CanPackType::get(SGF.getASTContext(), {substType});
|
|
return SGF.emitPackTransform(loc, componentValue,
|
|
formalPackType, componentIndex,
|
|
rawOutputPackAddr, outputFormalPackType, 0,
|
|
canForward, /*plus one*/ !canForward,
|
|
[&](ManagedValue input, SILType outputTy,
|
|
SGFContext context) {
|
|
if (canForward) return input;
|
|
|
|
auto substEltType =
|
|
cast<PackExpansionType>(substType).getPatternType();
|
|
if (auto openedEnv = SGF.getInnermostPackExpansion()->OpenedElementEnv) {
|
|
substEltType =
|
|
openedEnv->mapContextualPackTypeIntoElementContext(substEltType);
|
|
}
|
|
|
|
return handleScalar(input, origPatternType, substEltType,
|
|
context.getEmitInto(),
|
|
/*inout*/ false,
|
|
/*addressable*/ false);
|
|
});
|
|
}
|
|
|
|
ManagedValue visitType(CanType t, AbstractionPattern orig,
|
|
Initialization *emitInto) {
|
|
auto mv = claimNextParameter();
|
|
return handleScalar(mv, orig, t, emitInto,
|
|
/*inout*/ false,
|
|
/*addressable*/ false);
|
|
}
|
|
|
|
ManagedValue handleInOut(AbstractionPattern orig, CanType t,
|
|
bool isAddressable) {
|
|
auto mv = claimNextParameter();
|
|
return handleScalar(mv, orig, t, /*emitInto*/ nullptr,
|
|
/*inout*/ true,
|
|
isAddressable);
|
|
}
|
|
|
|
ManagedValue handleScalar(ManagedValue mv,
|
|
AbstractionPattern orig, CanType t,
|
|
Initialization *emitInto,
|
|
bool isInOut,
|
|
bool isAddressable) {
|
|
assert(!(isInOut && emitInto != nullptr));
|
|
|
|
auto argType = SGF.getLoweredType(t, mv.getType().getCategory());
|
|
|
|
// This is a hack to deal with the fact that Self.Type comes in as a static
|
|
// metatype, but we have to downcast it to a dynamic Self metatype to get
|
|
// the right semantics.
|
|
if (argType != mv.getType()) {
|
|
if (auto argMetaTy = argType.getAs<MetatypeType>()) {
|
|
if (auto argSelfTy = dyn_cast<DynamicSelfType>(argMetaTy.getInstanceType())) {
|
|
assert(argSelfTy.getSelfType()
|
|
== mv.getType().castTo<MetatypeType>().getInstanceType());
|
|
mv = SGF.B.createUncheckedBitCast(loc, mv, argType);
|
|
}
|
|
}
|
|
}
|
|
if (isInOut) {
|
|
// If we are inout and are move only, insert a note to the move checker to
|
|
// check ownership.
|
|
if (mv.getType().isMoveOnly() && !mv.getType().isMoveOnlyWrapped())
|
|
mv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, mv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable);
|
|
|
|
// If the value needs to be reabstracted, set up a shadow copy with
|
|
// writeback here.
|
|
if (argType.getASTType() != mv.getType().getASTType()) {
|
|
// Load the value coming in.
|
|
auto origBuf = mv.getValue();
|
|
mv = SGF.emitLoad(loc, origBuf, SGF.getTypeLowering(mv.getType()), SGFContext(), IsTake);
|
|
// Reabstract the value if necessary.
|
|
mv = SGF.emitOrigToSubstValue(loc, mv.ensurePlusOne(SGF, loc), orig, t);
|
|
// Store the value to a local buffer.
|
|
auto substBuf = SGF.emitTemporaryAllocation(loc, argType);
|
|
SGF.B.createStore(loc, mv.forward(SGF), substBuf, StoreOwnershipQualifier::Init);
|
|
// Introduce a writeback to put the final value back in the inout.
|
|
SGF.Cleanups.pushCleanup<WritebackReabstractedInoutCleanup>(origBuf, substBuf, orig, t);
|
|
mv = ManagedValue::forLValue(substBuf);
|
|
}
|
|
|
|
return mv;
|
|
}
|
|
|
|
// If the parameter is marked `@_addressable`, then we want to defer any
|
|
// reabstraction of the parameter as received, so that we can use the
|
|
// original value at its stable address when possible.
|
|
bool argIsLoadable = false;
|
|
if (!isAddressable) {
|
|
argIsLoadable = argType.isLoadable(SGF.F);
|
|
// This can happen if the value is resilient in the calling convention
|
|
// but not resilient locally.
|
|
if (argIsLoadable) {
|
|
if (argType.isAddress()) {
|
|
mv = SGF.B.createLoadWithSameOwnership(loc, mv);
|
|
argType = argType.getObjectType();
|
|
}
|
|
}
|
|
|
|
assert(argType.getCategory() == mv.getType().getCategory());
|
|
if (argType.getASTType() != mv.getType().getASTType()) {
|
|
// Reabstract the value if necessary.
|
|
mv = SGF.emitOrigToSubstValue(loc, mv.ensurePlusOne(SGF, loc), orig, t);
|
|
}
|
|
}
|
|
|
|
if (parameters.isNoImplicitCopy && !argIsLoadable) {
|
|
// We do not support no implicit copy address only types. Emit an error.
|
|
auto diag = diag::noimplicitcopy_used_on_generic_or_existential;
|
|
diagnose(SGF.getASTContext(), mv.getValue().getLoc().getSourceLoc(),
|
|
diag);
|
|
}
|
|
|
|
// If the value is a (possibly optional) ObjC block passed into the entry
|
|
// point of the function, then copy it so we can treat the value reliably
|
|
// as a heap object. Escape analysis can eliminate this copy if it's
|
|
// unneeded during optimization.
|
|
CanType objectType = t;
|
|
if (auto theObjTy = t.getOptionalObjectType())
|
|
objectType = theObjTy;
|
|
if (isa<FunctionType>(objectType) &&
|
|
cast<FunctionType>(objectType)->getRepresentation()
|
|
== FunctionType::Representation::Block) {
|
|
SILValue blockCopy = SGF.B.createCopyBlock(loc, mv.getValue());
|
|
mv = SGF.emitManagedRValueWithCleanup(blockCopy);
|
|
}
|
|
|
|
if (emitInto) {
|
|
if (mv.isPlusOneOrTrivial(SGF))
|
|
mv.forwardInto(SGF, loc, emitInto);
|
|
else
|
|
mv.copyInto(SGF, loc, emitInto);
|
|
return ManagedValue::forInContext();
|
|
}
|
|
|
|
return mv;
|
|
}
|
|
|
|
ManagedValue visitPackExpansionType(CanPackExpansionType t,
|
|
AbstractionPattern orig,
|
|
Initialization *emitInto) {
|
|
// Pack expansions in the formal parameter list are made
|
|
// concrete as packs.
|
|
return visitType(PackType::get(SGF.getASTContext(), {t})
|
|
->getCanonicalType(),
|
|
orig, emitInto);
|
|
}
|
|
|
|
ManagedValue visitTupleType(CanTupleType t, AbstractionPattern orig,
|
|
Initialization *emitInto) {
|
|
// Only destructure if the abstraction pattern is also a tuple.
|
|
if (!orig.isTuple())
|
|
return visitType(t, orig, emitInto);
|
|
|
|
auto &tl = SGF.SGM.Types.getTypeLowering(t, SGF.getTypeExpansionContext());
|
|
|
|
// If the tuple contains pack expansions, and we're not emitting
|
|
// into an initialization already, create a temporary so that we're
|
|
// always emitting into an initialization.
|
|
if (t.containsPackExpansionType() && !emitInto) {
|
|
auto temporary = SGF.emitTemporary(loc, tl);
|
|
|
|
auto result = expandTuple(orig, t, tl, temporary.get());
|
|
assert(result.isInContext()); (void) result;
|
|
|
|
return temporary->getManagedAddress();
|
|
}
|
|
|
|
return expandTuple(orig, t, tl, emitInto);
|
|
}
|
|
|
|
ManagedValue expandTuple(AbstractionPattern orig, CanTupleType t,
|
|
const TypeLowering &tl, Initialization *init) {
|
|
assert((!t.containsPackExpansionType() || init) &&
|
|
"should always have an emission context when expanding "
|
|
"a tuple containing pack expansions");
|
|
|
|
bool canBeGuaranteed = tl.isLoadable();
|
|
|
|
// We only use specific initializations here that can always be split.
|
|
SmallVector<InitializationPtr, 8> eltInitsBuffer;
|
|
MutableArrayRef<InitializationPtr> eltInits;
|
|
if (init) {
|
|
assert(init->canSplitIntoTupleElements());
|
|
eltInits = init->splitIntoTupleElements(SGF, loc, t, eltInitsBuffer);
|
|
}
|
|
|
|
// Collect the exploded elements.
|
|
//
|
|
// Reabstraction can give us original types that are pack
|
|
// expansions without having pack expansions in the result.
|
|
// In this case, we do not need to force emission into a pack
|
|
// expansion.
|
|
SmallVector<ManagedValue, 4> elements;
|
|
orig.forEachTupleElement(t, [&](TupleElementGenerator &elt) {
|
|
auto origEltType = elt.getOrigType();
|
|
auto substEltTypes = elt.getSubstTypes();
|
|
if (!elt.isOrigPackExpansion()) {
|
|
auto eltValue =
|
|
visit(substEltTypes[0], origEltType,
|
|
init ? eltInits[elt.getSubstIndex()].get() : nullptr);
|
|
assert((init != nullptr) == (eltValue.isInContext()));
|
|
if (!eltValue.isInContext())
|
|
elements.push_back(eltValue);
|
|
|
|
if (eltValue.hasCleanup())
|
|
canBeGuaranteed = false;
|
|
} else {
|
|
assert(init);
|
|
expandPack(origEltType, substEltTypes, elt.getSubstIndex(),
|
|
eltInits.slice(elt.getSubstIndex(), substEltTypes.size()),
|
|
elements);
|
|
}
|
|
});
|
|
|
|
// If we emitted into a context, we're done.
|
|
if (init) {
|
|
init->finishInitialization(SGF);
|
|
return ManagedValue::forInContext();
|
|
}
|
|
|
|
if (tl.isLoadable() || !SGF.silConv.useLoweredAddresses()) {
|
|
SmallVector<SILValue, 4> elementValues;
|
|
if (canBeGuaranteed) {
|
|
// If all of the elements were guaranteed, we can form a guaranteed tuple.
|
|
for (auto element : elements)
|
|
elementValues.push_back(element.getUnmanagedValue());
|
|
} else {
|
|
// Otherwise, we need to move or copy values into a +1 tuple.
|
|
for (auto element : elements) {
|
|
SILValue value = element.hasCleanup()
|
|
? element.forward(SGF)
|
|
: element.copyUnmanaged(SGF, loc).forward(SGF);
|
|
elementValues.push_back(value);
|
|
}
|
|
}
|
|
auto tupleValue = SGF.B.createTuple(loc, tl.getLoweredType(),
|
|
elementValues);
|
|
if (tupleValue->getOwnershipKind() == OwnershipKind::None)
|
|
return ManagedValue::forObjectRValueWithoutOwnership(tupleValue);
|
|
return canBeGuaranteed ? ManagedValue::forBorrowedObjectRValue(tupleValue)
|
|
: SGF.emitManagedRValueWithCleanup(tupleValue);
|
|
} else {
|
|
// If the type is address-only, we need to move or copy the elements into
|
|
// a tuple in memory.
|
|
// TODO: It would be a bit more efficient to use a preallocated buffer
|
|
// in this case.
|
|
auto buffer = SGF.emitTemporaryAllocation(loc, tl.getLoweredType());
|
|
for (auto i : indices(elements)) {
|
|
auto element = elements[i];
|
|
auto elementBuffer = SGF.B.createTupleElementAddr(loc, buffer,
|
|
i, element.getType().getAddressType());
|
|
if (element.hasCleanup())
|
|
element.forwardInto(SGF, loc, elementBuffer);
|
|
else
|
|
element.copyInto(SGF, loc, elementBuffer);
|
|
}
|
|
return SGF.emitManagedRValueWithCleanup(buffer);
|
|
}
|
|
}
|
|
|
|
void expandPack(AbstractionPattern origExpansionType,
|
|
CanTupleEltTypeArrayRef substEltTypes,
|
|
size_t firstSubstEltIndex,
|
|
MutableArrayRef<InitializationPtr> eltInits,
|
|
SmallVectorImpl<ManagedValue> &eltMVs) {
|
|
assert(substEltTypes.size() == eltInits.size());
|
|
|
|
// The next parameter is a pack which corresponds to some number of
|
|
// components in the tuple. Some of them may be pack expansions.
|
|
// Either copy/move them into the tuple (necessary if there are any
|
|
// pack expansions) or collect them in eltMVs.
|
|
|
|
// Claim the next parameter, remember whether it was +1, and forward
|
|
// the cleanup. We can get away with just forwarding the cleanup
|
|
// up front, not destructuring it, because we assume that the work
|
|
// we're doing here won't ever unwind.
|
|
ManagedValue packAddrMV = claimNextParameter();
|
|
CleanupCloner cloner(SGF, packAddrMV);
|
|
SILValue packAddr = packAddrMV.forward(SGF);
|
|
auto packTy = packAddr->getType().castTo<SILPackType>();
|
|
|
|
auto origPatternType = origExpansionType.getPackExpansionPatternType();
|
|
|
|
auto inducedPackType =
|
|
CanPackType::get(SGF.getASTContext(), substEltTypes);
|
|
|
|
for (auto packComponentIndex : indices(substEltTypes)) {
|
|
CanType substComponentType = substEltTypes[packComponentIndex];
|
|
Initialization *componentInit =
|
|
eltInits.empty() ? nullptr : eltInits[packComponentIndex].get();
|
|
auto packComponentTy = packTy->getSILElementType(packComponentIndex);
|
|
|
|
auto substExpansionType =
|
|
dyn_cast<PackExpansionType>(substComponentType);
|
|
|
|
// In the scalar case, project out the element address from the
|
|
// pack and use the normal scalar path to trigger initialization.
|
|
if (!substExpansionType) {
|
|
auto packIndex =
|
|
SGF.B.createScalarPackIndex(loc, packComponentIndex, inducedPackType);
|
|
auto eltAddr =
|
|
SGF.B.createPackElementGet(loc, packIndex, packAddr,
|
|
packComponentTy);
|
|
auto eltAddrMV = cloner.clone(eltAddr);
|
|
auto result = handleScalar(eltAddrMV, origPatternType,
|
|
substComponentType, componentInit,
|
|
/*inout*/ false,
|
|
/*addressable*/ false);
|
|
assert(result.isInContext() == (componentInit != nullptr));
|
|
if (!result.isInContext())
|
|
eltMVs.push_back(result);
|
|
continue;
|
|
}
|
|
|
|
// In the pack-expansion case, do the exact same thing,
|
|
// but in a pack loop.
|
|
assert(componentInit);
|
|
assert(componentInit->canPerformPackExpansionInitialization());
|
|
|
|
SILType eltTy;
|
|
CanType substEltType;
|
|
auto openedEnv =
|
|
SGF.createOpenedElementValueEnvironment({packComponentTy},
|
|
{&eltTy},
|
|
{substExpansionType},
|
|
{&substEltType});
|
|
|
|
SGF.emitDynamicPackLoop(loc, inducedPackType, packComponentIndex,
|
|
openedEnv,
|
|
[]() -> SILBasicBlock * { return nullptr; },
|
|
[&](SILValue indexWithinComponent,
|
|
SILValue expansionPackIndex,
|
|
SILValue packIndex) {
|
|
componentInit->performPackExpansionInitialization(SGF, loc,
|
|
indexWithinComponent,
|
|
[&](Initialization *eltInit) {
|
|
// Project out the pack element and enter a managed value for it.
|
|
auto eltAddr =
|
|
SGF.B.createPackElementGet(loc, packIndex, packAddr, eltTy);
|
|
auto eltAddrMV = cloner.clone(eltAddr);
|
|
|
|
auto result = handleScalar(eltAddrMV, origPatternType, substEltType,
|
|
eltInit,
|
|
/*inout*/ false,
|
|
/*addressable*/ false);
|
|
assert(result.isInContext()); (void) result;
|
|
});
|
|
});
|
|
componentInit->finishInitialization(SGF);
|
|
}
|
|
}
|
|
};
|
|
|
|
/// A helper for creating SILArguments and binding variables to the argument
|
|
/// names.
|
|
class ArgumentInitHelper {
|
|
SILGenFunction &SGF;
|
|
|
|
LoweredParamGenerator loweredParams;
|
|
uint16_t ArgNo = 0;
|
|
|
|
std::optional<FunctionInputGenerator> FormalParamTypes;
|
|
|
|
SmallPtrSet<ParamDecl *, 2> ScopedDependencies;
|
|
|
|
public:
|
|
ArgumentInitHelper(SILGenFunction &SGF,
|
|
unsigned numIgnoredTrailingParameters,
|
|
llvm::SmallPtrSet<ParamDecl*, 2> &&scopedDependencies)
|
|
: SGF(SGF), loweredParams(SGF, numIgnoredTrailingParameters),
|
|
ScopedDependencies(std::move(scopedDependencies)) {}
|
|
|
|
/// Emit the given list of parameters.
|
|
unsigned emitParams(std::optional<AbstractionPattern> origFnType,
|
|
ParameterList *paramList, ParamDecl *selfParam) {
|
|
// If have an orig function type, initialize FormalParamTypes.
|
|
SmallVector<AnyFunctionType::Param, 8> substFormalParams;
|
|
if (origFnType) {
|
|
// Start by constructing an array of subst params that we can use
|
|
// for the generator. This array needs to stay in scope across
|
|
// the loop below, while we're potentially using FormalParamTypes.
|
|
|
|
auto addParamDecl = [&](ParamDecl *pd) {
|
|
if (pd->hasExternalPropertyWrapper())
|
|
pd = cast<ParamDecl>(pd->getPropertyWrapperBackingProperty());
|
|
substFormalParams.push_back(
|
|
pd->toFunctionParam(pd->getTypeInContext()).getCanonical(nullptr));
|
|
};
|
|
for (auto paramDecl : *paramList) {
|
|
addParamDecl(paramDecl);
|
|
}
|
|
if (selfParam) {
|
|
addParamDecl(selfParam);
|
|
}
|
|
|
|
// Initialize the formal parameter generator. Note that this can
|
|
// immediately claim lowered parameters.
|
|
// Some of the callers to emitBasicProlog do ask it to ignore the
|
|
// formal self parameter, but they do not pass an origFnType down,
|
|
// so we can ignore that possibility.
|
|
FormalParamTypes.emplace(SGF.getASTContext(), loweredParams, *origFnType,
|
|
llvm::ArrayRef(substFormalParams),
|
|
/*ignore final*/ false);
|
|
}
|
|
|
|
// Go through all of our implicit SIL parameters and emit them. These do not
|
|
// exist in the AST and always appear in between the results and the
|
|
// explicit parameters.
|
|
while (auto param = loweredParams.peek()) {
|
|
if (!param->hasOption(SILParameterInfo::ImplicitLeading))
|
|
break;
|
|
loweredParams.configureParamDataForImplicitParam();
|
|
loweredParams.advance();
|
|
loweredParams.resetParamData();
|
|
}
|
|
|
|
// Emit each of the function's explicit parameters in order.
|
|
if (paramList) {
|
|
for (auto *param : *paramList)
|
|
emitParam(param);
|
|
}
|
|
|
|
// The self parameter follows the formal parameters.
|
|
if (selfParam) {
|
|
emitParam(selfParam);
|
|
}
|
|
|
|
if (FormalParamTypes) FormalParamTypes->finish();
|
|
loweredParams.finish();
|
|
return ArgNo;
|
|
}
|
|
|
|
private:
|
|
ManagedValue makeArgument(SILLocation loc, ParamDecl *pd) {
|
|
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None;
|
|
bool isNoImplicitCopy = false;
|
|
if (pd->isSelfParameter()) {
|
|
if (auto *afd = dyn_cast<AbstractFunctionDecl>(pd->getDeclContext())) {
|
|
lifetimeAnnotation = afd->getLifetimeAnnotation();
|
|
isNoImplicitCopy = afd->isNoImplicitCopy();
|
|
}
|
|
} else {
|
|
lifetimeAnnotation = pd->getLifetimeAnnotation();
|
|
isNoImplicitCopy = pd->isNoImplicitCopy();
|
|
}
|
|
|
|
// Configure the lowered parameter generator for this formal parameter.
|
|
loweredParams.configureParamData(pd, isNoImplicitCopy, lifetimeAnnotation);
|
|
|
|
ManagedValue paramValue;
|
|
EmitBBArguments argEmitter(loc, loweredParams);
|
|
if (FormalParamTypes && FormalParamTypes->isOrigPackExpansion()) {
|
|
paramValue = argEmitter.handlePackComponent(*FormalParamTypes);
|
|
} else {
|
|
auto substType = pd->getTypeInContext()->getCanonicalType();
|
|
assert(!FormalParamTypes ||
|
|
FormalParamTypes->getSubstParam().getParameterType() == substType);
|
|
auto origType = (FormalParamTypes ? FormalParamTypes->getOrigType()
|
|
: AbstractionPattern(substType));
|
|
|
|
// A parameter can be directly marked as addressable, or its
|
|
// addressability can be implied by a scoped dependency or a borrow
|
|
// dependency.
|
|
bool isAddressable =
|
|
pd->isAddressable() ||
|
|
(ScopedDependencies.contains(pd) &&
|
|
SGF.getTypeProperties(origType, substType)
|
|
.isAddressableForDependencies()) ||
|
|
SGF.getFunction().getConventions().hasAddressResult() ||
|
|
SGF.getFunction().getConventions().hasGuaranteedResult();
|
|
paramValue = argEmitter.handleParam(origType, substType, pd,
|
|
isAddressable);
|
|
}
|
|
|
|
// Reset the parameter data on the lowered parameter generator.
|
|
loweredParams.resetParamData();
|
|
|
|
// Advance the formal parameter types generator. This must happen
|
|
// after resetting parameter data because it can claim lowered
|
|
// parameters.
|
|
if (FormalParamTypes) {
|
|
FormalParamTypes->advance();
|
|
}
|
|
|
|
return paramValue;
|
|
}
|
|
|
|
void updateArgumentValueForBinding(ManagedValue argrv, SILLocation loc,
|
|
ParamDecl *pd,
|
|
const SILDebugVariable &varinfo) {
|
|
bool calledCompletedUpdate = false;
|
|
SWIFT_DEFER {
|
|
assert(calledCompletedUpdate && "Forgot to call completed update along "
|
|
"all paths or manually turn it off");
|
|
};
|
|
auto completeUpdate = [&](ManagedValue value) -> void {
|
|
SGF.B.emitDebugDescription(loc, value.getValue(), varinfo);
|
|
SGF.VarLocs[pd] = SILGenFunction::VarLoc(value.getValue(),
|
|
SILAccessEnforcement::Unknown);
|
|
calledCompletedUpdate = true;
|
|
};
|
|
|
|
// If we do not need to support lexical lifetimes, just return value as the
|
|
// updated value.
|
|
if (!SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule()))
|
|
return completeUpdate(argrv);
|
|
|
|
// Look for the following annotations on the function argument:
|
|
// - @noImplicitCopy
|
|
// - @_eagerMove
|
|
// - @_noEagerMove
|
|
bool isNoImplicitCopy = pd->isNoImplicitCopy();
|
|
if (!argrv.getType().isMoveOnly(/*orWrapped=*/false)) {
|
|
isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Borrowing;
|
|
isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming;
|
|
if (pd->isSelfParameter()) {
|
|
auto *dc = pd->getDeclContext();
|
|
if (auto *fn = dyn_cast<FuncDecl>(dc)) {
|
|
auto accessKind = fn->getSelfAccessKind();
|
|
isNoImplicitCopy |= accessKind == SelfAccessKind::Borrowing;
|
|
isNoImplicitCopy |= accessKind == SelfAccessKind::Consuming;
|
|
}
|
|
}
|
|
}
|
|
// If we're relying on ManualOwnership for explicit-copies enforcement,
|
|
// we don't need @noImplicitCopy / MoveOnlyWrapper.
|
|
if (SGF.B.hasManualOwnershipAttr())
|
|
isNoImplicitCopy = false;
|
|
|
|
// If we have a no implicit copy argument and the argument is trivial,
|
|
// we need to use copyable to move only to convert it to its move only
|
|
// form.
|
|
if (!isNoImplicitCopy) {
|
|
if (!argrv.getType().isMoveOnly()) {
|
|
// Follow the normal path. The value's lifetime will be enforced based
|
|
// on its ownership.
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
// At this point, we have a noncopyable type. If it is owned, create an
|
|
// alloc_box for it.
|
|
if (argrv.getOwnershipKind() == OwnershipKind::Owned) {
|
|
// TODO: Once owned values are mutable, this needs to become mutable.
|
|
auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture(
|
|
pd,
|
|
SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
|
|
pd->getTypeInContext()),
|
|
SGF.F.getGenericEnvironment(),
|
|
/*mutable*/ false);
|
|
|
|
auto *box = SGF.B.createAllocBox(loc, boxType, varinfo);
|
|
SILValue destAddr = SGF.B.createProjectBox(loc, box, 0);
|
|
SGF.B.emitStoreValueOperation(loc, argrv.forward(SGF), destAddr,
|
|
StoreOwnershipQualifier::Init);
|
|
SGF.emitManagedRValueWithCleanup(box);
|
|
|
|
// We manually set calledCompletedUpdate to true since we want to use
|
|
// the debug info from the box rather than insert a custom debug_value.
|
|
calledCompletedUpdate = true;
|
|
SGF.VarLocs[pd] = SILGenFunction::VarLoc(destAddr,
|
|
pd->isImmutableInFunctionBody() ? SILAccessEnforcement::Unknown
|
|
: SILAccessEnforcement::Dynamic,
|
|
box);
|
|
return;
|
|
}
|
|
|
|
// If we have a guaranteed noncopyable argument, we do something a little
|
|
// different. Specifically, we emit it as normal and do a non-consume or
|
|
// assign. The reason why we do this is that a guaranteed argument cannot
|
|
// be used in an escaping closure. So today, we leave it with the
|
|
// misleading consuming message. We still are able to pass it to
|
|
// non-escaping closures though since the onstack partial_apply does not
|
|
// consume the value.
|
|
assert(argrv.getOwnershipKind() == OwnershipKind::Guaranteed);
|
|
argrv = argrv.copy(SGF, loc);
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
if (argrv.getType().isTrivial(SGF.F)) {
|
|
SILValue value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(
|
|
loc, argrv.getValue());
|
|
argrv = SGF.emitManagedRValueWithCleanup(value);
|
|
argrv = SGF.B.createMoveValue(loc, argrv, IsLexical);
|
|
|
|
// If our argument was owned, we use no implicit copy. Otherwise, we
|
|
// use no copy.
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind kind;
|
|
switch (pd->getValueOwnership()) {
|
|
case ValueOwnership::Default:
|
|
case ValueOwnership::Shared:
|
|
case ValueOwnership::InOut:
|
|
kind = MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign;
|
|
break;
|
|
|
|
case ValueOwnership::Owned:
|
|
kind = MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable;
|
|
break;
|
|
}
|
|
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(loc, argrv, kind);
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
if (argrv.getOwnershipKind() == OwnershipKind::Guaranteed) {
|
|
argrv = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(loc, argrv);
|
|
argrv = argrv.copy(SGF, loc);
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
if (argrv.getOwnershipKind() == OwnershipKind::Owned) {
|
|
// If we have an owned value, forward it into the
|
|
// mark_unresolved_non_copyable_value to avoid an extra destroy_value.
|
|
argrv = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(loc, argrv);
|
|
argrv = SGF.B.createMoveValue(loc, argrv, IsLexical);
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable);
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
return completeUpdate(argrv);
|
|
}
|
|
|
|
/// Create a SILArgument and store its value into the given Initialization,
|
|
/// if not null.
|
|
void makeArgumentIntoBinding(SILLocation loc, ParamDecl *pd) {
|
|
ManagedValue argrv = makeArgument(loc, pd);
|
|
if (pd->isInOut()) {
|
|
assert(argrv.getType().isAddress() && "expected inout to be address");
|
|
} else if (argrv.getType().is<SILPackType>()) {
|
|
assert(argrv.getType().isAddress() && "expected pack to be address");
|
|
} else if (!pd->isImmutableInFunctionBody()) {
|
|
// If it's a locally mutable parameter, then we need to move the argument
|
|
// value into a local box to hold the mutated value.
|
|
// We don't need to mark_uninitialized since we immediately initialize.
|
|
auto mutableBox =
|
|
SGF.emitLocalVariableWithCleanup(pd,
|
|
/*uninitialized kind*/ std::nullopt);
|
|
argrv.ensurePlusOne(SGF, loc).forwardInto(SGF, loc, mutableBox.get());
|
|
return;
|
|
}
|
|
|
|
// If the variable is immutable, we can bind the value as is.
|
|
// Leave the cleanup on the argument, if any, in place to consume the
|
|
// argument if we're responsible for it.
|
|
SILDebugVariable varinfo(pd->isImmutableInFunctionBody(), ArgNo);
|
|
if (!argrv.getType().isAddress()) {
|
|
// NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding.
|
|
updateArgumentValueForBinding(argrv, loc, pd, varinfo);
|
|
SGF.enterLocalVariableAddressableBufferScope(pd);
|
|
return;
|
|
}
|
|
|
|
if (auto *allocStack = dyn_cast<AllocStackInst>(argrv.getValue())) {
|
|
allocStack->setArgNo(ArgNo);
|
|
allocStack->setIsFromVarDecl();
|
|
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
|
|
SGF.getModule()) &&
|
|
SGF.F.getLifetime(pd, allocStack->getType()).isLexical()) {
|
|
allocStack->setIsLexical();
|
|
}
|
|
SGF.VarLocs[pd] = SILGenFunction::VarLoc(allocStack,
|
|
SILAccessEnforcement::Unknown);
|
|
SGF.enterLocalVariableAddressableBufferScope(pd);
|
|
return;
|
|
}
|
|
|
|
if (auto *arg = dyn_cast<SILFunctionArgument>(argrv.getValue())) {
|
|
if (arg->isNoImplicitCopy()) {
|
|
switch (pd->getSpecifier()) {
|
|
case swift::ParamSpecifier::Borrowing:
|
|
// Shouldn't have any cleanups on this.
|
|
assert(!argrv.hasCleanup());
|
|
argrv = ManagedValue::forBorrowedAddressRValue(
|
|
SGF.B.createCopyableToMoveOnlyWrapperAddr(pd, argrv.getValue()));
|
|
break;
|
|
case swift::ParamSpecifier::ImplicitlyCopyableConsuming:
|
|
case swift::ParamSpecifier::Consuming:
|
|
case swift::ParamSpecifier::Default:
|
|
case swift::ParamSpecifier::InOut:
|
|
case swift::ParamSpecifier::LegacyOwned:
|
|
case swift::ParamSpecifier::LegacyShared:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SILValue debugOperand = argrv.getValue();
|
|
|
|
if (argrv.getType().isMoveOnly()) {
|
|
switch (pd->getValueOwnership()) {
|
|
case ValueOwnership::Default:
|
|
if (pd->isSelfParameter()) {
|
|
assert(!isa<MarkUnresolvedNonCopyableValueInst>(argrv.getValue()) &&
|
|
"Should not have inserted mark must check inst in EmitBBArgs");
|
|
if (!pd->isInOut()) {
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
NoConsumeOrAssign);
|
|
}
|
|
} else {
|
|
if (auto *fArg = dyn_cast<SILFunctionArgument>(argrv.getValue())) {
|
|
switch (fArg->getArgumentConvention()) {
|
|
case SILArgumentConvention::Direct_Guaranteed:
|
|
case SILArgumentConvention::Direct_Owned:
|
|
case SILArgumentConvention::Direct_Unowned:
|
|
case SILArgumentConvention::Indirect_Inout:
|
|
case SILArgumentConvention::Indirect_Out:
|
|
case SILArgumentConvention::Indirect_InoutAliasable:
|
|
case SILArgumentConvention::Pack_Inout:
|
|
case SILArgumentConvention::Pack_Guaranteed:
|
|
case SILArgumentConvention::Pack_Owned:
|
|
case SILArgumentConvention::Pack_Out:
|
|
llvm_unreachable("Should have been handled elsewhere");
|
|
case SILArgumentConvention::Indirect_In:
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable);
|
|
break;
|
|
case SILArgumentConvention::Indirect_In_CXX:
|
|
case SILArgumentConvention::Indirect_In_Guaranteed:
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
NoConsumeOrAssign);
|
|
}
|
|
} else {
|
|
assert(isa<MarkUnresolvedNonCopyableValueInst>(argrv.getValue()) &&
|
|
"Should have inserted mark must check inst in EmitBBArgs");
|
|
}
|
|
}
|
|
break;
|
|
case ValueOwnership::InOut: {
|
|
assert(isa<MarkUnresolvedNonCopyableValueInst>(argrv.getValue()) &&
|
|
"Expected mark must check inst with inout to be handled in "
|
|
"emitBBArgs earlier");
|
|
auto mark = cast<MarkUnresolvedNonCopyableValueInst>(argrv.getValue());
|
|
debugOperand = mark->getOperand();
|
|
break;
|
|
}
|
|
case ValueOwnership::Owned:
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable);
|
|
break;
|
|
case ValueOwnership::Shared:
|
|
argrv = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
loc, argrv,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugValueInst *debugInst
|
|
= SGF.B.emitDebugDescription(loc, debugOperand, varinfo);
|
|
|
|
if (argrv.getValue() != debugOperand) {
|
|
if (auto valueInst =
|
|
dyn_cast<MarkUnresolvedNonCopyableValueInst>(argrv.getValue())) {
|
|
// Move the debug instruction outside of any marker instruction that might
|
|
// have been applied to the value, so that analysis doesn't move the
|
|
// debug_value anywhere it shouldn't be.
|
|
debugInst->moveBefore(valueInst);
|
|
}
|
|
}
|
|
|
|
SILAccessEnforcement access;
|
|
switch (pd->getValueOwnership()) {
|
|
case ValueOwnership::Shared:
|
|
case ValueOwnership::Owned:
|
|
case ValueOwnership::Default:
|
|
access = SILAccessEnforcement::Unknown;
|
|
break;
|
|
|
|
case ValueOwnership::InOut:
|
|
access = SILAccessEnforcement::Static;
|
|
break;
|
|
}
|
|
|
|
SGF.VarLocs[pd] = SILGenFunction::VarLoc(argrv.getValue(), access);
|
|
SGF.enterLocalVariableAddressableBufferScope(pd);
|
|
}
|
|
|
|
void emitParam(ParamDecl *PD) {
|
|
// Register any auxiliary declarations for the parameter to be
|
|
// visited later.
|
|
PD->visitAuxiliaryVars(/*forNameLookup*/ false, [&](VarDecl *localVar) {
|
|
SGF.LocalAuxiliaryDecls.push_back(localVar);
|
|
});
|
|
|
|
// If the parameter has an external property wrapper, then the
|
|
// wrapper is the actual parameter. Use that for everything
|
|
// except the auxiliary decls collection above.
|
|
if (PD->hasExternalPropertyWrapper()) {
|
|
PD = cast<ParamDecl>(PD->getPropertyWrapperBackingProperty());
|
|
}
|
|
|
|
SILLocation loc(PD);
|
|
loc.markAsPrologue();
|
|
|
|
assert(PD->getTypeInContext()->isMaterializable());
|
|
|
|
++ArgNo;
|
|
if (PD->hasName() || PD->isIsolated()) {
|
|
makeArgumentIntoBinding(loc, PD);
|
|
} else {
|
|
emitAnonymousParam(loc, PD);
|
|
}
|
|
}
|
|
|
|
void emitAnonymousParam(SILLocation loc, ParamDecl *PD) {
|
|
// A value bound to _ is unused and can be immediately released.
|
|
Scope discardScope(SGF.Cleanups, CleanupLocation(PD));
|
|
|
|
// Manage the parameter.
|
|
auto argrv = makeArgument(loc, PD);
|
|
|
|
// Emit debug information for the argument.
|
|
SILDebugVariable DebugVar(PD->isLet(), ArgNo);
|
|
if (argrv.getType().isAddress())
|
|
SGF.B.emitDebugDescription(loc, argrv.getValue(), DebugVar);
|
|
else
|
|
SGF.B.emitDebugDescription(loc, argrv.getValue(), DebugVar);
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
|
|
static void makeArgument(Type ty, ParamDecl *decl,
|
|
SmallVectorImpl<SILValue> &args, SILGenFunction &SGF) {
|
|
assert(ty && "no type?!");
|
|
|
|
if (ty->is<PackExpansionType>()) {
|
|
ty = PackType::get(SGF.getASTContext(), {ty});
|
|
}
|
|
|
|
// Destructure tuple value arguments.
|
|
if (!decl->isInOut()) {
|
|
if (TupleType *tupleTy = ty->getAs<TupleType>()) {
|
|
for (auto fieldType : tupleTy->getElementTypes())
|
|
makeArgument(fieldType, decl, args, SGF);
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto loweredTy = SGF.getLoweredTypeForFunctionArgument(ty);
|
|
if (decl->isInOut())
|
|
loweredTy = SILType::getPrimitiveAddressType(loweredTy.getASTType());
|
|
auto arg = SGF.F.begin()->createFunctionArgument(loweredTy, decl);
|
|
args.push_back(arg);
|
|
}
|
|
|
|
void SILGenFunction::bindParameterForForwarding(ParamDecl *param,
|
|
SmallVectorImpl<SILValue> ¶meters) {
|
|
if (param->hasExternalPropertyWrapper()) {
|
|
param = cast<ParamDecl>(param->getPropertyWrapperBackingProperty());
|
|
}
|
|
|
|
makeArgument(param->getTypeInContext(), param, parameters, *this);
|
|
}
|
|
|
|
void SILGenFunction::bindParametersForForwarding(const ParameterList *params,
|
|
SmallVectorImpl<SILValue> ¶meters) {
|
|
for (auto param : *params)
|
|
bindParameterForForwarding(param, parameters);
|
|
}
|
|
|
|
static void emitCaptureArguments(SILGenFunction &SGF,
|
|
GenericSignature origGenericSig,
|
|
CapturedValue capture,
|
|
uint16_t ArgNo) {
|
|
if (auto *expr = capture.getPackElement()) {
|
|
SILLocation Loc(expr);
|
|
Loc.markAsPrologue();
|
|
|
|
auto interfaceType = expr->getType()->mapTypeOutOfContext();
|
|
|
|
auto type = SGF.F.mapTypeIntoContext(interfaceType);
|
|
auto &lowering = SGF.getTypeLowering(type);
|
|
SILType ty = lowering.getLoweredType();
|
|
|
|
SILValue arg;
|
|
|
|
auto expansion = SGF.getTypeExpansionContext();
|
|
auto captureKind = SGF.SGM.Types.getDeclCaptureKind(capture, expansion);
|
|
switch (captureKind) {
|
|
case CaptureKind::Constant:
|
|
case CaptureKind::StorageAddress:
|
|
case CaptureKind::Immutable: {
|
|
auto argIndex = SGF.F.begin()->getNumArguments();
|
|
// Non-escaping stored decls are captured as the address of the value.
|
|
auto param = SGF.F.getConventions().getParamInfoForSILArg(argIndex);
|
|
if (SGF.F.getConventions().isSILIndirect(param))
|
|
ty = ty.getAddressType();
|
|
|
|
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, nullptr);
|
|
fArg->setClosureCapture(true);
|
|
|
|
arg = fArg;
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::ImmutableBox:
|
|
case CaptureKind::Box:
|
|
llvm_unreachable("should be impossible");
|
|
}
|
|
|
|
ManagedValue mv = ManagedValue::forBorrowedRValue(arg);
|
|
auto inserted = SGF.OpaqueValues.insert(std::make_pair(expr, mv));
|
|
assert(inserted.second);
|
|
(void) inserted;
|
|
|
|
return;
|
|
}
|
|
|
|
auto *VD = cast<VarDecl>(capture.getDecl());
|
|
|
|
SILLocation Loc(VD);
|
|
Loc.markAsPrologue();
|
|
|
|
auto interfaceType = VD->getInterfaceType()->getReducedType(
|
|
origGenericSig);
|
|
|
|
// If we're capturing a parameter pack, wrap it in a tuple.
|
|
bool isPack = false;
|
|
if (isa<PackExpansionType>(interfaceType)) {
|
|
assert(!VD->supportsMutation() &&
|
|
"Cannot capture a pack as an lvalue");
|
|
|
|
SmallVector<TupleTypeElt, 1> elts;
|
|
elts.push_back(interfaceType);
|
|
interfaceType = CanTupleType(TupleType::get(elts, SGF.getASTContext()));
|
|
isPack = true;
|
|
}
|
|
|
|
auto type = SGF.F.mapTypeIntoContext(interfaceType);
|
|
auto &lowering = SGF.getTypeLowering(type);
|
|
SILType ty = lowering.getLoweredType();
|
|
|
|
bool isNoImplicitCopy;
|
|
|
|
if (ty.isTrivial(SGF.F) || ty.isMoveOnly() ||
|
|
SGF.B.hasManualOwnershipAttr()) {
|
|
isNoImplicitCopy = false;
|
|
} else if (VD->isNoImplicitCopy()) {
|
|
isNoImplicitCopy = true;
|
|
} else if (auto pd = dyn_cast<ParamDecl>(VD)) {
|
|
switch (pd->getSpecifier()) {
|
|
case ParamSpecifier::Borrowing:
|
|
case ParamSpecifier::Consuming:
|
|
isNoImplicitCopy = true;
|
|
break;
|
|
case ParamSpecifier::ImplicitlyCopyableConsuming:
|
|
case ParamSpecifier::Default:
|
|
case ParamSpecifier::InOut:
|
|
case ParamSpecifier::LegacyOwned:
|
|
case ParamSpecifier::LegacyShared:
|
|
isNoImplicitCopy = false;
|
|
break;
|
|
}
|
|
} else {
|
|
isNoImplicitCopy = false;
|
|
}
|
|
|
|
SILValue arg;
|
|
SILFunctionArgument *box = nullptr;
|
|
|
|
auto expansion = SGF.getTypeExpansionContext();
|
|
auto captureKind = SGF.SGM.Types.getDeclCaptureKind(capture, expansion);
|
|
SILAccessEnforcement enforcement;
|
|
switch (captureKind) {
|
|
case CaptureKind::Constant: {
|
|
assert(!isPack);
|
|
|
|
// Constant decls are captured by value.
|
|
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, VD);
|
|
fArg->setClosureCapture(true);
|
|
|
|
ManagedValue val = ManagedValue::forBorrowedRValue(fArg);
|
|
|
|
// If the original variable was settable, then Sema will have treated the
|
|
// VarDecl as an lvalue, even in the closure's use. As such, we need to
|
|
// allow formation of the address for this captured value. Create a
|
|
// temporary within the closure to provide this address.
|
|
if (VD->isSettable(VD->getDeclContext())) {
|
|
auto addr = SGF.emitTemporary(VD, lowering);
|
|
// We have created a copy that needs to be destroyed.
|
|
val = SGF.B.emitCopyValueOperation(Loc, val);
|
|
// We use the SILValue version of this because the SILGenBuilder version
|
|
// will create a cloned cleanup, which we do not want since our temporary
|
|
// already has a cleanup.
|
|
//
|
|
// MG: Is this the right semantics for createStore? Seems like that
|
|
// should be potentially a different API.
|
|
SGF.B.emitStoreValueOperation(VD, val.forward(SGF), addr->getAddress(),
|
|
StoreOwnershipQualifier::Init);
|
|
addr->finishInitialization(SGF);
|
|
val = addr->getManagedAddress();
|
|
}
|
|
|
|
if (isNoImplicitCopy && !val.getType().isMoveOnly()) {
|
|
val = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(VD, val);
|
|
}
|
|
|
|
// If this constant is a move only type, we need to add no_consume_or_assign checking to
|
|
// ensure that we do not consume this captured value in the function. This
|
|
// is because closures can be invoked multiple times which is inconsistent
|
|
// with consuming the move only type.
|
|
if (val.getType().isMoveOnly()) {
|
|
val = val.ensurePlusOne(SGF, Loc);
|
|
val = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
Loc, val,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::NoConsumeOrAssign);
|
|
}
|
|
|
|
arg = val.getValue();
|
|
enforcement = SILAccessEnforcement::Unknown;
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::ImmutableBox:
|
|
case CaptureKind::Box: {
|
|
assert(!isPack);
|
|
|
|
// LValues are captured as a retained @box that owns
|
|
// the captured value.
|
|
bool isMutable = captureKind == CaptureKind::Box;
|
|
// Get the content for the box in the minimal resilience domain because we
|
|
// are declaring a type.
|
|
ty = SGF.SGM.Types.getLoweredType(type, TypeExpansionContext::minimal());
|
|
auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture(
|
|
VD, ty.getASTType(), SGF.F.getGenericEnvironment(),
|
|
/*mutable*/ isMutable);
|
|
box = SGF.F.begin()->createFunctionArgument(
|
|
SILType::getPrimitiveObjectType(boxTy), VD);
|
|
box->setClosureCapture(true);
|
|
arg = SGF.B.createProjectBox(VD, box, 0);
|
|
if (isNoImplicitCopy && !arg->getType().isMoveOnly()) {
|
|
arg = SGF.B.createCopyableToMoveOnlyWrapperAddr(VD, arg);
|
|
}
|
|
enforcement = isMutable
|
|
? SILAccessEnforcement::Dynamic
|
|
: SILAccessEnforcement::Unknown;
|
|
break;
|
|
}
|
|
case CaptureKind::StorageAddress:
|
|
assert(!isPack);
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case CaptureKind::Immutable: {
|
|
auto argIndex = SGF.F.begin()->getNumArguments();
|
|
// Non-escaping stored decls are captured as the address of the value.
|
|
auto fnConv = SGF.F.getConventions();
|
|
auto paramInfo = fnConv.getParamInfoForSILArg(argIndex);
|
|
if (fnConv.isSILIndirect(paramInfo)) {
|
|
ty = ty.getAddressType();
|
|
}
|
|
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, VD);
|
|
fArg->setClosureCapture(true);
|
|
arg = SILValue(fArg);
|
|
|
|
if (isNoImplicitCopy && !arg->getType().isMoveOnly()) {
|
|
// FIXME: this incompatible with -enable-sil-opaque-values
|
|
switch (fnConv.getSILArgumentConvention(argIndex)) {
|
|
case SILArgumentConvention::Indirect_Inout:
|
|
case SILArgumentConvention::Indirect_InoutAliasable:
|
|
case SILArgumentConvention::Indirect_In:
|
|
case SILArgumentConvention::Indirect_In_Guaranteed:
|
|
case SILArgumentConvention::Indirect_In_CXX:
|
|
case SILArgumentConvention::Pack_Inout:
|
|
case SILArgumentConvention::Pack_Owned:
|
|
case SILArgumentConvention::Pack_Guaranteed:
|
|
arg = SGF.B.createCopyableToMoveOnlyWrapperAddr(VD, arg);
|
|
break;
|
|
|
|
case SILArgumentConvention::Direct_Owned:
|
|
arg = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(VD, arg);
|
|
break;
|
|
|
|
case SILArgumentConvention::Direct_Guaranteed:
|
|
arg = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(VD, arg);
|
|
break;
|
|
|
|
case SILArgumentConvention::Direct_Unowned:
|
|
case SILArgumentConvention::Indirect_Out:
|
|
case SILArgumentConvention::Pack_Out:
|
|
llvm_unreachable("should be impossible");
|
|
}
|
|
}
|
|
|
|
// If we have an inout noncopyable parameter, insert a consumable and
|
|
// assignable.
|
|
//
|
|
// NOTE: If we have an escaping closure, we are going to emit an error later
|
|
// in SIL since it is illegal to capture an inout value in an escaping
|
|
// closure. The later code knows how to handle that we have the
|
|
// mark_unresolved_non_copyable_value here.
|
|
bool isInOut = paramInfo.isIndirectMutating();
|
|
if (isInOut && arg->getType().isMoveOnly()) {
|
|
arg = SGF.B.createMarkUnresolvedNonCopyableValueInst(
|
|
Loc, arg,
|
|
MarkUnresolvedNonCopyableValueInst::CheckKind::
|
|
ConsumableAndAssignable);
|
|
}
|
|
enforcement = isInOut
|
|
? SILAccessEnforcement::Static
|
|
: SILAccessEnforcement::Unknown;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we captured a pack as a tuple, create a pack from the elements
|
|
// of the tuple.
|
|
if (isPack) {
|
|
auto tupleType = ty.castTo<TupleType>();
|
|
assert(tupleType->getNumElements() == 1);
|
|
|
|
auto packType =
|
|
SILPackType::get(SGF.getASTContext(),
|
|
SILPackType::ExtInfo(/*indirect=*/true),
|
|
{tupleType.getElementType(0)});
|
|
auto packValue = SGF.emitTemporaryPackAllocation(
|
|
Loc, SILType::getPrimitiveObjectType(packType));
|
|
|
|
auto formalPackType = cast<TupleType>(type->getCanonicalType())
|
|
.getInducedPackType();
|
|
SGF.projectTupleElementsToPack(Loc, arg, packValue, formalPackType);
|
|
|
|
arg = packValue;
|
|
}
|
|
|
|
SGF.VarLocs[VD] = SILGenFunction::VarLoc(arg, enforcement, box);
|
|
SGF.enterLocalVariableAddressableBufferScope(VD);
|
|
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
|
|
if (auto *AllocStack = dyn_cast<AllocStackInst>(arg)) {
|
|
AllocStack->setArgNo(ArgNo);
|
|
} else if (box || ty.isAddress()) {
|
|
SGF.B.emitDebugDescription(Loc, arg, DbgVar);
|
|
} else {
|
|
SGF.B.emitDebugDescription(Loc, arg, DbgVar);
|
|
}
|
|
}
|
|
|
|
void SILGenFunction::emitProlog(
|
|
DeclContext *DC, CaptureInfo captureInfo, ParameterList *paramList,
|
|
ParamDecl *selfParam, Type resultType, std::optional<Type> errorType,
|
|
SourceLoc throwsLoc) {
|
|
// Emit the capture argument variables. These are placed last because they
|
|
// become the first curry level of the SIL function.
|
|
bool hasErasedIsolation =
|
|
(TypeContext && TypeContext->ExpectedLoweredType->hasErasedIsolation());
|
|
|
|
uint16_t ArgNo = emitBasicProlog(DC, paramList, selfParam, resultType,
|
|
errorType, throwsLoc,
|
|
/*ignored parameters*/
|
|
(hasErasedIsolation ? 1 : 0) +
|
|
captureInfo.getCaptures().size());
|
|
|
|
// If we're emitting into a type context that expects erased isolation,
|
|
// add (and ignore) the isolation parameter.
|
|
if (hasErasedIsolation) {
|
|
SILType ty = SILType::getOpaqueIsolationType(getASTContext());
|
|
SILValue val = F.begin()->createFunctionArgument(ty);
|
|
(void) val;
|
|
}
|
|
|
|
for (auto capture : captureInfo.getCaptures()) {
|
|
if (capture.isDynamicSelfMetadata()) {
|
|
auto selfMetatype = MetatypeType::get(
|
|
captureInfo.getDynamicSelfType());
|
|
SILType ty = getLoweredType(selfMetatype);
|
|
SILValue val = F.begin()->createFunctionArgument(ty);
|
|
(void) val;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (capture.isOpaqueValue()) {
|
|
OpaqueValueExpr *opaqueValue = capture.getOpaqueValue();
|
|
Type type = opaqueValue->getType()->mapTypeOutOfContext();
|
|
type = F.mapTypeIntoContext(type);
|
|
auto &lowering = getTypeLowering(type);
|
|
SILType ty = lowering.getLoweredType();
|
|
SILValue val = F.begin()->createFunctionArgument(ty);
|
|
|
|
// Opaque values are always passed 'owned', so add a clean up if needed.
|
|
//
|
|
// TODO: Should this be tied to the mv?
|
|
if (!lowering.isTrivial())
|
|
enterDestroyCleanup(val);
|
|
|
|
ManagedValue mv;
|
|
if (lowering.isTrivial())
|
|
mv = ManagedValue::forObjectRValueWithoutOwnership(val);
|
|
else
|
|
mv = ManagedValue::forUnmanagedOwnedValue(val);
|
|
|
|
OpaqueValues[opaqueValue] = mv;
|
|
|
|
continue;
|
|
}
|
|
|
|
emitCaptureArguments(*this, DC->getGenericSignatureOfContext(),
|
|
capture, ++ArgNo);
|
|
}
|
|
|
|
emitExpectedExecutorProlog();
|
|
|
|
// IMPORTANT: This block should be the last one in `emitProlog`,
|
|
// since it terminates BB and no instructions should be insterted after it.
|
|
// Emit an unreachable instruction if a parameter type is
|
|
// uninhabited
|
|
if (paramList) {
|
|
for (auto *param : *paramList) {
|
|
if (param->getTypeInContext()->isStructurallyUninhabited()) {
|
|
SILLocation unreachableLoc(param);
|
|
unreachableLoc.markAsPrologue();
|
|
B.createUnreachable(unreachableLoc);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void emitIndirectPackParameter(SILGenFunction &SGF,
|
|
PackType *resultType,
|
|
CanTupleEltTypeArrayRef
|
|
resultTypesInContext,
|
|
AbstractionPattern origExpansionType,
|
|
DeclContext *DC) {
|
|
auto &ctx = SGF.getASTContext();
|
|
|
|
bool indirect =
|
|
origExpansionType.arePackElementsPassedIndirectly(SGF.SGM.Types);
|
|
SmallVector<CanType, 4> packElts;
|
|
for (auto substEltType : resultTypesInContext) {
|
|
auto origComponentType
|
|
= origExpansionType.getPackExpansionComponentType(substEltType);
|
|
CanType loweredEltTy =
|
|
SGF.getLoweredRValueType(origComponentType, substEltType);
|
|
packElts.push_back(loweredEltTy);
|
|
}
|
|
|
|
SILPackType::ExtInfo extInfo(indirect);
|
|
auto packType = SILPackType::get(ctx, extInfo, packElts);
|
|
auto resultSILType = SILType::getPrimitiveAddressType(packType);
|
|
|
|
auto var = new (ctx) ParamDecl(SourceLoc(), SourceLoc(),
|
|
ctx.getIdentifier("$return_value"), SourceLoc(),
|
|
ctx.getIdentifier("$return_value"),
|
|
DC);
|
|
var->setSpecifier(ParamSpecifier::InOut);
|
|
var->setInterfaceType(resultType);
|
|
auto *arg = SGF.F.begin()->createFunctionArgument(resultSILType, var);
|
|
(void)arg;
|
|
}
|
|
|
|
static void emitIndirectResultParameters(SILGenFunction &SGF,
|
|
Type resultType,
|
|
AbstractionPattern origResultType,
|
|
DeclContext *DC) {
|
|
// Borrow and mutate accessors do not return indirectly.
|
|
if (auto *accessor = dyn_cast<AccessorDecl>(DC)) {
|
|
if (accessor->isBorrowAccessor() || accessor->isMutateAccessor()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
CanType resultTypeInContext =
|
|
DC->mapTypeIntoContext(resultType)->getCanonicalType();
|
|
|
|
// Tuples in the original result type are expanded.
|
|
if (origResultType.isTuple()) {
|
|
origResultType.forEachTupleElement(resultTypeInContext,
|
|
[&](TupleElementGenerator &elt) {
|
|
auto origEltType = elt.getOrigType();
|
|
auto substEltTypes = elt.getSubstTypes(resultType);
|
|
|
|
// If the original element isn't a pack expansion, pull out the
|
|
// corresponding substituted tuple element and recurse.
|
|
if (!elt.isOrigPackExpansion()) {
|
|
emitIndirectResultParameters(SGF, substEltTypes[0], origEltType, DC);
|
|
return;
|
|
}
|
|
|
|
// Otherwise, bind a pack parameter.
|
|
PackType *resultPackType = [&] {
|
|
SmallVector<Type, 4> packElts(substEltTypes.begin(),
|
|
substEltTypes.end());
|
|
return PackType::get(SGF.getASTContext(), packElts);
|
|
}();
|
|
emitIndirectPackParameter(SGF, resultPackType, elt.getSubstTypes(),
|
|
origEltType, DC);
|
|
});
|
|
return;
|
|
}
|
|
|
|
assert(!resultType->is<PackExpansionType>());
|
|
|
|
// Skip yields, they are emitted elsewhere
|
|
if (resultType->is<YieldResultType>())
|
|
return;
|
|
|
|
// If the return type is address-only, emit the indirect return argument.
|
|
|
|
// The calling convention always uses minimal resilience expansion.
|
|
auto resultConvType = SGF.SGM.Types.getLoweredType(
|
|
resultTypeInContext, TypeExpansionContext::minimal());
|
|
|
|
// And the abstraction pattern may force an indirect return even if the
|
|
// concrete type wouldn't normally be returned indirectly.
|
|
if (!SILModuleConventions::isReturnedIndirectlyInSIL(resultConvType,
|
|
SGF.SGM.M)) {
|
|
if (!SILModuleConventions(SGF.SGM.M).useLoweredAddresses()
|
|
|| origResultType.getResultConvention(SGF.SGM.Types) != AbstractionPattern::Indirect)
|
|
return;
|
|
}
|
|
|
|
auto &ctx = SGF.getASTContext();
|
|
auto var = new (ctx) ParamDecl(SourceLoc(), SourceLoc(),
|
|
ctx.getIdentifier("$return_value"), SourceLoc(),
|
|
ctx.getIdentifier("$return_value"),
|
|
DC);
|
|
var->setSpecifier(ParamSpecifier::InOut);
|
|
var->setInterfaceType(resultType);
|
|
auto &resultTI =
|
|
SGF.SGM.Types.getTypeLowering(origResultType, resultTypeInContext,
|
|
SGF.getTypeExpansionContext());
|
|
SILType resultSILType = resultTI.getLoweredType().getAddressType();
|
|
auto *arg = SGF.F.begin()->createFunctionArgument(resultSILType, var);
|
|
(void)arg;
|
|
}
|
|
|
|
static void emitIndirectErrorParameter(SILGenFunction &SGF,
|
|
Type errorType,
|
|
AbstractionPattern origErrorType,
|
|
DeclContext *DC) {
|
|
CanType errorTypeInContext =
|
|
DC->mapTypeIntoContext(errorType)->getCanonicalType();
|
|
|
|
// If the error type is address-only, emit the indirect error argument.
|
|
|
|
// The calling convention always uses minimal resilience expansion.
|
|
auto errorConvType = SGF.SGM.Types.getLoweredType(
|
|
origErrorType, errorTypeInContext, TypeExpansionContext::minimal());
|
|
|
|
// And the abstraction pattern may force an indirect return even if the
|
|
// concrete type wouldn't normally be returned indirectly.
|
|
if (!SILModuleConventions::isThrownIndirectlyInSIL(errorConvType,
|
|
SGF.SGM.M)) {
|
|
if (!SILModuleConventions(SGF.SGM.M).useLoweredAddresses()
|
|
|| origErrorType.getErrorConvention(SGF.SGM.Types)
|
|
!= AbstractionPattern::Indirect)
|
|
return;
|
|
}
|
|
|
|
auto &ctx = SGF.getASTContext();
|
|
auto var = new (ctx) ParamDecl(SourceLoc(), SourceLoc(),
|
|
ctx.getIdentifier("$error"), SourceLoc(),
|
|
ctx.getIdentifier("$error"),
|
|
DC);
|
|
var->setSpecifier(ParamSpecifier::InOut);
|
|
var->setInterfaceType(errorType);
|
|
|
|
auto &errorTI =
|
|
SGF.SGM.Types.getTypeLowering(origErrorType, errorTypeInContext,
|
|
SGF.getTypeExpansionContext());
|
|
SILType errorSILType = errorTI.getLoweredType().getAddressType();
|
|
assert(SGF.IndirectErrorResult == nullptr);
|
|
SGF.IndirectErrorResult = SGF.F.begin()->createFunctionArgument(errorSILType, var);
|
|
}
|
|
|
|
uint16_t SILGenFunction::emitBasicProlog(
|
|
DeclContext *DC, ParameterList *paramList, ParamDecl *selfParam,
|
|
Type resultType, std::optional<Type> errorType, SourceLoc throwsLoc,
|
|
unsigned numIgnoredTrailingParameters) {
|
|
// Create the indirect result parameters.
|
|
auto genericSig = DC->getGenericSignatureOfContext();
|
|
resultType = resultType->getReducedType(genericSig);
|
|
if (errorType)
|
|
errorType = (*errorType)->getReducedType(genericSig);
|
|
|
|
std::optional<AbstractionPattern> origClosureType;
|
|
if (TypeContext) origClosureType = TypeContext->OrigType;
|
|
|
|
AbstractionPattern origResultType = origClosureType
|
|
? origClosureType->getFunctionResultType()
|
|
: AbstractionPattern(genericSig.getCanonicalSignature(),
|
|
resultType->getCanonicalType());
|
|
|
|
emitIndirectResultParameters(*this, resultType, origResultType, DC);
|
|
|
|
std::optional<AbstractionPattern> origErrorType;
|
|
if (origClosureType && !origClosureType->isTypeParameterOrOpaqueArchetype() &&
|
|
!origClosureType->isClangType()) {
|
|
origErrorType = origClosureType->getFunctionThrownErrorType();
|
|
if (origErrorType && !errorType)
|
|
errorType = origErrorType->getEffectiveThrownErrorType();
|
|
} else if (errorType) {
|
|
origErrorType = AbstractionPattern(genericSig.getCanonicalSignature(),
|
|
(*errorType)->getCanonicalType());
|
|
}
|
|
|
|
if (origErrorType && errorType &&
|
|
F.getConventions().hasIndirectSILErrorResults()) {
|
|
emitIndirectErrorParameter(*this, *errorType, *origErrorType, DC);
|
|
}
|
|
|
|
// Parameters with scoped dependencies may lower differently. Parameters are
|
|
// relative to the current SILGenFunction, not the passed in DeclContext. For
|
|
// example, the an argument initializer's DeclContext is the enclosing
|
|
// function definition rather that the initializer's generator function.
|
|
llvm::SmallPtrSet<ParamDecl *, 2> scopedDependencyParams;
|
|
if (auto afd = dyn_cast<AbstractFunctionDecl>(FunctionDC)) {
|
|
if (auto deps = afd->getLifetimeDependencies()) {
|
|
for (auto &dep : *deps) {
|
|
auto scoped = dep.getScopeIndices();
|
|
if (!scoped) {
|
|
continue;
|
|
}
|
|
for (unsigned i = 0, e = paramList->size(); i < e; ++i) {
|
|
if (scoped->contains(i)) {
|
|
scopedDependencyParams.insert((*paramList)[i]);
|
|
}
|
|
}
|
|
if (scoped->contains(paramList->size())) {
|
|
scopedDependencyParams.insert(selfParam);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Emit the argument variables in calling convention order.
|
|
unsigned ArgNo =
|
|
ArgumentInitHelper(*this, numIgnoredTrailingParameters,
|
|
std::move(scopedDependencyParams))
|
|
.emitParams(origClosureType, paramList, selfParam);
|
|
|
|
// Record the ArgNo of the artificial $error inout argument.
|
|
if (errorType && IndirectErrorResult == nullptr) {
|
|
CanType errorTypeInContext =
|
|
DC->mapTypeIntoContext(*errorType)->getCanonicalType();
|
|
auto loweredErrorTy = getLoweredType(*origErrorType, errorTypeInContext);
|
|
ManagedValue undef = emitUndef(loweredErrorTy);
|
|
SILDebugVariable dbgVar("$error", /*Constant*/ false, ++ArgNo);
|
|
RegularLocation loc = RegularLocation::getAutoGeneratedLocation();
|
|
if (throwsLoc.isValid())
|
|
loc = throwsLoc;
|
|
B.emitDebugDescription(loc, undef.getValue(), dbgVar);
|
|
}
|
|
|
|
for (auto &bb : B.getFunction())
|
|
for (auto &i : bb) {
|
|
auto *alloc = dyn_cast<AllocStackInst>(&i);
|
|
if (!alloc)
|
|
continue;
|
|
auto varInfo = alloc->getVarInfo();
|
|
if (!varInfo || varInfo->ArgNo)
|
|
continue;
|
|
// The allocation has a varinfo but no argument number, which should not
|
|
// happen in the prolog. Unfortunately, some copies can generate wrong
|
|
// debug info, so we have to fix it here, by invalidating it.
|
|
alloc->invalidateVarInfo();
|
|
}
|
|
|
|
return ArgNo;
|
|
}
|