//===--- 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(); uint16_t ArgNo = 1; // Hardcoded for destructors. B.createDebugValue(PrologueLoc, selfValue, SILDebugVariable(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 { public: SILGenFunction &SGF; SILBasicBlock *parent; SILLocation loc; bool functionArgs; ArrayRef ¶meters; EmitBBArguments(SILGenFunction &sgf, SILBasicBlock *parent, SILLocation l, bool functionArgs, ArrayRef ¶meters) : SGF(sgf), parent(parent), loc(l), functionArgs(functionArgs), parameters(parameters) {} 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"); ManagedValue mv = SGF.B.createInputFunctionArgument( argType, loc.getAsASTNode()); // 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 (functionArgs && isa(objectType) && cast(objectType)->getRepresentation() == FunctionType::Representation::Block) { SILValue blockCopy = SGF.B.createCopyBlock(loc, mv.getValue()); mv = SGF.emitManagedRValueWithCleanup(blockCopy); } return mv; } ManagedValue visitTupleType(CanTupleType t) { SmallVector 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 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 parameters; uint16_t 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(objectType)) { // FIXME: mark a debug location? SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(address); SGF.B.createDebugValueAddr(loc, address, SILDebugVariable(vd->isLet(), ArgNo)); return; } assert(argrv.getType().isAddress() && "expected inout to be address"); } else if (auto *metatypeTy = ty->getAs()) { // 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()) { auto loweredTy = SGF.getLoweredType(ty); if (loweredTy != argrv.getType()) { argrv = ManagedValue::forUnmanaged( SGF.B.createUncheckedBitCast(loc, argrv.getValue(), loweredTy)); } } } else { assert(vd->isImmutable() && "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(), SILDebugVariable(vd->isLet(), ArgNo)); else SGF.B.createDebugValue(loc, argrv.getValue(), SILDebugVariable(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()) { 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(), SILDebugVariable(PD->isLet(), ArgNo)); else SGF.B.createDebugValue(loc, argrv.getValue(), SILDebugVariable(PD->isLet(), ArgNo)); } }; } // end anonymous namespace static void makeArgument(Type ty, ParamDecl *decl, SmallVectorImpl &args, SILGenFunction &SGF) { assert(ty && "no type?!"); // Destructure tuple arguments. if (TupleType *tupleTy = ty->getAs()) { 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 ¶meters) { 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, uint16_t 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(val)) AllocStack->setArgNo(ArgNo); else { SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); SGF.B.createDebugValue(Loc, val, DbgVar); } // 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); SILDebugVariable DbgVar(/*Constant*/ false, ArgNo); SGF.B.createDebugValueAddr(Loc, addr, DbgVar); 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); SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); SGF.B.createDebugValueAddr(Loc, addr, DbgVar); break; } } } void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, ArrayRef paramPatterns, Type resultType, bool throws) { uint16_t 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()) { 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; } uint16_t SILGenFunction::emitProlog(ArrayRef 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 ¶m : *paramList) emitter.emitParam(param); } // Record the ArgNo of the artificial $error inout argument. unsigned ArgNo = emitter.getNumArgs(); if (throws) { RegularLocation Loc = RegularLocation::getAutoGeneratedLocation(); if (auto *AFD = dyn_cast(DC)) Loc = AFD->getThrowsLoc(); else if (auto *ACE = dyn_cast(DC)) Loc = ACE->getLoc(); auto NativeErrorTy = SILType::getExceptionType(getASTContext()); ManagedValue Undef = emitUndef(Loc, NativeErrorTy); SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo); B.createDebugValue(Loc, Undef.getValue(), DbgVar); } return ArgNo; }