ManagedValue SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc, ManagedValue optional) { // Generate code to the optional is present, and if not, abort with a message // (provided by the stdlib). SILBasicBlock *contBB = createBasicBlock(); SILBasicBlock *failBB = createBasicBlock(); bool hadCleanup = optional.hasCleanup(); bool hadLValue = optional.isLValue(); auto noneDecl = getASTContext().getOptionalNoneDecl(); auto someDecl = getASTContext().getOptionalSomeDecl(); if (optional.getType().isAddress()) { // We forward in the creation routine for // unchecked_take_enum_data_addr. switch_enum_addr is a +0 operation. B.createSwitchEnumAddr(loc, optional.getValue(), /*defaultDest*/ nullptr, {{someDecl, contBB}, {noneDecl, failBB}}); } else { B.createSwitchEnum(loc, optional.forward(*this), /*defaultDest*/ nullptr, {{someDecl, contBB}, {noneDecl, failBB}}); } B.emitBlock(failBB); // Call the standard library implementation of _diagnoseUnexpectedNilOptional. if (auto diagnoseFailure = getASTContext().getDiagnoseUnexpectedNilOptional(nullptr)) { ManagedValue args[4]; emitSourceLocationArgs(*this, loc, args); emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, SubstitutionMap(), args, SGFContext()); } B.createUnreachable(loc); B.clearInsertionPoint(); B.emitBlock(contBB); ManagedValue result; SILType payloadType = optional.getType().getAnyOptionalObjectType(); if (payloadType.isObject()) { result = B.createOwnedPHIArgument(payloadType); } else { result = B.createUncheckedTakeEnumDataAddr(loc, optional, someDecl, payloadType); } if (hadCleanup) { return result; } if (hadLValue) { return ManagedValue::forLValue(result.forward(*this)); } return ManagedValue::forUnmanaged(result.forward(*this)); }
ManagedValue SILGenFunction::emitCheckedGetOptionalValueFrom(SILLocation loc, ManagedValue src, const TypeLowering &optTL, SGFContext C) { SILType optType = src.getType().getObjectType(); OptionalTypeKind optionalKind; CanType valueType = getOptionalValueType(optType, optionalKind); FuncDecl *fn = getASTContext().getOptionalUnwrappedDecl( nullptr, optionalKind); Substitution sub = getSimpleSubstitution(fn, valueType); // The intrinsic takes its parameter indirectly. if (src.getType().isObject()) { auto buf = emitTemporaryAllocation(loc, src.getType()); B.createStore(loc, src.forward(*this), buf); src = emitManagedBufferWithCleanup(buf); } RValue result = emitApplyOfLibraryIntrinsic(loc, fn, sub, src, C); if (result) { return std::move(result).getAsSingleValue(*this, loc); } else { return ManagedValue::forInContext(); } }
static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen, SILLocation loc, ManagedValue v, SILType bridgedTy) { assert(v.getType().isLoadable(gen.F.getModule()) && "Cannot bridge address-only types"); CanType loweredBridgedTy = bridgedTy.getSwiftRValueType(); CanType loweredNativeTy = v.getType().getSwiftRValueType(); if (loweredNativeTy == loweredBridgedTy) return v; if (loweredNativeTy.getAnyOptionalObjectType()) { return gen.emitOptionalToOptional(loc, v, bridgedTy, emitNativeToCBridgedValue); } // Check if we need to wrap the bridged result in an optional. OptionalTypeKind OTK; if (SILType bridgedObjectType = bridgedTy.getAnyOptionalObjectType(gen.SGM.M, OTK)) { auto bridgedPayload = emitNativeToCBridgedNonoptionalValue(gen, loc, v, bridgedObjectType); return gen.getOptionalSomeValue(loc, bridgedPayload, gen.getTypeLowering(bridgedTy)); } return emitNativeToCBridgedNonoptionalValue(gen, loc, v, bridgedTy); }
ManagedValue SILGenBuilder::createBlockToAnyObject(SILLocation loc, ManagedValue v, SILType destType) { assert(SGF.getASTContext().LangOpts.EnableObjCInterop); assert(destType.isAnyObject()); assert(v.getType().is<SILFunctionType>()); assert(v.getType().castTo<SILFunctionType>()->getRepresentation() == SILFunctionTypeRepresentation::Block); // For now, we don't have a better instruction than this. return createUncheckedRefCast(loc, v, destType); }
ManagedValue Scope::popPreservingValue(ManagedValue mv) { // If we have a value, make sure that it is an object. The reason why is // that we want to make sure that we are not forwarding a cleanup for a // stack location that will be destroyed by this scope. assert(mv && mv.getType().isObject() && (mv.getType().isTrivial(cleanups.SGF.getModule()) || mv.getOwnershipKind() == ValueOwnershipKind::Trivial || mv.hasCleanup())); CleanupCloner cloner(cleanups.SGF, mv); SILValue value = mv.forward(cleanups.SGF); pop(); return cloner.clone(value); }
void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { assert(thunk.isCurried); auto *vd = thunk.getDecl(); if (auto *fd = dyn_cast<AbstractFunctionDecl>(vd)) { assert(!SGM.M.Types.hasLoweredLocalCaptures(fd) && "methods cannot have captures"); (void) fd; } auto selfTy = vd->getInterfaceType()->castTo<AnyFunctionType>() ->getInput(); selfTy = vd->getInnermostDeclContext()->mapTypeIntoContext(selfTy); ManagedValue selfArg = B.createFunctionArgument(getLoweredType(selfTy), nullptr); // Forward substitutions. auto subs = F.getForwardingSubstitutions(); ManagedValue toFn = getNextUncurryLevelRef(*this, vd, thunk, selfArg, subs); // FIXME: Using the type from the ConstantInfo instead of looking at // getConstantOverrideInfo() for methods looks suspect in the presence // of covariant overrides and multiple vtable entries. SILFunctionConventions fromConv( SGM.Types.getConstantInfo(thunk).SILFnType, SGM.M); SILType resultTy = fromConv.getSingleSILResultType(); resultTy = F.mapTypeIntoContext(resultTy); auto substTy = toFn.getType().substGenericArgs(SGM.M, subs); // Partially apply the next uncurry level and return the result closure. selfArg = selfArg.ensurePlusOne(*this, vd); auto calleeConvention = ParameterConvention::Direct_Guaranteed; auto closureTy = SILGenBuilder::getPartialApplyResultType( toFn.getType(), /*appliedParams=*/1, SGM.M, subs, calleeConvention); ManagedValue toClosure = B.createPartialApply(vd, toFn, substTy, subs, {selfArg}, closureTy); if (resultTy != closureTy) { CanSILFunctionType resultFnTy = resultTy.castTo<SILFunctionType>(); CanSILFunctionType closureFnTy = closureTy.castTo<SILFunctionType>(); if (resultFnTy->isABICompatibleWith(closureFnTy).isCompatible()) { toClosure = B.createConvertFunction(vd, toClosure, resultTy); } else { toClosure = emitCanonicalFunctionThunk(vd, toClosure, closureFnTy, resultFnTy); } } B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(vd), toClosure); }
/// Bridge an optional foreign error type to ErrorProtocol. ManagedValue SILGenFunction::emitBridgedToNativeError(SILLocation loc, ManagedValue bridgedError) { #ifndef NDEBUG { OptionalTypeKind optKind; auto objType = bridgedError.getType().getSwiftRValueType() .getAnyOptionalObjectType(optKind); assert(optKind == OTK_Optional && "not Optional type"); assert(objType == SGM.Types.getNSErrorType() && "only handling NSError for now"); } #endif auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getNSErrorToErrorProtocolFn()); auto bridgeFnType = bridgeFn->getType().castTo<SILFunctionType>(); assert(bridgeFnType->getNumAllResults() == 1); assert(bridgeFnType->getAllResults()[0].getConvention() == ResultConvention::Owned); auto nativeErrorProtocol = bridgeFnType->getAllResults()[0].getSILType(); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Owned); SILValue nativeError = B.createApply(loc, bridgeFn, bridgeFn->getType(), nativeErrorProtocol, {}, bridgedError.forward(*this)); return emitManagedRValueWithCleanup(nativeError); }
static ManagedValue emitBuiltinAllocWithTailElems(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { unsigned NumTailTypes = subs.getReplacementTypes().size() - 1; assert(args.size() == NumTailTypes * 2 + 1 && "wrong number of substitutions for allocWithTailElems"); // The substitution determines the element type for bound memory. auto replacementTypes = subs.getReplacementTypes(); SILType RefType = SGF.getLoweredType(replacementTypes[0]-> getCanonicalType()).getObjectType(); SmallVector<ManagedValue, 4> Counts; SmallVector<SILType, 4> ElemTypes; for (unsigned Idx = 0; Idx < NumTailTypes; ++Idx) { Counts.push_back(args[Idx * 2 + 1]); ElemTypes.push_back(SGF.getLoweredType(replacementTypes[Idx+1]-> getCanonicalType()).getObjectType()); } ManagedValue Metatype = args[0]; if (isa<MetatypeInst>(Metatype)) { auto InstanceType = Metatype.getType().castTo<MetatypeType>().getInstanceType(); assert(InstanceType == RefType.getASTType() && "substituted type does not match operand metatype"); (void) InstanceType; return SGF.B.createAllocRef(loc, RefType, false, false, ElemTypes, Counts); } else { return SGF.B.createAllocRefDynamic(loc, Metatype, RefType, false, ElemTypes, Counts); } }
static ManagedValue emitBuiltinAllocWithTailElems(SILGenFunction &gen, SILLocation loc, SubstitutionList subs, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { unsigned NumTailTypes = subs.size() - 1; assert(args.size() == NumTailTypes * 2 + 1 && "wrong number of substitutions for allocWithTailElems"); // The substitution determines the element type for bound memory. SILType RefType = gen.getLoweredType(subs[0].getReplacement()-> getCanonicalType()).getObjectType(); SmallVector<ManagedValue, 4> Counts; SmallVector<SILType, 4> ElemTypes; for (unsigned Idx = 0; Idx < NumTailTypes; ++Idx) { Counts.push_back(args[Idx * 2 + 1]); ElemTypes.push_back(gen.getLoweredType(subs[Idx+1].getReplacement()-> getCanonicalType()).getObjectType()); } ManagedValue Metatype = args[0]; if (isa<MetatypeInst>(Metatype)) { assert(Metatype.getType().getMetatypeInstanceType(gen.SGM.M) == RefType && "substituted type does not match operand metatype"); return gen.B.createAllocRef(loc, RefType, false, false, ElemTypes, Counts); } else { return gen.B.createAllocRefDynamic(loc, Metatype, RefType, false, ElemTypes, Counts); } }
static ManagedValue emitBridgeCollectionToNative(SILGenFunction &gen, SILLocation loc, SILDeclRef bridgeFnRef, ManagedValue collection, SILType nativeTy) { SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef); auto collectionTy = nativeTy.getSwiftRValueType()->castTo<BoundGenericType>(); auto subs = collectionTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); Type inputType = collection.getType().getSwiftRValueType(); if (!inputType->getOptionalObjectType()) { SILType loweredOptTy = gen.SGM.getLoweredType(OptionalType::get(inputType)); auto *someDecl = gen.getASTContext().getOptionalSomeDecl(); auto *enumInst = gen.B.createEnum(loc, collection.getValue(), someDecl, loweredOptTy); collection = ManagedValue(enumInst, collection.getCleanup()); } SILValue result = gen.B.createApply(loc, bridgeFn, substFnType, nativeTy, subs, { collection.forward(gen) }); return gen.emitManagedRValueWithCleanup(result); }
static ManagedValue emitBridgeCollectionFromNative(SILGenFunction &gen, SILLocation loc, SILDeclRef bridgeFnRef, ManagedValue collection, SILType bridgedTy) { SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef); // If the expected return is optional, we'll need to wrap it. OptionalTypeKind OTK = OTK_None; SILType origBridgedTy = bridgedTy; if (auto bridgedObjTy = bridgedTy.getAnyOptionalObjectType(gen.SGM.M, OTK)) { bridgedTy = bridgedObjTy; } // Figure out the type parameters. auto inputTy = collection.getType().getSwiftRValueType()->castTo<BoundGenericType>(); auto subs = inputTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); SILValue bridged = gen.B.createApply(loc, bridgeFn, substFnType, bridgedTy, subs, { collection.forward(gen) }); // Wrap the result if necessary. if (OTK != OTK_None) { bridged = gen.B.createEnum(loc, bridged, gen.getASTContext().getOptionalSomeDecl(OTK), origBridgedTy); } return gen.emitManagedRValueWithCleanup(bridged); }
RValue SILGenFunction::emitPointerToPointer(SILLocation loc, ManagedValue input, CanType inputType, CanType outputType, SGFContext C) { auto converter = getASTContext().getConvertPointerToPointerArgument(nullptr); // The generic function currently always requires indirection, but pointers // are always loadable. auto origBuf = emitTemporaryAllocation(loc, input.getType()); B.emitStoreValueOperation(loc, input.forward(*this), origBuf, StoreOwnershipQualifier::Init); auto origValue = emitManagedBufferWithCleanup(origBuf); // Invoke the conversion intrinsic to convert to the destination type. auto *M = SGM.M.getSwiftModule(); auto *proto = getPointerProtocol(); auto firstSubMap = inputType->getContextSubstitutionMap(M, proto); auto secondSubMap = outputType->getContextSubstitutionMap(M, proto); auto *genericSig = converter->getGenericSignature(); auto subMap = SubstitutionMap::combineSubstitutionMaps(firstSubMap, secondSubMap, CombineSubstitutionMaps::AtIndex, 1, 0, genericSig); return emitApplyOfLibraryIntrinsic(loc, converter, subMap, origValue, C); }
/// Bridge a native function to a block with a thunk. ManagedValue SILGenFunction::emitBlockToFunc(SILLocation loc, ManagedValue block, CanSILFunctionType funcTy) { CanSILFunctionType substFnTy; SmallVector<Substitution, 4> subs; // Declare the thunk. auto blockTy = block.getType().castTo<SILFunctionType>(); auto thunkTy = buildThunkType(block, funcTy, substFnTy, subs); auto thunk = SGM.getOrCreateReabstractionThunk(F.getContextGenericParams(), thunkTy, blockTy, funcTy, F.isFragile()); // Build it if necessary. if (thunk->empty()) { SILGenFunction thunkSGF(SGM, *thunk); thunk->setContextGenericParams(F.getContextGenericParams()); auto loc = RegularLocation::getAutoGeneratedLocation(); buildBlockToFuncThunkBody(thunkSGF, loc, blockTy, funcTy); } // Create it in the current function. auto thunkValue = B.createFunctionRef(loc, thunk); auto thunkedFn = B.createPartialApply(loc, thunkValue, SILType::getPrimitiveObjectType(substFnTy), subs, block.forward(*this), SILType::getPrimitiveObjectType(funcTy)); return emitManagedRValueWithCleanup(thunkedFn); }
/// Bridge a native function to a block with a thunk. ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, ManagedValue fn, CanSILFunctionType blockTy) { // Build the invoke function signature. The block will capture the original // function value. auto fnTy = fn.getType().castTo<SILFunctionType>(); auto storageTy = SILBlockStorageType::get(fnTy); // Build the invoke function type. SmallVector<SILParameterInfo, 4> params; params.push_back(SILParameterInfo(storageTy, ParameterConvention::Indirect_InoutAliasable)); std::copy(blockTy->getParameters().begin(), blockTy->getParameters().end(), std::back_inserter(params)); auto invokeTy = SILFunctionType::get(nullptr, SILFunctionType::ExtInfo() .withRepresentation(SILFunctionType::Representation:: CFunctionPointer), ParameterConvention::Direct_Unowned, params, blockTy->getAllResults(), blockTy->getOptionalErrorResult(), getASTContext()); // Create the invoke function. Borrow the mangling scheme from reabstraction // thunks, which is what we are in spirit. auto thunk = SGM.getOrCreateReabstractionThunk(nullptr, invokeTy, fnTy, blockTy, F.isFragile()); // Build it if necessary. if (thunk->empty()) { SILGenFunction thunkSGF(SGM, *thunk); auto loc = RegularLocation::getAutoGeneratedLocation(); buildFuncToBlockInvokeBody(thunkSGF, loc, blockTy, storageTy, fnTy); } // Form the block on the stack. auto storageAddrTy = SILType::getPrimitiveAddressType(storageTy); auto storage = emitTemporaryAllocation(loc, storageAddrTy); auto capture = B.createProjectBlockStorage(loc, storage); // Store the function to the block without claiming it, so that it still // gets cleaned up in scope. Copying the block will create an independent // reference. B.createStore(loc, fn.getValue(), capture); auto invokeFn = B.createFunctionRef(loc, thunk); auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn, SILType::getPrimitiveObjectType(blockTy)); // Copy the block so we have an independent heap object we can hand off. auto heapBlock = B.createCopyBlock(loc, stackBlock); return emitManagedRValueWithCleanup(heapBlock); }
static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen, SILLocation loc, ManagedValue v, SILType nativeTy) { CanType loweredNativeTy = nativeTy.getSwiftRValueType(); CanType loweredBridgedTy = v.getType().getSwiftRValueType(); if (loweredNativeTy == loweredBridgedTy) return v; if (loweredNativeTy.getAnyOptionalObjectType()) { return gen.emitOptionalToOptional(loc, v, nativeTy, emitCBridgedToNativeValue); } // Bridge Bool to ObjCBool or DarwinBoolean when requested. if (loweredNativeTy == gen.SGM.Types.getBoolType()) { if (loweredBridgedTy == gen.SGM.Types.getObjCBoolType()) { return emitBridgeForeignBoolToBool(gen, loc, v, gen.SGM.getObjCBoolToBoolFn()); } if (loweredBridgedTy == gen.SGM.Types.getDarwinBooleanType()) { return emitBridgeForeignBoolToBool(gen, loc, v, gen.SGM.getDarwinBooleanToBoolFn()); } } // Bridge Objective-C to thick metatypes. if (auto bridgedMetaTy = dyn_cast<AnyMetatypeType>(loweredBridgedTy)){ if (bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) { SILValue native = gen.B.emitObjCToThickMetatype(loc, v.getValue(), gen.getLoweredType(loweredNativeTy)); return ManagedValue(native, v.getCleanup()); } } // Bridge blocks back into native function types. auto bridgedFTy = dyn_cast<SILFunctionType>(loweredBridgedTy); if (bridgedFTy && bridgedFTy->getRepresentation() == SILFunctionType::Representation::Block){ auto nativeFTy = cast<SILFunctionType>(loweredNativeTy); if (nativeFTy->getRepresentation() != SILFunctionType::Representation::Block) return gen.emitBlockToFunc(loc, v, nativeFTy); } // Bridge via _ObjectiveCBridgeable. if (auto conformance = gen.SGM.getConformanceToObjectiveCBridgeable(loc, loweredNativeTy)) { if (auto result = emitBridgeObjectiveCToNative(gen, loc, v, conformance)) return *result; assert(gen.SGM.getASTContext().Diags.hadAnyError() && "Bridging code should have complained"); return gen.emitUndef(loc, nativeTy); } return v; }
static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &gen, SILLocation loc, ManagedValue v, SILType bridgedTy) { CanType loweredBridgedTy = bridgedTy.getSwiftRValueType(); CanType loweredNativeTy = v.getType().getSwiftRValueType(); if (loweredNativeTy == loweredBridgedTy) return v; // FIXME: Handle this via an _ObjectiveCBridgeable query rather than // hardcoding String -> NSString. if (loweredNativeTy == gen.SGM.Types.getStringType() && loweredBridgedTy == gen.SGM.Types.getNSStringType()) { if (auto result = emitBridgeNativeToObjectiveC(gen, loc, v)) return *result; return gen.emitUndef(loc, bridgedTy); } // If the input is a native type with a bridged mapping, convert it. #define BRIDGE_TYPE(BridgedModule,BridgedType, NativeModule,NativeType,Opt) \ if (loweredNativeTy == gen.SGM.Types.get##NativeType##Type() \ && loweredBridgedTy == gen.SGM.Types.get##BridgedType##Type()) { \ return emitBridge##NativeType##To##BridgedType(gen, loc, v); \ } #include "swift/SIL/BridgedTypes.def" // Bridge thick to Objective-C metatypes. if (auto bridgedMetaTy = dyn_cast<AnyMetatypeType>(loweredBridgedTy)) { if (bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) { SILValue native = gen.B.emitThickToObjCMetatype(loc, v.getValue(), SILType::getPrimitiveObjectType(loweredBridgedTy)); return ManagedValue(native, v.getCleanup()); } } // Bridge native functions to blocks. auto bridgedFTy = dyn_cast<SILFunctionType>(loweredBridgedTy); if (bridgedFTy && bridgedFTy->getRepresentation() == SILFunctionType::Representation::Block){ auto nativeFTy = cast<SILFunctionType>(loweredNativeTy); if (nativeFTy->getRepresentation() != SILFunctionType::Representation::Block) return gen.emitFuncToBlock(loc, v, bridgedFTy); } // If the native type conforms to _ObjectiveCBridgeable, use its // _bridgeToObjectiveC witness. if (auto conformance = gen.SGM.getConformanceToObjectiveCBridgeable(loc, loweredNativeTy)) { if (auto result = emitBridgeNativeToObjectiveC(gen, loc, v, conformance)) return *result; return gen.emitUndef(loc, bridgedTy); } return v; }
SILValue Lowering::emitIsa(SILGenFunction &SGF, SILLocation loc, Expr *operand, Type targetType, CheckedCastKind castKind) { // Handle collection downcasts separately. if (castKind == CheckedCastKind::ArrayDowncast || castKind == CheckedCastKind::DictionaryDowncast || castKind == CheckedCastKind::SetDowncast) { ManagedValue operandMV = SGF.emitRValueAsSingleValue(operand); ManagedValue optValue = emitCollectionDowncastExpr( SGF, operandMV, operand->getType(), loc, targetType, SGFContext(), /*conditional=*/true) .getAsSingleValue(SGF, loc); // Materialize the input. SILValue optValueTemp; if (optValue.getType().isAddress()) { optValueTemp = optValue.forward(SGF); } else { optValueTemp = SGF.emitTemporaryAllocation(loc, optValue.getType()); optValue.forwardInto(SGF, loc, optValueTemp); } return SGF.emitDoesOptionalHaveValue(loc, optValueTemp); } // Prepare a jump destination here. ExitableFullExpr scope(SGF, CleanupLocation::get(loc)); auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext()); SGF.emitCheckedCastBranch(loc, operand, targetType, SGFContext(), [&](ManagedValue value) { SILValue yes = SGF.B.createIntegerLiteral(loc, i1Ty, 1); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, yes); }, [&] { SILValue no = SGF.B.createIntegerLiteral(loc, i1Ty, 0); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, no); }); auto contBB = scope.exit(); auto isa = new (SGF.SGM.M) SILArgument(contBB, i1Ty); return isa; }
static ManagedValue adjustForConditionalCheckedCastOperand(SILLocation loc, ManagedValue src, CanType sourceType, CanType targetType, SILGenFunction &SGF) { // Reabstract to the most general abstraction, and put it into a // temporary if necessary. // Figure out if we need the value to be in a temporary. bool requiresAddress = !canUseScalarCheckedCastInstructions(SGF.SGM.M, sourceType, targetType); AbstractionPattern abstraction = SGF.SGM.M.Types.getMostGeneralAbstraction(); auto &srcAbstractTL = SGF.getTypeLowering(abstraction, sourceType); bool hasAbstraction = (src.getType() != srcAbstractTL.getLoweredType()); // Fast path: no re-abstraction required. if (!hasAbstraction && (!requiresAddress || src.getType().isAddress())) { return src; } std::unique_ptr<TemporaryInitialization> init; SGFContext ctx; if (requiresAddress) { init = SGF.emitTemporary(loc, srcAbstractTL); // Okay, if all we need to do is drop the value in an address, // this is easy. if (!hasAbstraction) { SGF.B.createStore(loc, src.forward(SGF), init->getAddress()); init->finishInitialization(SGF); return init->getManagedAddress(); } ctx = SGFContext(init.get()); } assert(hasAbstraction); assert(src.getType().isObject() && "address-only type with abstraction difference?"); // Produce the value at +1. return SGF.emitSubstToOrigValue(loc, src, abstraction, sourceType); }
/// Emit a materializeForSet operation that calls a mutable addressor. /// /// If it's not an unsafe addressor, this uses a callback function to /// write the l-value back. SILValue MaterializeForSetEmitter::emitUsingAddressor(SILGenFunction &SGF, SILLocation loc, ManagedValue self, RValue &&indices, SILValue callbackBuffer, SILFunction *&callback) { bool isDirect = (TheAccessSemantics != AccessSemantics::Ordinary); // Call the mutable addressor. auto addressor = SGF.getAddressorDeclRef(WitnessStorage, AccessKind::ReadWrite, isDirect); std::pair<ManagedValue, ManagedValue> result; { FormalEvaluationScope Scope(SGF); SILType addressType = WitnessStorageType.getAddressType(); ArgumentSource baseRV = SGF.prepareAccessorBaseArg(loc, self, SubstSelfType, addressor); result = SGF.emitAddressorAccessor(loc, addressor, WitnessSubs, std::move(baseRV), IsSuper, isDirect, std::move(indices), addressType); } SILValue address = result.first.getUnmanagedValue(); AddressorKind addressorKind = WitnessStorage->getMutableAddressor()->getAddressorKind(); ManagedValue owner = result.second; if (!owner) { assert(addressorKind == AddressorKind::Unsafe); } else { SILValue allocatedCallbackBuffer = SGF.B.createAllocValueBuffer(loc, owner.getType(), callbackBuffer); SGF.B.emitStoreValueOperation(loc, owner.forward(SGF), allocatedCallbackBuffer, StoreOwnershipQualifier::Init); callback = createAddressorCallback(SGF.F, owner.getType(), addressorKind); } return address; }
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc, ManagedValue addrOrValue, const TypeLowering &optTL, SGFContext C) { OptionalTypeKind OTK; SILType origPayloadTy = addrOrValue.getType().getAnyOptionalObjectType(SGM.M, OTK); auto formalOptionalTy = addrOrValue.getType().getSwiftRValueType(); auto formalPayloadTy = formalOptionalTy ->getAnyOptionalObjectType() ->getCanonicalType(); auto someDecl = getASTContext().getOptionalSomeDecl(OTK); ManagedValue payload; // Take the payload from the optional. Cheat a bit in the +0 // case—UncheckedTakeEnumData will never actually invalidate an Optional enum // value. SILValue payloadVal; if (!addrOrValue.getType().isAddress()) { payloadVal = B.createUncheckedEnumData(loc, addrOrValue.forward(*this), someDecl); } else { payloadVal = B.createUncheckedTakeEnumDataAddr(loc, addrOrValue.forward(*this), someDecl, origPayloadTy); if (optTL.isLoadable()) payloadVal = B.createLoad(loc, payloadVal); } // Produce a correctly managed value. if (addrOrValue.hasCleanup()) payload = emitManagedRValueWithCleanup(payloadVal); else payload = ManagedValue::forUnmanaged(payloadVal); // Reabstract it to the substituted form, if necessary. return emitOrigToSubstValue(loc, payload, AbstractionPattern::getOpaque(), formalPayloadTy, C); }
ManagedValue SILGenBuilder::createCopyUnownedValue(SILLocation loc, ManagedValue originalValue) { auto unownedType = originalValue.getType().castTo<UnownedStorageType>(); assert(unownedType->isLoadable(ResilienceExpansion::Maximal)); (void)unownedType; SILValue result = SILBuilder::createCopyUnownedValue(loc, originalValue.getValue()); return gen.emitManagedRValueWithCleanup(result); }
ManagedValue SILGenBuilder::createStore(SILLocation loc, ManagedValue value, SILValue address, StoreOwnershipQualifier qualifier) { SILModule &M = SGF.F.getModule(); CleanupCloner cloner(*this, value); if (value.getType().isTrivial(M) || value.getOwnershipKind() == ValueOwnershipKind::Any) qualifier = StoreOwnershipQualifier::Trivial; createStore(loc, value.forward(SGF), address, qualifier); return cloner.clone(address); }
ManagedValue SILGenBuilder::createUnsafeCopyUnownedValue(SILLocation loc, ManagedValue originalValue) { auto unmanagedType = originalValue.getType().getAs<UnmanagedStorageType>(); SILValue result = SILBuilder::createUnmanagedToRef( loc, originalValue.getValue(), SILType::getPrimitiveObjectType(unmanagedType.getReferentType())); SILBuilder::createUnmanagedRetainValue(loc, result, getDefaultAtomicity()); return gen.emitManagedRValueWithCleanup(result); }
ManagedValue SILGenBuilder::createOptionalSome(SILLocation loc, ManagedValue arg) { CleanupCloner cloner(*this, arg); auto &argTL = SGF.getTypeLowering(arg.getType()); SILType optionalType = SILType::getOptionalType(arg.getType()); if (argTL.isLoadable() || !SGF.silConv.useLoweredAddresses()) { SILValue someValue = createOptionalSome(loc, arg.forward(SGF), optionalType); return cloner.clone(someValue); } SILValue tempResult = SGF.emitTemporaryAllocation(loc, optionalType); RValue rvalue(SGF, loc, arg.getType().getASTType(), arg); ArgumentSource argValue(loc, std::move(rvalue)); SGF.emitInjectOptionalValueInto( loc, std::move(argValue), tempResult, SGF.getTypeLowering(tempResult->getType())); return ManagedValue::forUnmanaged(tempResult); }
ManagedValue SILGenBuilder::createLoadTake(SILLocation loc, ManagedValue v, const TypeLowering &lowering) { assert(lowering.getLoweredType().getAddressType() == v.getType()); SILValue result = lowering.emitLoadOfCopy(*this, loc, v.forward(SGF), IsTake); if (lowering.isTrivial()) return ManagedValue::forUnmanaged(result); assert(!lowering.isAddressOnly() && "cannot retain an unloadable type"); return SGF.emitManagedRValueWithCleanup(result, lowering); }
ManagedValue SILGenBuilder::createLoadBorrow(SILLocation loc, ManagedValue base) { if (SGF.getTypeLowering(base.getType()).isTrivial()) { auto *i = createLoad(loc, base.getValue(), LoadOwnershipQualifier::Trivial); return ManagedValue::forUnmanaged(i); } auto *i = createLoadBorrow(loc, base.getValue()); return SGF.emitManagedBorrowedRValueWithCleanup(base.getValue(), i); }
static void boxIndirectEnumPayload(SILGenFunction &gen, ManagedValue &payload, SILLocation loc, EnumElementDecl *element) { // If the payload is indirect, we'll need to box it. if (payload && (element->isIndirect() || element->getParentEnum()->isIndirect())) { auto box = gen.B.createAllocBox(loc, payload.getType()); payload.forwardInto(gen, loc, box->getAddressResult()); payload = gen.emitManagedRValueWithCleanup(box); } }
/// Recursively walk into the given formal index type, expanding tuples, /// in order to form the arguments to a subscript accessor. static void translateIndices(SILGenFunction &gen, SILLocation loc, AbstractionPattern pattern, CanType formalType, ArrayRef<ManagedValue> &sourceIndices, RValue &result) { // Expand if the pattern was a tuple. if (pattern.isTuple()) { auto formalTupleType = cast<TupleType>(formalType); for (auto i : indices(formalTupleType.getElementTypes())) { translateIndices(gen, loc, pattern.getTupleElementType(i), formalTupleType.getElementType(i), sourceIndices, result); } return; } assert(!sourceIndices.empty() && "ran out of elements in index!"); ManagedValue value = sourceIndices.front(); sourceIndices = sourceIndices.slice(1); // We're going to build an RValue here, so make sure we translate // indirect arguments to be scalar if we have a loadable type. if (value.getType().isAddress()) { auto &valueTL = gen.getTypeLowering(value.getType()); if (!valueTL.isAddressOnly()) { value = gen.emitLoad(loc, value.forward(gen), valueTL, SGFContext(), IsTake); } } // Reabstract the subscripts from the requirement pattern to the // formal type. value = gen.emitOrigToSubstValue(loc, value, pattern, formalType); // Invoking the accessor will expect a value of the formal type, so // don't reabstract to that here. // Add that to the result, further expanding if necessary. result.addElement(gen, value, formalType, loc); }
ManagedValue SILGenBuilder::createFormalAccessLoadBorrow(SILLocation loc, ManagedValue base) { if (getFunction().getTypeLowering(base.getType()).isTrivial()) { auto *i = SILBuilder::createLoad(loc, base.getValue(), LoadOwnershipQualifier::Trivial); return ManagedValue::forUnmanaged(i); } SILValue baseValue = base.getValue(); auto *i = SILBuilder::createLoadBorrow(loc, baseValue); return gen.emitFormalEvaluationManagedBorrowedRValueWithCleanup(loc, baseValue, i); }
// FIXME: With some changes to their callers, all of the below functions // could be re-worked to use emitInjectEnum(). ManagedValue SILGenFunction::emitInjectOptional(SILLocation loc, ManagedValue v, CanType inputFormalType, CanType substFormalType, const TypeLowering &expectedTL, SGFContext ctxt) { // Optional's payload is currently maximally abstracted. FIXME: Eventually // it shouldn't be. auto opaque = AbstractionPattern::getOpaque(); OptionalTypeKind substOTK; auto substObjectType = substFormalType.getAnyOptionalObjectType(substOTK); auto loweredTy = getLoweredType(opaque, substObjectType); if (v.getType() != loweredTy) v = emitTransformedValue(loc, v, AbstractionPattern(inputFormalType), inputFormalType, opaque, substObjectType); auto someDecl = getASTContext().getOptionalSomeDecl(substOTK); SILType optTy = getLoweredType(substFormalType); if (v.getType().isAddress()) { auto buf = getBufferForExprResult(loc, optTy.getObjectType(), ctxt); auto payload = B.createInitEnumDataAddr(loc, buf, someDecl, v.getType()); // FIXME: Is it correct to use IsTake here even if v doesn't have a cleanup? B.createCopyAddr(loc, v.forward(*this), payload, IsTake, IsInitialization); B.createInjectEnumAddr(loc, buf, someDecl); v = manageBufferForExprResult(buf, expectedTL, ctxt); } else { auto some = B.createEnum(loc, v.getValue(), someDecl, optTy); v = ManagedValue(some, v.getCleanup()); } return v; }