//===--- 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, ForUnwind_t forUnwind) 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, ForUnwind_t forUnwind) 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; CanSILFunctionType fnTy; ArrayRef ¶meters; EmitBBArguments(SILGenFunction &sgf, SILBasicBlock *parent, SILLocation l, CanSILFunctionType fnTy, ArrayRef ¶meters) : SGF(sgf), parent(parent), loc(l), fnTy(fnTy), parameters(parameters) {} ManagedValue visitType(CanType t) { return visitType(t, /*isInOut=*/false); } ManagedValue visitType(CanType t, bool isInOut) { // The calling convention always uses minimal resilience expansion but // inside the function we lower/expand types in context of the current // function. auto argType = SGF.SGM.Types.getLoweredType(t, SGF.getTypeExpansionContext()); auto argTypeConv = SGF.SGM.Types.getLoweredType(t, TypeExpansionContext::minimal()); argType = argType.getCategoryType(argTypeConv.getCategory()); if (isInOut) argType = SILType::getPrimitiveAddressType(argType.getASTType()); // Pop the next parameter info. auto parameterInfo = parameters.front(); parameters = parameters.slice(1); auto paramType = SGF.F.mapTypeIntoContext(SGF.getSILType(parameterInfo, fnTy)); ManagedValue mv = SGF.B.createInputFunctionArgument( paramType, loc.getAsASTNode()); if (argType != paramType) { // 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. assert( cast( argType.castTo().getInstanceType()) .getSelfType() == paramType.castTo().getInstanceType()); mv = SGF.B.createUncheckedBitCast(loc, mv, argType); } if (isInOut) return mv; // This can happen if the value is resilient in the calling convention // but not resilient locally. if (argType.isLoadable(SGF.F) && argType.isAddress()) { if (mv.isPlusOne(SGF)) mv = SGF.B.createLoadTake(loc, mv); else mv = SGF.B.createLoadBorrow(loc, mv); } // 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(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.SGM.Types.getTypeLowering(t, SGF.getTypeExpansionContext()); 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, loc, elementBuffer); } 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.getLoweredFunctionTypeInContext(SGF.B.getTypeExpansionContext()) ->getParameters()) {} unsigned getNumArgs() const { return ArgNo; } ManagedValue makeArgument(Type ty, bool isInOut, SILBasicBlock *parent, SILLocation l) { assert(ty && "no type?!"); // Create an RValue by emitting destructured arguments into a basic block. CanType canTy = ty->getCanonicalType(); EmitBBArguments argEmitter(SGF, parent, l, f.getLoweredFunctionType(), parameters); // Note: inouts of tuples are not exploded, so we bypass visit(). if (isInOut) return argEmitter.visitType(canTy, /*isInOut=*/true); return argEmitter.visit(canTy); } /// Create a SILArgument and store its value into the given Initialization, /// if not null. void makeArgumentIntoBinding(Type ty, SILBasicBlock *parent, ParamDecl *pd) { SILLocation loc(pd); loc.markAsPrologue(); ManagedValue argrv = makeArgument(ty, pd->isInOut(), parent, loc); if (pd->isInOut()) { assert(argrv.getType().isAddress() && "expected inout to be address"); } else { assert(pd->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[pd] = SILGenFunction::VarLoc::get(argrv.getValue()); SILValue value = argrv.getValue(); SILDebugVariable varinfo(pd->isImmutable(), ArgNo); if (!argrv.getType().isAddress()) { SGF.B.createDebugValue(loc, value, varinfo); } else { if (auto AllocStack = dyn_cast(value)) AllocStack->setArgNo(ArgNo); else SGF.B.createDebugValueAddr(loc, value, varinfo); } } void emitParam(ParamDecl *PD) { auto type = PD->getType(); assert(type->isMaterializable()); ++ArgNo; if (PD->hasName()) { makeArgumentIntoBinding(type, &*f.begin(), PD); return; } emitAnonymousParam(type, PD, PD); } void emitAnonymousParam(Type type, SILLocation paramLoc, 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(type, PD->isInOut(), &*f.begin(), paramLoc); // 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 value arguments. if (TupleType *tupleTy = decl->isInOut() ? nullptr : ty->getAs()) { for (auto fieldType : tupleTy->getElementTypes()) makeArgument(fieldType, decl, args, SGF); } else { 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 ¶meters) { makeArgument(param->getType(), param, parameters, *this); } void SILGenFunction::bindParametersForForwarding(const ParameterList *params, SmallVectorImpl ¶meters) { for (auto param : *params) bindParameterForForwarding(param, parameters); } static void emitCaptureArguments(SILGenFunction &SGF, GenericSignature origGenericSig, CapturedValue capture, uint16_t ArgNo) { auto *VD = cast(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()->getCanonicalType( origGenericSig); return SGF.F.mapTypeIntoContext(interfaceType); }; auto expansion = SGF.getTypeExpansionContext(); switch (SGF.SGM.Types.getDeclCaptureKind(capture, expansion)) { 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.emitCopyValueOperation(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(); // Get the content for the box in the minimal resilience domain because we // are declaring a type. auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture( VD, SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(), type), 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::Immutable: 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(CaptureInfo captureInfo, ParameterList *paramList, ParamDecl *selfParam, DeclContext *DC, Type resultType, bool throws, SourceLoc throwsLoc) { uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, DC, throws, throwsLoc); // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. assert(captureInfo.hasBeenComputed() && "can't emit prolog of function with uncomputed captures"); 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); OpaqueValues[opaqueValue] = ManagedValue::forUnmanaged(val); // Opaque values are always passed 'owned', so add a clean up if needed. if (!lowering.isTrivial()) enterDestroyCleanup(val); continue; } emitCaptureArguments(*this, DC->getGenericSignatureOfContext(), capture, ++ArgNo); } // Emit an unreachable instruction if a parameter type is // uninhabited if (paramList) { for (auto *param : *paramList) { if (param->getType()->isStructurallyUninhabited()) { SILLocation unreachableLoc(param); unreachableLoc.markAsPrologue(); B.createUnreachable(unreachableLoc); break; } } } } 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. // The calling convention always uses minimal resilience expansion. auto &resultTI = SGF.SGM.Types.getTypeLowering(DC->mapTypeIntoContext(resultType), SGF.getTypeExpansionContext()); auto &resultTIConv = SGF.SGM.Types.getTypeLowering( DC->mapTypeIntoContext(resultType), TypeExpansionContext::minimal()); if (!SILModuleConventions::isReturnedIndirectlyInSIL( resultTIConv.getLoweredType(), SGF.SGM.M)) { 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 *arg = SGF.F.begin()->createFunctionArgument( resultTI.getLoweredType().getAddressType(), var); (void)arg; } uint16_t SILGenFunction::emitProlog(ParameterList *paramList, ParamDecl *selfParam, Type resultType, DeclContext *DC, bool throws, SourceLoc throwsLoc) { // 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); // Add the SILArguments and use them to initialize the local argument // values. if (paramList) for (auto *param : *paramList) emitter.emitParam(param); if (selfParam) emitter.emitParam(selfParam); // Record the ArgNo of the artificial $error inout argument. unsigned ArgNo = emitter.getNumArgs(); if (throws) { auto NativeErrorTy = SILType::getExceptionType(getASTContext()); ManagedValue Undef = emitUndef(NativeErrorTy); SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo); RegularLocation loc = RegularLocation::getAutoGeneratedLocation(); if (throwsLoc.isValid()) loc = throwsLoc; B.createDebugValue(loc, Undef.getValue(), DbgVar); } return ArgNo; }