ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF, SGFContext C) && { switch (StoredKind) { case Kind::Invalid: llvm_unreachable("argument source is invalid"); case Kind::LValue: { auto loc = getKnownLValueLocation(); LValue &&lv = std::move(*this).asKnownLValue(); return SGF.emitAddressOfLValue(loc, std::move(lv)); } case Kind::RValue: { auto loc = getKnownRValueLocation(); if (auto init = C.getEmitInto()) { std::move(*this).asKnownRValue(SGF) .ensurePlusOne(SGF, loc) .forwardInto(SGF, loc, init); return ManagedValue::forInContext(); } else { return std::move(*this).asKnownRValue(SGF).getAsSingleValue(SGF, loc); } } case Kind::Expr: { auto e = std::move(*this).asKnownExpr(); if (e->isSemanticallyInOutExpr()) { auto lv = SGF.emitLValue(e, SGFAccessKind::ReadWrite); return SGF.emitAddressOfLValue(e, std::move(lv)); } else { return SGF.emitRValueAsSingleValue(e, C); } } } llvm_unreachable("bad kind"); }
ManagedValue SILGenFunction::manageOpaqueValue(OpaqueValueState &entry, SILLocation loc, SGFContext C) { // If the opaque value is consumable, we can just return the // value with a cleanup. There is no need to retain it separately. if (entry.IsConsumable) { assert(!entry.HasBeenConsumed && "Uniquely-referenced opaque value already consumed"); entry.HasBeenConsumed = true; return entry.Value; } assert(!entry.Value.hasCleanup()); // If the context wants a +0 value, guaranteed or immediate, we can // give it to them, because OpenExistential emission guarantees the // value. if (C.isGuaranteedPlusZeroOk()) { return entry.Value; } // If the context wants us to initialize a buffer, copy there instead // of making a temporary allocation. if (auto I = C.getEmitInto()) { if (SILValue address = I->getAddressForInPlaceInitialization()) { entry.Value.copyInto(*this, address, loc); I->finishInitialization(*this); return ManagedValue::forInContext(); } } // Otherwise, copy the value into a temporary. return entry.Value.copyUnmanaged(*this, loc); }
RValue ArgumentSource::getKnownTupleAsRValue(SILGenFunction &SGF, SGFContext C) && { return std::move(*this).withKnownTupleElementSources<RValue>( [&](SILLocation loc, CanTupleType type, MutableArrayRef<ArgumentSource> elements) { // If there's a target initialization, and we can split it, do so. if (auto init = C.getEmitInto()) { if (init->canSplitIntoTupleElements()) { // Split the tuple. SmallVector<InitializationPtr, 4> scratch; auto eltInits = init->splitIntoTupleElements(SGF, loc, type, scratch); // Emit each element into the corresponding element initialization. for (auto i : indices(eltInits)) { std::move(elements[i]).forwardInto(SGF, eltInits[i].get()); } // Finish initialization. init->finishInitialization(SGF); return RValue::forInContext(); } } // Otherwise, emit all of the elements into a single big r-value. RValue result(type); for (auto &element : elements) { result.addElement(std::move(element).getAsRValue(SGF)); } return result; }); }
ManagedValue SILGenBuilder::formalAccessBufferForExpr( SILLocation loc, SILType ty, const TypeLowering &lowering, SGFContext context, std::function<void(SILValue)> rvalueEmitter) { // If we have a single-buffer "emit into" initialization, use that for the // result. SILValue address = context.getAddressForInPlaceInitialization(); // If we couldn't emit into the Initialization, emit into a temporary // allocation. if (!address) { address = gen.emitTemporaryAllocation(loc, ty.getObjectType()); } rvalueEmitter(address); // If we have a single-buffer "emit into" initialization, use that for the // result. if (context.getAddressForInPlaceInitialization()) { context.getEmitInto()->finishInitialization(gen); return ManagedValue::forInContext(); } // Add a cleanup for the temporary we allocated. if (lowering.isTrivial()) return ManagedValue::forUnmanaged(address); return gen.emitFormalAccessManagedBufferWithCleanup(loc, address); }
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF, SGFContext C) && { switch (StoredKind) { case Kind::Invalid: llvm_unreachable("argument source is invalid"); case Kind::LValue: { auto loc = getKnownLValueLocation(); return SGF.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(), AccessKind::ReadWrite); } case Kind::RValue: { auto loc = getKnownRValueLocation(); if (auto init = C.getEmitInto()) { std::move(*this).asKnownRValue().forwardInto(SGF, loc, init); return ManagedValue::forInContext(); } else { return std::move(*this).asKnownRValue().getAsSingleValue(SGF, loc); } } case Kind::Expr: { auto e = std::move(*this).asKnownExpr(); if (e->getType()->is<InOutType>()) { return SGF.emitAddressOfLValue(e, SGF.emitLValue(e, AccessKind::ReadWrite), AccessKind::ReadWrite); } else { return SGF.emitRValueAsSingleValue(e, C); } } case Kind::Tuple: { auto loc = getKnownTupleLocation(); auto rvalue = std::move(*this).getKnownTupleAsRValue(SGF, C); if (rvalue.isInContext()) return ManagedValue::forInContext(); return std::move(rvalue).getAsSingleValue(SGF, loc); } } llvm_unreachable("bad kind"); }
RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF, SILLocation loc, ManagedValue operand, Type operandType, Type optTargetType, CheckedCastKind castKind, SGFContext C) { // Drill into the result type. CanType resultObjectType = optTargetType->getCanonicalType().getAnyOptionalObjectType(); assert(resultObjectType); // Handle collection downcasts directly; they have specific library // entry points. if (castKind == CheckedCastKind::ArrayDowncast || castKind == CheckedCastKind::DictionaryDowncast || castKind == CheckedCastKind::SetDowncast) { return emitCollectionDowncastExpr(SGF, operand, operandType, loc, resultObjectType, C, /*conditional=*/true); } operand = adjustForConditionalCheckedCastOperand(loc, operand, operandType->getCanonicalType(), resultObjectType, SGF); auto someDecl = SGF.getASTContext().getOptionalSomeDecl(); auto &resultTL = SGF.getTypeLowering(optTargetType); // Set up a result buffer if desirable/required. SILValue resultBuffer; SILValue resultObjectBuffer; Optional<TemporaryInitialization> resultObjectTemp; SGFContext resultObjectCtx; if (resultTL.isAddressOnly() || (C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) { SILType resultTy = resultTL.getLoweredType(); resultBuffer = SGF.getBufferForExprResult(loc, resultTy, C); resultObjectBuffer = SGF.B.createInitEnumDataAddr(loc, resultBuffer, someDecl, resultTy.getAnyOptionalObjectType().getAddressType()); resultObjectTemp.emplace(resultObjectBuffer, CleanupHandle::invalid()); resultObjectCtx = SGFContext(&resultObjectTemp.getValue()); } // Prepare a jump destination here. ExitableFullExpr scope(SGF, CleanupLocation::get(loc)); auto operandCMV = ConsumableManagedValue::forOwned(operand); SGF.emitCheckedCastBranch(loc, operandCMV, operandType, resultObjectType, resultObjectCtx, // The success path. [&](ManagedValue objectValue) { // If we're not emitting into a temporary, just wrap up the result // in Some and go to the continuation block. if (!resultObjectTemp) { auto some = SGF.B.createEnum(loc, objectValue.forward(SGF), someDecl, resultTL.getLoweredType()); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { some }); return; } // Otherwise, make sure the value is in the context. if (!objectValue.isInContext()) { objectValue.forwardInto(SGF, loc, resultObjectBuffer); } SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc); }, // The failure path. [&] { auto noneDecl = SGF.getASTContext().getOptionalNoneDecl(); // If we're not emitting into a temporary, just wrap up the result // in None and go to the continuation block. if (!resultObjectTemp) { auto none = SGF.B.createEnum(loc, nullptr, noneDecl, resultTL.getLoweredType()); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { none }); // Just construct the enum directly in the context. } else { SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc); } }); // Enter the continuation block. auto contBB = scope.exit(); ManagedValue result; if (resultObjectTemp) { result = SGF.manageBufferForExprResult(resultBuffer, resultTL, C); } else { auto argument = new (SGF.F.getModule()) SILArgument(contBB, resultTL.getLoweredType()); result = SGF.emitManagedRValueWithCleanup(argument, resultTL); } return RValue(SGF, loc, optTargetType->getCanonicalType(), result); }