mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
511 lines
21 KiB
C++
511 lines
21 KiB
C++
//===--- GenBorrow.cpp - LLVM type lowering of borrow types ---------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2026 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements TypeInfo subclasses for `Builtin.Borrow`.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FixedTypeInfo.h"
|
|
#include "GenBorrow.h"
|
|
#include "GenType.h"
|
|
#include "IRGen.h"
|
|
#include "IRGenModule.h"
|
|
#include "LoadableTypeInfo.h"
|
|
#include "NativeConventionSchema.h"
|
|
#include "NonFixedTypeInfo.h"
|
|
#include "ScalarTypeInfo.h"
|
|
#include "swift/AST/ResilienceExpansion.h"
|
|
#include "swift/AST/TypeExpansionContext.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
enum class BorrowTypeInfoSubclassKind : unsigned {
|
|
BorrowByPointer,
|
|
BorrowInline,
|
|
BorrowNonFixed,
|
|
};
|
|
|
|
// Type info for `Builtin.Borrow`s that are represented as a pointer.
|
|
class BorrowByPointerTypeInfo final
|
|
: public PODSingleScalarTypeInfo<BorrowByPointerTypeInfo, LoadableTypeInfo>
|
|
{
|
|
public:
|
|
BorrowByPointerTypeInfo(IRGenModule &IGM)
|
|
: PODSingleScalarTypeInfo(IGM.PtrTy, IGM.getPointerSize(),
|
|
IGM.TargetInfo.PointerSpareBits,
|
|
IGM.getPointerAlignment())
|
|
{
|
|
setSubclassKind((unsigned)BorrowTypeInfoSubclassKind::BorrowByPointer);
|
|
}
|
|
|
|
static bool classof(const BorrowByPointerTypeInfo *) { return true; }
|
|
// NB: this classof implementation assumes that it is already known that
|
|
// the `TypeInfo` being cast is converted from a `Builtin.Borrow`. Other
|
|
// kinds of type may reuse the same subclass kind with other meanings.
|
|
static bool classof(const TypeInfo *t) {
|
|
return t->getSubclassKind()
|
|
== (unsigned)BorrowTypeInfoSubclassKind::BorrowByPointer;
|
|
}
|
|
};
|
|
|
|
// Type info for `Builtin.Borrow`s that are represented with an inline
|
|
// bitwise copy of the borrowed value.
|
|
class BorrowInlineTypeInfo final
|
|
: public ScalarTypeInfo<BorrowInlineTypeInfo, LoadableTypeInfo>
|
|
{
|
|
const LoadableTypeInfo &ReferentTI;
|
|
public:
|
|
BorrowInlineTypeInfo(IRGenModule &IGM,
|
|
const LoadableTypeInfo &referentTI)
|
|
: ScalarTypeInfo(referentTI.getStorageType(),
|
|
referentTI.getFixedSize(),
|
|
referentTI.getSpareBits(),
|
|
referentTI.getFixedAlignment(),
|
|
// Borrow is trivially destroyed and copyable even if
|
|
// the referent is not.
|
|
IsTriviallyDestroyable,
|
|
IsCopyable,
|
|
IsFixedSize,
|
|
IsABIAccessible),
|
|
ReferentTI(referentTI)
|
|
{
|
|
setSubclassKind((unsigned)BorrowTypeInfoSubclassKind::BorrowInline);
|
|
}
|
|
|
|
unsigned getExplosionSize() const override {
|
|
return ReferentTI.getExplosionSize();
|
|
}
|
|
|
|
// Copying the borrow is done by bitwise copying the referent's
|
|
// representation.
|
|
void loadAsCopy(IRGenFunction &IGF, Address addr, Explosion &explosion)
|
|
const override {
|
|
loadAsTake(IGF, addr, explosion);
|
|
}
|
|
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &explosion)
|
|
const override {
|
|
ReferentTI.loadAsTake(IGF, addr, explosion);
|
|
}
|
|
|
|
void assign(IRGenFunction &IGF, Explosion &explosion, Address addr,
|
|
bool isOutlined, SILType T) const override {
|
|
initialize(IGF, explosion, addr, isOutlined);
|
|
}
|
|
void initialize(IRGenFunction &IGF, Explosion &explosion, Address addr,
|
|
bool isOutlined) const override {
|
|
ReferentTI.initialize(IGF, explosion, addr, isOutlined);
|
|
}
|
|
|
|
void reexplode(Explosion &src, Explosion &dest) const override {
|
|
ReferentTI.reexplode(src, dest);
|
|
}
|
|
void copy(IRGenFunction &IGF, Explosion &src, Explosion &dest,
|
|
Atomicity atomicity) const override {
|
|
reexplode(src, dest);
|
|
}
|
|
void consume(IRGenFunction &IGF, Explosion &explosion,
|
|
Atomicity atomicity, SILType T) const override {
|
|
Explosion discard;
|
|
reexplode(explosion, discard);
|
|
(void)discard.claimAll();
|
|
}
|
|
|
|
void fixLifetime(IRGenFunction &IGF, Explosion &explosion) const override {
|
|
Explosion discard;
|
|
reexplode(explosion, discard);
|
|
(void)discard.claimAll();
|
|
}
|
|
|
|
void destroy(IRGenFunction &IGF, Address address, SILType T,
|
|
bool isOutlined) const override {
|
|
/*nop*/
|
|
}
|
|
|
|
void getSchema(ExplosionSchema &schema) const override {
|
|
ReferentTI.getSchema(schema);
|
|
}
|
|
|
|
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
|
Size offset) const override {
|
|
ReferentTI.addToAggLowering(IGM, lowering, offset);
|
|
}
|
|
|
|
void packIntoEnumPayload(IRGenModule &IGM,
|
|
IRBuilder &builder,
|
|
EnumPayload &payload,
|
|
Explosion &source,
|
|
unsigned offset) const override {
|
|
ReferentTI.packIntoEnumPayload(IGM, builder, payload, source, offset);
|
|
}
|
|
|
|
void unpackFromEnumPayload(IRGenFunction &IGF,
|
|
const EnumPayload &payload,
|
|
Explosion &target,
|
|
unsigned offset) const override {
|
|
ReferentTI.unpackFromEnumPayload(IGF, payload, target, offset);
|
|
}
|
|
|
|
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM, SILType T,
|
|
bool useStructLayouts) const override {
|
|
return ReferentTI.buildTypeLayoutEntry(IGM, T, useStructLayouts);
|
|
}
|
|
|
|
static bool classof(const BorrowByPointerTypeInfo *) { return true; }
|
|
// NB: this classof implementation assumes that it is already known that
|
|
// the `TypeInfo` being cast is converted from a `Builtin.Borrow`. Other
|
|
// kinds of type may reuse the same subclass kind with other meanings.
|
|
static bool classof(const TypeInfo *t) {
|
|
return t->getSubclassKind()
|
|
== (unsigned)BorrowTypeInfoSubclassKind::BorrowInline;
|
|
}
|
|
};
|
|
|
|
class BorrowNonFixedTypeInfo final
|
|
: public WitnessSizedTypeInfo<BorrowNonFixedTypeInfo>
|
|
{
|
|
public:
|
|
BorrowNonFixedTypeInfo(IRGenModule &IGM)
|
|
: WitnessSizedTypeInfo(IGM.OpaqueTy,
|
|
Alignment(1),
|
|
IsTriviallyDestroyable,
|
|
IsBitwiseTakableAndBorrowable,
|
|
IsCopyable,
|
|
IsABIAccessible)
|
|
{
|
|
setSubclassKind((unsigned)BorrowTypeInfoSubclassKind::BorrowNonFixed);
|
|
}
|
|
|
|
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM, SILType T,
|
|
bool useStructLayouts) const override {
|
|
return IGM.typeLayoutCache.getOrCreateArchetypeEntry(T.getObjectType());
|
|
}
|
|
|
|
void assignWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr,
|
|
SILType T, bool isOutlined) const override {
|
|
// 'Builtin.Borrow' is always bitwise copyable.
|
|
IGF.Builder.CreateMemCpy(destAddr, srcAddr, getSize(IGF, T));
|
|
}
|
|
|
|
void initializeWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr,
|
|
SILType T, bool isOutlined,
|
|
bool zeroizeIfSensitive) const override {
|
|
// 'Builtin.Borrow' is always bitwise copyable.
|
|
IGF.Builder.CreateMemCpy(destAddr, srcAddr, getSize(IGF, T));
|
|
}
|
|
|
|
void initializeWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr,
|
|
SILType T, bool isOutlined) const override {
|
|
// 'Builtin.Borrow' is always bitwise copyable.
|
|
IGF.Builder.CreateMemCpy(destAddr, srcAddr, getSize(IGF, T));
|
|
}
|
|
|
|
void destroy(IRGenFunction &IGF, Address address, SILType T,
|
|
bool isOutlined) const override {
|
|
// 'Builtin.Borrow' is always trivial to destroy, thus it's a nop.
|
|
}
|
|
|
|
llvm::Value *getBitwiseBorrowable(IRGenFunction &IGF, SILType T) const {
|
|
auto astBorrowTy = T.getASTType()->castTo<BuiltinBorrowType>();
|
|
auto referentTy = SILType::getPrimitiveObjectType(astBorrowTy->getReferentType());
|
|
auto &referentTI = IGF.IGM.getTypeInfo(referentTy);
|
|
// let bitwiseBorrowable = (!T.isBitwiseTakable || T.isBitwiseBorrowable)
|
|
// && !T.isAddressableForDependencies
|
|
// if bitwiseBorrowable {
|
|
// return T.getEnumTagSinglePayload(...)
|
|
// } else {
|
|
// return RawPointer.getEnumTagSinglePayload(...)
|
|
// }
|
|
|
|
auto isBitwiseTakable = referentTI.getIsBitwiseTakable(IGF, referentTy);
|
|
auto notValue = IGF.Builder.CreateNot(isBitwiseTakable);
|
|
auto isBitwiseBorrowable = referentTI.getIsBitwiseBorrowable(IGF, referentTy);
|
|
auto orValue = IGF.Builder.CreateOr(notValue, isBitwiseBorrowable);
|
|
auto cmp = IGF.Builder.CreateICmpEQ(orValue, IGF.IGM.getBool(true));
|
|
// auto isAddressableForDeps = referentTI.getIsAddressableForDependencies(IGF,
|
|
// referent);
|
|
return cmp;
|
|
}
|
|
|
|
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
|
llvm::Value *numEmptyCases,
|
|
Address enumAddr, SILType T,
|
|
bool isOutlined) const override {
|
|
auto astBorrowTy = T.getASTType()->castTo<BuiltinBorrowType>();
|
|
auto referentTy = SILType::getPrimitiveObjectType(astBorrowTy->getReferentType());
|
|
auto &referentTI = IGF.IGM.getTypeInfo(referentTy);
|
|
|
|
auto isBitwiseBorrowable = getBitwiseBorrowable(IGF, T);
|
|
auto isBitwiseBorrowableBB = IGF.createBasicBlock("is_bitwise_borrowable");
|
|
auto notBitwiseBorrowableBB = IGF.createBasicBlock("not_bitwise_borrowable");
|
|
auto doneBB = IGF.createBasicBlock("done");
|
|
|
|
IGF.Builder.CreateCondBr(isBitwiseBorrowable, isBitwiseBorrowableBB,
|
|
notBitwiseBorrowableBB);
|
|
|
|
// Is bitwise borrowable, meaning we can use the referent's TypeInfo to grab
|
|
// this value.
|
|
IGF.Builder.emitBlock(isBitwiseBorrowableBB);
|
|
|
|
auto inlineResult = referentTI.getEnumTagSinglePayload(IGF, numEmptyCases,
|
|
enumAddr,
|
|
referentTy,
|
|
isOutlined);
|
|
|
|
// Calling the referent's getEnumTagSinglePayload may have introduced new
|
|
// blocks. Get the current one that contains the result and save it for the
|
|
// phi node later.
|
|
auto isBitwiseBorrowablePhiBB = IGF.Builder.GetInsertBlock();
|
|
|
|
IGF.Builder.CreateBr(doneBB);
|
|
|
|
// Not bitwise borrowable, meaning we need to grab the value from
|
|
// RawPointer's TypeInfo.
|
|
IGF.Builder.emitBlock(notBitwiseBorrowableBB);
|
|
|
|
auto pointerTy = SILType::getPrimitiveObjectType(IGF.IGM.Context.TheRawPointerType);
|
|
auto &rawPointerTI = IGF.IGM.getRawPointerTypeInfo();
|
|
auto pointerResult = rawPointerTI.getEnumTagSinglePayload(IGF, numEmptyCases,
|
|
enumAddr,
|
|
pointerTy,
|
|
isOutlined);
|
|
|
|
// Calling the raw pointer's getEnumTagSinglePayload may have introduced new
|
|
// blocks. Get the current one that contains the result and save it for the
|
|
// phi node later.
|
|
auto notBitwiseBorrowablePhiBB = IGF.Builder.GetInsertBlock();
|
|
|
|
IGF.Builder.CreateBr(doneBB);
|
|
|
|
IGF.Builder.emitBlock(doneBB);
|
|
auto phi = IGF.Builder.CreatePHI(IGF.IGM.Int32Ty, 2);
|
|
phi->addIncoming(inlineResult, isBitwiseBorrowablePhiBB);
|
|
phi->addIncoming(pointerResult, notBitwiseBorrowablePhiBB);
|
|
|
|
return phi;
|
|
}
|
|
|
|
void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
|
|
llvm::Value *numEmptyCases, Address enumAddr,
|
|
SILType T, bool isOutlined) const override {
|
|
auto astBorrowTy = T.getASTType()->castTo<BuiltinBorrowType>();
|
|
auto referentTy = SILType::getPrimitiveObjectType(astBorrowTy->getReferentType());
|
|
auto &referentTI = IGF.IGM.getTypeInfo(referentTy);
|
|
|
|
auto isBitwiseBorrowable = getBitwiseBorrowable(IGF, T);
|
|
auto isBitwiseBorrowableBB = IGF.createBasicBlock("is_bitwise_borrowable");
|
|
auto notBitwiseBorrowableBB = IGF.createBasicBlock("not_bitwise_borrowable");
|
|
|
|
IGF.Builder.CreateCondBr(isBitwiseBorrowable, isBitwiseBorrowableBB,
|
|
notBitwiseBorrowableBB);
|
|
|
|
// Is bitwise borrowable, meaning we can use the referent's TypeInfo to
|
|
// store the tag.
|
|
IGF.Builder.emitBlock(isBitwiseBorrowableBB);
|
|
|
|
referentTI.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases, enumAddr,
|
|
referentTy, isOutlined);
|
|
|
|
IGF.Builder.CreateRetVoid();
|
|
|
|
// Not bitwise borrowable, meaning we need to use RawPointer's TypeInfo to
|
|
// store the tag.
|
|
IGF.Builder.emitBlock(notBitwiseBorrowableBB);
|
|
|
|
auto pointerTy = SILType::getPrimitiveObjectType(IGF.IGM.Context.TheRawPointerType);
|
|
auto &rawPointerTI = IGF.IGM.getRawPointerTypeInfo();
|
|
rawPointerTI.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases, enumAddr,
|
|
pointerTy, isOutlined);
|
|
return;
|
|
}
|
|
};
|
|
|
|
const TypeInfo *
|
|
TypeConverter::convertBuiltinBorrowType(BuiltinBorrowType *T) {
|
|
// NB: Builtin.Borrow is reabstracted through, so we lower the referent as a
|
|
// SIL type.
|
|
auto referentTy = SILType::getPrimitiveObjectType(T->getReferentType());
|
|
auto &referentTI = IGM.getTypeInfo(referentTy);
|
|
|
|
// If the referent doesn't have fixed layout here, then the borrow layout
|
|
// is also dependent.
|
|
auto *fixedReferent = dyn_cast<FixedTypeInfo>(&referentTI);
|
|
if (!fixedReferent) {
|
|
return new BorrowNonFixedTypeInfo(IGM);
|
|
}
|
|
|
|
// TODO: If the referent type's layout is dependent on a type defined in a
|
|
// library-evolution-enabled module whose interface has been compiled with a
|
|
// toolchain older than Xcode 26, then its runtime metadata won't have
|
|
// the "bitwise borrowable" or "addressable for dependencies" value witness
|
|
// flags set accurately. To ensure compatible runtime and compile-time
|
|
// layout with older and newer versions of the binary framework, we should
|
|
// also fall back to opaque non-fixed borrow layout for these types.
|
|
|
|
// If the type parameter to `Builtin.Borrow` has any of the following
|
|
// properties:
|
|
// - it is passed indirectly, or
|
|
// - it is non-bitwise-borrowable, or
|
|
// - it is addressable-for-dependencies
|
|
// then `Builtin.Borrow` uses a pointer representation, where the pointer
|
|
// references the original value's location in memory.
|
|
if (fixedReferent->nativeParameterValueSchema(IGM).requiresIndirect()
|
|
|| !fixedReferent->isBitwiseBorrowable(ResilienceExpansion::Maximal)
|
|
|| referentTy.isAddressableForDeps(IGM.getSILModule(),
|
|
TypeExpansionContext::minimal())) {
|
|
return new BorrowByPointerTypeInfo(IGM);
|
|
}
|
|
|
|
// Otherwise, the referent uses an inline representation for borrows.
|
|
auto *loadableReferent = cast<LoadableTypeInfo>(fixedReferent);
|
|
return new BorrowInlineTypeInfo(IGM, *loadableReferent);
|
|
}
|
|
|
|
void irgen::emitMakeBorrow(IRGenFunction &IGF, SILType borrowTy,
|
|
Explosion &referent,
|
|
Explosion &borrow) {
|
|
ASSERT(borrowTy.is<BuiltinBorrowType>());
|
|
|
|
// The borrow must use an inline representation.
|
|
auto *tl = cast<BorrowInlineTypeInfo>(&IGF.IGM.getTypeInfo(borrowTy));
|
|
|
|
// The borrow representation is a bitwise copy of the referent's
|
|
// representation.
|
|
tl->reexplode(referent, borrow);
|
|
}
|
|
|
|
void irgen::emitMakeBorrowFromAddress(IRGenFunction &IGF,
|
|
SILType borrowTy,
|
|
Address referent,
|
|
Explosion &explosion) {
|
|
ASSERT(borrowTy.is<BuiltinBorrowType>());
|
|
|
|
// The borrow must use a pointer representation.
|
|
ASSERT(isa<BorrowByPointerTypeInfo>(&IGF.IGM.getTypeInfo(borrowTy)));
|
|
|
|
// The borrow representation just holds the address of the referent.
|
|
explosion.add(referent.getAddress());
|
|
}
|
|
|
|
void irgen::emitInitBorrowAtAddress(IRGenFunction &IGF,
|
|
SILType borrowTy,
|
|
Address destBorrow,
|
|
Address srcReferent) {
|
|
ASSERT(borrowTy.is<BuiltinBorrowType>());
|
|
|
|
auto &tl = IGF.IGM.getTypeInfo(borrowTy);
|
|
|
|
// The address-only instruction form can handle any borrow representation.
|
|
switch ((BorrowTypeInfoSubclassKind)tl.getSubclassKind()) {
|
|
case BorrowTypeInfoSubclassKind::BorrowInline: {
|
|
// The borrow is a bitwise copy of the referent's representation.
|
|
auto *inlineTL = cast<BorrowInlineTypeInfo>(&tl);
|
|
IGF.emitMemCpy(destBorrow, srcReferent, inlineTL->getFixedSize());
|
|
return;
|
|
}
|
|
case BorrowTypeInfoSubclassKind::BorrowByPointer:
|
|
// The borrow is a pointer to the referent.
|
|
IGF.Builder.CreateStore(srcReferent.getAddress(), destBorrow);
|
|
return;
|
|
|
|
case BorrowTypeInfoSubclassKind::BorrowNonFixed:
|
|
// The borrow representation is dependent on the referent type.
|
|
// Ask the runtime 'swift_initBorrow' to handle it.
|
|
auto astBorrowTy = borrowTy.getASTType()->castTo<BuiltinBorrowType>();
|
|
auto metadata = IGF.emitTypeMetadataRef(astBorrowTy->getReferentType());
|
|
auto initBorrow = IGF.IGM.getInitBorrowFunctionPointer();
|
|
|
|
IGF.Builder.CreateCall(initBorrow, {metadata, destBorrow.getAddress(),
|
|
srcReferent.getAddress()});
|
|
|
|
return;
|
|
}
|
|
llvm_unreachable("invalid borrow representation!");
|
|
}
|
|
|
|
void irgen::emitDereferenceBorrow(IRGenFunction &IGF,
|
|
SILType borrowTy,
|
|
Explosion &borrow,
|
|
Explosion &referent) {
|
|
ASSERT(borrowTy.is<BuiltinBorrowType>());
|
|
|
|
// The borrow must use an inline representation.
|
|
auto *tl = cast<BorrowInlineTypeInfo>(&IGF.IGM.getTypeInfo(borrowTy));
|
|
|
|
// The borrow representation is a bitwise copy of the referent's
|
|
// representation.
|
|
tl->reexplode(borrow, referent);
|
|
}
|
|
|
|
Address irgen::emitDereferenceBorrowToAddress(IRGenFunction &IGF,
|
|
SILType borrowTy,
|
|
Explosion &borrow) {
|
|
auto builtinBorrowTy = borrowTy.castTo<BuiltinBorrowType>();
|
|
|
|
// The borrow must use a pointer representation.
|
|
ASSERT(isa<BorrowByPointerTypeInfo>(&IGF.IGM.getTypeInfo(borrowTy)));
|
|
|
|
auto &referentTL = IGF.IGM.getTypeInfo(
|
|
SILType::getPrimitiveObjectType(builtinBorrowTy->getReferentType()));
|
|
|
|
auto addr = borrow.claimNext();
|
|
|
|
return Address(addr, referentTL.getStorageType(),
|
|
referentTL.getBestKnownAlignment());
|
|
}
|
|
|
|
Address irgen::emitDereferenceBorrowAtAddress(IRGenFunction &IGF,
|
|
SILType borrowTy,
|
|
Address borrow) {
|
|
auto builtinBorrowTy = borrowTy.castTo<BuiltinBorrowType>();
|
|
|
|
auto &tl = IGF.IGM.getTypeInfo(borrowTy);
|
|
auto &referentTL = IGF.IGM.getTypeInfo(
|
|
SILType::getPrimitiveObjectType(builtinBorrowTy->getReferentType()));
|
|
|
|
// The address-only instruction form can handle any borrow representation.
|
|
switch ((BorrowTypeInfoSubclassKind)tl.getSubclassKind()) {
|
|
case BorrowTypeInfoSubclassKind::BorrowInline:
|
|
// The borrow is a bitwise copy of the referent's representation, so
|
|
// we can use the address of the borrow value as the address of the value
|
|
// itself.
|
|
return borrow;
|
|
|
|
case BorrowTypeInfoSubclassKind::BorrowByPointer: {
|
|
// The borrow is a pointer to the referent. Load the pointer and use it as
|
|
// the address of the value.
|
|
auto addr = IGF.Builder.CreateLoad(borrow.getAddress(),
|
|
IGF.IGM.PtrTy,
|
|
IGF.IGM.getPointerAlignment());
|
|
|
|
return Address(addr, referentTL.getStorageType(),
|
|
referentTL.getBestKnownAlignment());
|
|
}
|
|
|
|
case BorrowTypeInfoSubclassKind::BorrowNonFixed: {
|
|
// The borrow representation is dependent on the referent type.
|
|
// Ask the runtime 'swift_dereferenceBorrow' to handle it.
|
|
auto astBorrowTy = borrowTy.getASTType()->castTo<BuiltinBorrowType>();
|
|
auto metadata = IGF.emitTypeMetadataRef(astBorrowTy->getReferentType());
|
|
auto dereferenceBorrow = IGF.IGM.getDereferenceBorrowFunctionPointer();
|
|
|
|
auto addr = IGF.Builder.CreateCall(dereferenceBorrow,
|
|
{metadata, borrow.getAddress()});
|
|
|
|
return Address(addr, referentTL.getStorageType(),
|
|
referentTL.getBestKnownAlignment());
|
|
}
|
|
}
|
|
llvm_unreachable("invalid borrow representation!");
|
|
}
|