blob: 57d787f613f60ba1061d7a493b064358c6ad6d0b [file] [log] [blame]
//===--- 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 "SILGenFunction.h"
#include "Initialization.h"
#include "ManagedValue.h"
#include "Scope.h"
#include "swift/SIL/SILArgument.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ParameterList.h"
using namespace swift;
using namespace Lowering;
SILValue SILGenFunction::emitSelfDecl(VarDecl *selfDecl) {
// Emit the implicit 'self' argument.
SILType selfType = getLoweredLoadableType(selfDecl->getType());
SILValue selfValue = F.begin()->createFunctionArgument(selfType, selfDecl);
VarLocs[selfDecl] = VarLoc::get(selfValue);
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
unsigned ArgNo = 1; // Hardcoded for destructors.
B.createDebugValue(PrologueLoc, selfValue, {selfDecl->isLet(), ArgNo});
return selfValue;
}
namespace {
/// Cleanup that writes back to an inout argument on function exit.
class CleanupWriteBackToInOut : public Cleanup {
VarDecl *var;
SILValue inoutAddr;
public:
CleanupWriteBackToInOut(VarDecl *var, SILValue inoutAddr)
: var(var), inoutAddr(inoutAddr) {}
void emit(SILGenFunction &SGF, CleanupLocation l) override {
// Assign from the local variable to the inout address with an
// 'autogenerated' copyaddr.
l.markAutoGenerated();
SGF.B.createCopyAddr(l, SGF.VarLocs[var].value, inoutAddr,
IsNotTake, IsNotInitialization);
}
};
} // end anonymous namespace
namespace {
class StrongReleaseCleanup : public Cleanup {
SILValue box;
public:
StrongReleaseCleanup(SILValue box) : box(box) {}
void emit(SILGenFunction &SGF, CleanupLocation l) override {
SGF.B.emitDestroyValueOperation(l, box);
}
void dump(SILGenFunction &) const override {
#ifndef NDEBUG
llvm::errs() << "DeallocateValueBuffer\n"
<< "State: " << getState() << "box: " << box << "\n";
#endif
}
};
} // end anonymous namespace
namespace {
class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
/*RetTy*/ ManagedValue>
{
public:
SILGenFunction &SGF;
SILBasicBlock *parent;
SILLocation loc;
bool functionArgs;
ArrayRef<SILParameterInfo> &parameters;
EmitBBArguments(SILGenFunction &sgf, SILBasicBlock *parent,
SILLocation l, bool functionArgs,
ArrayRef<SILParameterInfo> &parameters)
: SGF(sgf), parent(parent), loc(l), functionArgs(functionArgs),
parameters(parameters) {}
ManagedValue getManagedValue(SILValue arg, CanType t,
SILParameterInfo parameterInfo) const {
switch (parameterInfo.getConvention()) {
case ParameterConvention::Direct_Guaranteed:
case ParameterConvention::Indirect_In_Guaranteed:
// If we have a guaranteed parameter, it is passed in at +0, and its
// lifetime is guaranteed. We can potentially use the argument as-is
// if the parameter is bound as a 'let' without cleaning up.
return ManagedValue::forUnmanaged(arg);
case ParameterConvention::Direct_Unowned:
// An unowned parameter is passed at +0, like guaranteed, but it isn't
// kept alive by the caller, so we need to retain and manage it
// regardless.
return SGF.emitManagedRetain(loc, arg);
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
// An inout parameter is +0 and guaranteed, but represents an lvalue.
return ManagedValue::forLValue(arg);
case ParameterConvention::Direct_Owned:
case ParameterConvention::Indirect_In:
// An owned or 'in' parameter is passed in at +1. We can claim ownership
// of the parameter and clean it up when it goes out of scope.
return SGF.emitManagedRValueWithCleanup(arg);
case ParameterConvention::Indirect_In_Constant:
break;
}
llvm_unreachable("bad parameter convention");
}
ManagedValue visitType(CanType t) {
auto argType = SGF.getLoweredType(t);
// Pop the next parameter info.
auto parameterInfo = parameters.front();
parameters = parameters.slice(1);
assert(
argType
== parent->getParent()->mapTypeIntoContext(
SGF.getSILType(parameterInfo))
&& "argument does not have same type as specified by parameter info");
SILValue arg =
parent->createFunctionArgument(argType, loc.getAsASTNode<ValueDecl>());
ManagedValue mv = getManagedValue(arg, t, parameterInfo);
// 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.getAnyOptionalObjectType())
objectType = theObjTy;
if (functionArgs
&& isa<FunctionType>(objectType)
&& cast<FunctionType>(objectType)->getRepresentation()
== FunctionType::Representation::Block) {
SILValue blockCopy = SGF.B.createCopyBlock(loc, mv.getValue());
mv = SGF.emitManagedRValueWithCleanup(blockCopy);
}
return mv;
}
ManagedValue visitTupleType(CanTupleType t) {
SmallVector<ManagedValue, 4> elements;
auto &tl = SGF.getTypeLowering(t);
bool canBeGuaranteed = tl.isLoadable();
// Collect the exploded elements.
for (auto fieldType : t.getElementTypes()) {
auto elt = visit(fieldType);
// If we can't borrow one of the elements as a guaranteed parameter, then
// we have to +1 the tuple.
if (elt.hasCleanup())
canBeGuaranteed = false;
elements.push_back(elt);
}
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);
return canBeGuaranteed
? ManagedValue::forUnmanaged(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, elementBuffer, loc);
}
return SGF.emitManagedRValueWithCleanup(buffer);
}
}
};
} // end anonymous namespace
namespace {
/// A helper for creating SILArguments and binding variables to the argument
/// names.
struct ArgumentInitHelper {
SILGenFunction &SGF;
SILFunction &f;
SILGenBuilder &initB;
/// An ArrayRef that we use in our SILParameterList queue. Parameters are
/// sliced off of the front as they're emitted.
ArrayRef<SILParameterInfo> parameters;
unsigned ArgNo = 0;
ArgumentInitHelper(SILGenFunction &SGF, SILFunction &f)
: SGF(SGF), f(f), initB(SGF.B),
parameters(f.getLoweredFunctionType()->getParameters()) {
}
unsigned getNumArgs() const { return ArgNo; }
ManagedValue makeArgument(Type ty, SILBasicBlock *parent, SILLocation l) {
assert(ty && "no type?!");
// Create an RValue by emitting destructured arguments into a basic block.
CanType canTy = ty->eraseDynamicSelfType()->getCanonicalType();
return EmitBBArguments(SGF, parent, l, /*functionArgs*/ true,
parameters).visit(canTy);
}
/// Create a SILArgument and store its value into the given Initialization,
/// if not null.
void makeArgumentIntoBinding(Type ty, SILBasicBlock *parent, VarDecl *vd) {
SILLocation loc(vd);
loc.markAsPrologue();
ManagedValue argrv = makeArgument(ty, parent, loc);
// Create a shadow copy of inout parameters so they can be captured
// by closures. The InOutDeshadowing guaranteed optimization will
// eliminate the variable if it is not needed.
if (vd->isInOut()) {
SILValue address = argrv.getUnmanagedValue();
CanType objectType = vd->getType()->getInOutObjectType()->getCanonicalType();
// As a special case, don't introduce a local variable for
// Builtin.UnsafeValueBuffer, which is not copyable.
if (isa<BuiltinUnsafeValueBufferType>(objectType)) {
// FIXME: mark a debug location?
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(address);
SGF.B.createDebugValueAddr(loc, address, {vd->isLet(), ArgNo});
return;
}
assert(argrv.getType().isAddress() && "expected inout to be address");
} else if (auto *metatypeTy = ty->getAs<MetatypeType>()) {
// 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 (metatypeTy->getInstanceType()->is<DynamicSelfType>()) {
auto loweredTy = SGF.getLoweredType(ty);
if (loweredTy != argrv.getType()) {
argrv = ManagedValue::forUnmanaged(
SGF.B.createUncheckedBitCast(loc, argrv.getValue(), loweredTy));
}
}
} else {
assert((vd->isLet() || vd->isShared())
&& "expected parameter to be immutable!");
// 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.
}
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(argrv.getValue());
if (argrv.getType().isAddress())
SGF.B.createDebugValueAddr(loc, argrv.getValue(), {vd->isLet(), ArgNo});
else
SGF.B.createDebugValue(loc, argrv.getValue(), {vd->isLet(), ArgNo});
}
void emitParam(ParamDecl *PD) {
auto type = PD->getType();
++ArgNo;
if (PD->hasName()) {
makeArgumentIntoBinding(type, &*f.begin(), PD);
return;
}
emitAnonymousParam(type, PD, PD);
}
void emitAnonymousParam(Type type, SILLocation paramLoc, ParamDecl *PD) {
// Allow non-materializable tuples to be bound to anonymous parameters.
if (!type->isMaterializable()) {
if (auto tupleType = type->getAs<TupleType>()) {
for (auto eltType : tupleType->getElementTypes()) {
emitAnonymousParam(eltType, paramLoc, nullptr);
}
return;
}
}
// A value bound to _ is unused and can be immediately released.
Scope discardScope(SGF.Cleanups, CleanupLocation(PD));
// Manage the parameter.
ManagedValue argrv = makeArgument(type, &*f.begin(), paramLoc);
// Don't do anything else if we don't have a parameter.
if (!PD) return;
// Emit debug information for the argument.
SILLocation loc(PD);
loc.markAsPrologue();
if (argrv.getType().isAddress())
SGF.B.createDebugValueAddr(loc, argrv.getValue(), {PD->isLet(), ArgNo});
else
SGF.B.createDebugValue(loc, argrv.getValue(), {PD->isLet(), ArgNo});
}
};
} // end anonymous namespace
static void makeArgument(Type ty, ParamDecl *decl,
SmallVectorImpl<SILValue> &args, SILGenFunction &SGF) {
assert(ty && "no type?!");
// Destructure tuple arguments.
if (TupleType *tupleTy = ty->getAs<TupleType>()) {
for (auto fieldType : tupleTy->getElementTypes())
makeArgument(fieldType, decl, args, SGF);
} else {
auto arg =
SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(ty), decl);
args.push_back(arg);
}
}
void SILGenFunction::bindParametersForForwarding(const ParameterList *params,
SmallVectorImpl<SILValue> &parameters) {
for (auto param : *params) {
Type type = (param->hasType()
? param->getType()
: F.mapTypeIntoContext(param->getInterfaceType()));
makeArgument(type->eraseDynamicSelfType(), param, parameters, *this);
}
}
static void emitCaptureArguments(SILGenFunction &SGF,
AnyFunctionRef closure,
CapturedValue capture,
unsigned ArgNo) {
auto *VD = capture.getDecl();
SILLocation Loc(VD);
Loc.markAsPrologue();
// Local function to get the captured variable type within the capturing
// context.
auto getVarTypeInCaptureContext = [&]() -> Type {
auto interfaceType = VD->getInterfaceType();
return GenericEnvironment::mapTypeIntoContext(
closure.getGenericEnvironment(), interfaceType);
};
switch (SGF.SGM.Types.getDeclCaptureKind(capture)) {
case CaptureKind::None:
break;
case CaptureKind::Constant: {
auto type = getVarTypeInCaptureContext();
auto &lowering = SGF.getTypeLowering(type);
// Constant decls are captured by value.
SILType ty = lowering.getLoweredType();
SILValue val = SGF.F.begin()->createFunctionArgument(ty, VD);
bool NeedToDestroyValueAtExit = false;
// 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.emitTemporaryAllocation(VD, ty);
// We have created a copy that needs to be destroyed.
val = SGF.B.createCopyValue(Loc, val);
NeedToDestroyValueAtExit = true;
lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init);
val = addr;
}
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val);
if (auto *AllocStack = dyn_cast<AllocStackInst>(val))
AllocStack->setArgNo(ArgNo);
else
SGF.B.createDebugValue(Loc, val, {/*Constant*/true, ArgNo});
// TODO: Closure contexts should always be guaranteed.
if (NeedToDestroyValueAtExit && !lowering.isTrivial())
SGF.enterDestroyCleanup(val);
break;
}
case CaptureKind::Box: {
// LValues are captured as a retained @box that owns
// the captured value.
auto type = getVarTypeInCaptureContext();
auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture(VD,
SGF.getLoweredType(type).getSwiftRValueType(),
SGF.F.getGenericEnvironment(), /*mutable*/ true);
SILValue box = SGF.F.begin()->createFunctionArgument(
SILType::getPrimitiveObjectType(boxTy), VD);
SILValue addr = SGF.B.createProjectBox(VD, box, 0);
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box);
SGF.B.createDebugValueAddr(Loc, addr, {/*Constant*/false, ArgNo});
break;
}
case CaptureKind::StorageAddress: {
// Non-escaping stored decls are captured as the address of the value.
auto type = getVarTypeInCaptureContext();
SILType ty = SGF.getLoweredType(type).getAddressType();
SILValue addr = SGF.F.begin()->createFunctionArgument(ty, VD);
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr);
SGF.B.createDebugValueAddr(Loc, addr, {/*Constant*/true, ArgNo});
break;
}
}
}
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure,
ArrayRef<ParameterList*> paramPatterns,
Type resultType, bool throws) {
unsigned ArgNo = emitProlog(paramPatterns, resultType,
TheClosure.getAsDeclContext(), throws);
// Emit the capture argument variables. These are placed last because they
// become the first curry level of the SIL function.
auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure);
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;
return;
}
emitCaptureArguments(*this, TheClosure, capture, ++ArgNo);
}
}
static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType,
DeclContext *DC) {
// Expand tuples.
if (auto tupleType = resultType->getAs<TupleType>()) {
for (auto eltType : tupleType->getElementTypes()) {
emitIndirectResultParameters(SGF, eltType, DC);
}
return;
}
// If the return type is address-only, emit the indirect return argument.
const TypeLowering &resultTI =
SGF.getTypeLowering(DC->mapTypeIntoContext(resultType));
if (!SILModuleConventions::isReturnedIndirectlyInSIL(
resultTI.getLoweredType(), SGF.SGM.M)) {
return;
}
auto &ctx = SGF.getASTContext();
auto var = new (ctx) ParamDecl(VarDecl::Specifier::InOut,
SourceLoc(), SourceLoc(),
ctx.getIdentifier("$return_value"), SourceLoc(),
ctx.getIdentifier("$return_value"), Type(),
DC);
var->setInterfaceType(resultType);
auto *arg =
SGF.F.begin()->createFunctionArgument(resultTI.getLoweredType(), var);
(void)arg;
}
unsigned SILGenFunction::emitProlog(ArrayRef<ParameterList *> paramLists,
Type resultType, DeclContext *DC,
bool throws) {
// Create the indirect result parameters.
auto *genericSig = DC->getGenericSignatureOfContext();
resultType = resultType->getCanonicalType(genericSig);
emitIndirectResultParameters(*this, resultType, DC);
// Emit the argument variables in calling convention order.
ArgumentInitHelper emitter(*this, F);
for (ParameterList *paramList : reversed(paramLists)) {
// Add the SILArguments and use them to initialize the local argument
// values.
for (auto &param : *paramList)
emitter.emitParam(param);
}
// Record the ArgNo of the artificial $error inout argument.
unsigned ArgNo = emitter.getNumArgs();
if (throws) {
RegularLocation Loc = getCompilerGeneratedLocation();
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC))
Loc = AFD->getThrowsLoc();
else if (auto *ACE = dyn_cast<AbstractClosureExpr>(DC))
Loc = ACE->getLoc();
auto NativeErrorTy = SILType::getExceptionType(getASTContext());
ManagedValue Undef = emitUndef(Loc, NativeErrorTy);
B.createDebugValue(Loc, Undef.getValue(),
{"$error", /*Constant*/ false, ++ArgNo});
}
return ArgNo;
}