/// Specialized emitter for Builtin.reinterpretCast. static ManagedValue emitBuiltinReinterpretCast(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1 && "reinterpretCast should be given one argument"); assert(substitutions.size() == 2 && "reinterpretCast should have two subs"); auto &fromTL = gen.getTypeLowering(substitutions[0].getReplacement()); auto &toTL = gen.getTypeLowering(substitutions[1].getReplacement()); // If casting between address-only types, cast the address. if (!fromTL.isLoadable() || !toTL.isLoadable()) { SILValue fromAddr; // If the from value is loadable, move it to a buffer. if (fromTL.isLoadable()) { fromAddr = gen.emitTemporaryAllocation(loc, args[0].getValue()->getType()); gen.B.createStore(loc, args[0].getValue(), fromAddr); } else { fromAddr = args[0].getValue(); } auto toAddr = gen.B.createUncheckedAddrCast(loc, fromAddr, toTL.getLoweredType().getAddressType()); // Load and retain the destination value if it's loadable. Leave the cleanup // on the original value since we don't know anything about it's type. if (toTL.isLoadable()) { SILValue val = gen.B.createLoad(loc, toAddr); return gen.emitManagedRetain(loc, val, toTL); } // Leave the cleanup on the original value. if (toTL.isTrivial()) return ManagedValue::forUnmanaged(toAddr); // Initialize the +1 result buffer without taking the incoming value. The // source and destination cleanups will be independent. auto buffer = gen.getBufferForExprResult(loc, toTL.getLoweredType(), C); gen.B.createCopyAddr(loc, toAddr, buffer, IsNotTake, IsInitialization); return gen.manageBufferForExprResult(buffer, toTL, C); } // Create the appropriate bitcast based on the source and dest types. auto &in = args[0]; SILValue out = gen.B.createUncheckedBitCast(loc, in.getValue(), toTL.getLoweredType()); // If the cast reduces to unchecked_ref_cast, then the source and dest // have identical cleanup, so just forward the cleanup as an optimization. if (isa<UncheckedRefCastInst>(out)) return ManagedValue(out, in.getCleanup()); // Otherwise leave the original cleanup and retain the cast value. return gen.emitManagedRetain(loc, out, toTL); }
/// Specialized emitter for Builtin.reinterpretCast. static ManagedValue emitBuiltinReinterpretCast(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "reinterpretCast should be given one argument"); assert(substitutions.getReplacementTypes().size() == 2 && "reinterpretCast should have two subs"); auto &fromTL = SGF.getTypeLowering(substitutions.getReplacementTypes()[0]); auto &toTL = SGF.getTypeLowering(substitutions.getReplacementTypes()[1]); // If casting between address types, cast the address. if (fromTL.isAddress() || toTL.isAddress()) { SILValue fromAddr; // If the from value is not an address, move it to a buffer. if (!fromTL.isAddress()) { fromAddr = SGF.emitTemporaryAllocation(loc, args[0].getValue()->getType()); fromTL.emitStore(SGF.B, loc, args[0].getValue(), fromAddr, StoreOwnershipQualifier::Init); } else { fromAddr = args[0].getValue(); } auto toAddr = SGF.B.createUncheckedAddrCast(loc, fromAddr, toTL.getLoweredType().getAddressType()); // Load and retain the destination value if it's loadable. Leave the cleanup // on the original value since we don't know anything about it's type. if (!toTL.isAddress()) { return SGF.emitManagedLoadCopy(loc, toAddr, toTL); } // Leave the cleanup on the original value. if (toTL.isTrivial()) return ManagedValue::forUnmanaged(toAddr); // Initialize the +1 result buffer without taking the incoming value. The // source and destination cleanups will be independent. return SGF.B.bufferForExpr( loc, toTL.getLoweredType(), toTL, C, [&](SILValue bufferAddr) { SGF.B.createCopyAddr(loc, toAddr, bufferAddr, IsNotTake, IsInitialization); }); } // Create the appropriate bitcast based on the source and dest types. ManagedValue in = args[0]; SILType resultTy = toTL.getLoweredType(); if (resultTy.isTrivial(SGF.F)) return SGF.B.createUncheckedTrivialBitCast(loc, in, resultTy); // If we can perform a ref cast, just return. if (auto refCast = SGF.B.tryCreateUncheckedRefCast(loc, in, resultTy)) return refCast; // Otherwise leave the original cleanup and retain the cast value. SILValue out = SGF.B.createUncheckedBitwiseCast(loc, in.getValue(), resultTy); return SGF.emitManagedRetain(loc, out, toTL); }
static ManagedValue emitBuiltinValueToBridgeObject(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "ValueToBridgeObject should have one argument"); assert(subs.getReplacementTypes().size() == 1 && "ValueToBridgeObject should have one sub"); Type argTy = subs.getReplacementTypes()[0]; if (!argTy->is<BuiltinIntegerType>()) { SGF.SGM.diagnose(loc, diag::invalid_sil_builtin, "argument to builtin should be a builtin integer"); SILType objPointerType = SILType::getBridgeObjectType(SGF.F.getASTContext()); return SGF.emitUndef(objPointerType); } SILValue result = SGF.B.createValueToBridgeObject(loc, args[0].getValue()); return SGF.emitManagedRetain(loc, result); }
/// Specialized emitter for Builtin.bridgeFromRawPointer. static ManagedValue emitBuiltinBridgeFromRawPointer(SILGenFunction &SGF, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.size() == 1 && "bridge should have a single substitution"); assert(args.size() == 1 && "bridge should have a single argument"); // The substitution determines the destination type. // FIXME: Archetype destination type? auto &destLowering = SGF.getTypeLowering(substitutions[0].getReplacement()); assert(destLowering.isLoadable()); SILType destType = destLowering.getLoweredType(); // Take the raw pointer argument and cast it to the destination type. SILValue result = SGF.B.createRawPointerToRef(loc, args[0].getUnmanagedValue(), destType); // The result has ownership semantics, so retain it with a cleanup. return SGF.emitManagedRetain(loc, result, destLowering); }
static void buildFuncToBlockInvokeBody(SILGenFunction &gen, SILLocation loc, CanSILFunctionType blockTy, CanSILBlockStorageType blockStorageTy, CanSILFunctionType funcTy) { Scope scope(gen.Cleanups, CleanupLocation::get(loc)); SILBasicBlock *entry = &*gen.F.begin(); // Get the captured native function value out of the block. auto storageAddrTy = SILType::getPrimitiveAddressType(blockStorageTy); auto storage = new (gen.SGM.M) SILArgument(entry, storageAddrTy); auto capture = gen.B.createProjectBlockStorage(loc, storage); auto &funcTL = gen.getTypeLowering(funcTy); auto fn = gen.emitLoad(loc, capture, funcTL, SGFContext(), IsNotTake); // Collect the block arguments, which may have nonstandard conventions. assert(blockTy->getParameters().size() == funcTy->getParameters().size() && "block and function types don't match"); SmallVector<ManagedValue, 4> args; for (unsigned i : indices(funcTy->getParameters())) { auto &funcParam = funcTy->getParameters()[i]; auto ¶m = blockTy->getParameters()[i]; SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType()); ManagedValue mv; // If the parameter is a block, we need to copy it to ensure it lives on // the heap. The adapted closure value might outlive the block's original // scope. if (param.getSILType().isBlockPointerCompatible()) { // We still need to consume the original block if it was owned. switch (param.getConvention()) { case ParameterConvention::Direct_Owned: gen.emitManagedRValueWithCleanup(v); break; case ParameterConvention::Direct_Deallocating: case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: break; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: llvm_unreachable("indirect params to blocks not supported"); } SILValue blockCopy = gen.B.createCopyBlock(loc, v); mv = gen.emitManagedRValueWithCleanup(blockCopy); } else { switch (param.getConvention()) { case ParameterConvention::Direct_Owned: // Consume owned parameters at +1. mv = gen.emitManagedRValueWithCleanup(v); break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: // We need to independently retain the value. mv = gen.emitManagedRetain(loc, v); break; case ParameterConvention::Direct_Deallocating: // We do not need to retain the value since the value is already being // deallocated. mv = ManagedValue::forUnmanaged(v); break; case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: llvm_unreachable("indirect arguments to blocks not supported"); } } args.push_back(gen.emitBridgedToNativeValue(loc, mv, SILFunctionTypeRepresentation::CFunctionPointer, funcParam.getType())); } // Call the native function. assert(!funcTy->hasIndirectResults() && "block thunking func with indirect result not supported"); assert(funcTy->getNumDirectResults() <= 1 && "block thunking func with multiple results not supported"); ManagedValue result = gen.emitMonomorphicApply(loc, fn, args, funcTy->getSILResult().getSwiftRValueType(), ApplyOptions::None, None, None) .getAsSingleValue(gen, loc); // Bridge the result back to ObjC. result = gen.emitNativeToBridgedValue(loc, result, SILFunctionTypeRepresentation::CFunctionPointer, blockTy->getSILResult().getSwiftRValueType()); auto resultVal = result.forward(gen); scope.pop(); gen.B.createReturn(loc, resultVal); }