Skip to content

Commit 7bf2f7d

Browse files
committed
IRGen: Start using ExistentialLayout
Replace a few usages of TypeBase::getExistentialTypeProtocols(), which I'm going to remove. NFC for now, since subclass existentials are still not fully plumbed through here.
1 parent a5a40c7 commit 7bf2f7d

File tree

3 files changed

+92
-86
lines changed

3 files changed

+92
-86
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/IR/Function.h"
2929
#include "llvm/IR/Module.h"
3030

31+
#include "swift/AST/ExistentialLayout.h"
3132
#include "swift/SIL/SILInstruction.h"
3233
#include "swift/SIL/SILModule.h"
3334
#include "swift/SIL/TypeLowering.h"
@@ -471,24 +472,32 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
471472
CheckedCastMode mode,
472473
Optional<MetatypeRepresentation> metatypeKind,
473474
Explosion &ex) {
474-
SmallVector<ProtocolDecl*, 4> allProtos;
475-
destType.getSwiftRValueType().getAnyExistentialTypeProtocols(allProtos);
475+
auto instanceType = destType.getSwiftRValueType();
476+
while (auto metatypeType = dyn_cast<ExistentialMetatypeType>(instanceType))
477+
instanceType = metatypeType.getInstanceType();
478+
479+
auto layout = instanceType.getExistentialLayout();
476480

477481
// Look up witness tables for the protocols that need them and get
478482
// references to the ObjC Protocol* values for the objc protocols.
479483
SmallVector<llvm::Value*, 4> objcProtos;
480484
SmallVector<llvm::Value*, 4> witnessTableProtos;
481485

482-
bool hasClassConstraint = false;
486+
bool hasClassConstraint = layout.requiresClass;
483487
bool hasClassConstraintByProtocol = false;
484488

485-
for (auto proto : allProtos) {
489+
assert(!layout.superclass && "Subclass existentials not supported yet");
490+
491+
for (auto protoTy : layout.getProtocols()) {
492+
auto *protoDecl = protoTy->getDecl();
493+
486494
// If the protocol introduces a class constraint, track whether we need
487495
// to check for it independent of protocol witnesses.
488-
if (proto->requiresClass()) {
489-
hasClassConstraint = true;
490-
if (proto->getKnownProtocolKind()
491-
&& *proto->getKnownProtocolKind() == KnownProtocolKind::AnyObject) {
496+
if (protoDecl->requiresClass()) {
497+
assert(hasClassConstraint);
498+
499+
if (protoDecl->getKnownProtocolKind()
500+
&& *protoDecl->getKnownProtocolKind() == KnownProtocolKind::AnyObject) {
492501
// AnyObject only requires that the type be a class.
493502
continue;
494503
}
@@ -498,15 +507,13 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
498507
hasClassConstraintByProtocol = true;
499508
}
500509

501-
if (Lowering::TypeConverter::protocolRequiresWitnessTable(proto)) {
502-
auto descriptor = emitProtocolDescriptorRef(IGF, proto);
510+
if (Lowering::TypeConverter::protocolRequiresWitnessTable(protoDecl)) {
511+
auto descriptor = emitProtocolDescriptorRef(IGF, protoDecl);
503512
witnessTableProtos.push_back(descriptor);
504513
}
505514

506-
if (!proto->isObjC())
507-
continue;
508-
509-
objcProtos.push_back(emitReferenceToObjCProtocol(IGF, proto));
515+
if (protoDecl->isObjC())
516+
objcProtos.push_back(emitReferenceToObjCProtocol(IGF, protoDecl));
510517
}
511518

512519
llvm::Type *resultType;

lib/IRGen/GenExistential.cpp

Lines changed: 56 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/Decl.h"
21+
#include "swift/AST/ExistentialLayout.h"
2122
#include "swift/AST/ProtocolConformance.h"
2223
#include "swift/AST/Types.h"
2324
#include "swift/IRGen/Linking.h"
@@ -1335,14 +1336,15 @@ class ErrorExistentialTypeInfo : public HeapTypeInfo<ErrorExistentialTypeInfo>
13351336

13361337
} // end anonymous namespace
13371338

1338-
static const TypeInfo *createErrorExistentialTypeInfo(IRGenModule &IGM,
1339-
ArrayRef<ProtocolDecl*> protocols) {
1339+
static const TypeInfo *
1340+
createErrorExistentialTypeInfo(IRGenModule &IGM,
1341+
const ExistentialLayout &layout) {
13401342
// The Error existential has a special boxed representation. It has
13411343
// space only for witnesses to the Error protocol.
1342-
assert(protocols.size() == 1
1343-
&& *protocols[0]->getKnownProtocolKind() == KnownProtocolKind::Error);
1344-
1345-
const ProtocolInfo &impl = IGM.getProtocolInfo(protocols[0]);
1344+
assert(layout.isErrorExistential());
1345+
auto *protocol = layout.getProtocols()[0]->getDecl();
1346+
auto &impl = IGM.getProtocolInfo(protocol);
1347+
13461348
auto refcounting = (!IGM.ObjCInterop
13471349
? ReferenceCounting::Native
13481350
: ReferenceCounting::Error);
@@ -1351,36 +1353,28 @@ static const TypeInfo *createErrorExistentialTypeInfo(IRGenModule &IGM,
13511353
IGM.getPointerSize(),
13521354
IGM.getHeapObjectSpareBits(),
13531355
IGM.getPointerAlignment(),
1354-
ProtocolEntry(protocols[0], impl),
1356+
ProtocolEntry(protocol, impl),
13551357
refcounting);
13561358
}
13571359

1358-
static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
1359-
ArrayRef<ProtocolDecl*> protocols) {
1360+
static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
1361+
auto layout = T.getExistentialLayout();
1362+
13601363
SmallVector<llvm::Type*, 5> fields;
13611364
SmallVector<ProtocolEntry, 4> entries;
13621365

13631366
// Check for special existentials.
1364-
if (protocols.size() == 1) {
1365-
switch (getSpecialProtocolID(protocols[0])) {
1366-
case SpecialProtocol::Error:
1367-
// Error has a special runtime representation.
1368-
return createErrorExistentialTypeInfo(IGM, protocols);
1369-
// Other existentials have standard representations.
1370-
case SpecialProtocol::AnyObject:
1371-
case SpecialProtocol::None:
1372-
break;
1373-
}
1367+
if (layout.isErrorExistential()) {
1368+
// Error has a special runtime representation.
1369+
return createErrorExistentialTypeInfo(IGM, layout);
13741370
}
13751371

1372+
// Note: Protocol composition types are not nominal, but we name them anyway.
13761373
llvm::StructType *type;
13771374
if (isa<ProtocolType>(T))
13781375
type = IGM.createNominalType(T);
1379-
else if (auto compT = dyn_cast<ProtocolCompositionType>(T))
1380-
// Protocol composition types are not nominal, but we name them anyway.
1381-
type = IGM.createNominalType(compT.getPointer());
13821376
else
1383-
llvm_unreachable("unknown existential type kind");
1377+
type = IGM.createNominalType(cast<ProtocolCompositionType>(T.getPointer()));
13841378

13851379
assert(type->isOpaque() && "creating existential type in concrete struct");
13861380

@@ -1392,25 +1386,25 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
13921386
fields.push_back(nullptr);
13931387
fields.push_back(nullptr);
13941388

1395-
bool requiresClass = false;
1389+
// The existential container is class-constrained if any of its protocol
1390+
// constraints are.
1391+
bool requiresClass = layout.requiresClass;
13961392
bool allowsTaggedPointers = true;
13971393

1398-
for (auto protocol : protocols) {
1399-
// The existential container is class-constrained if any of its protocol
1400-
// constraints are.
1401-
requiresClass |= protocol->requiresClass();
1394+
for (auto protoTy : layout.getProtocols()) {
1395+
auto *protoDecl = protoTy->getDecl();
14021396

1403-
if (protocol->getAttrs().hasAttribute<UnsafeNoObjCTaggedPointerAttr>())
1397+
if (protoDecl->getAttrs().hasAttribute<UnsafeNoObjCTaggedPointerAttr>())
14041398
allowsTaggedPointers = false;
14051399

14061400
// ObjC protocols need no layout or witness table info. All dispatch is done
14071401
// through objc_msgSend.
1408-
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
1402+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protoDecl))
14091403
continue;
14101404

14111405
// Find the protocol layout.
1412-
const ProtocolInfo &impl = IGM.getProtocolInfo(protocol);
1413-
entries.push_back(ProtocolEntry(protocol, impl));
1406+
const ProtocolInfo &impl = IGM.getProtocolInfo(protoDecl);
1407+
entries.push_back(ProtocolEntry(protoDecl, impl));
14141408

14151409
// Each protocol gets a witness table.
14161410
fields.push_back(IGM.WitnessTablePtrTy);
@@ -1423,7 +1417,8 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
14231417
// native reference counting entry points.
14241418
ReferenceCounting refcounting;
14251419

1426-
// Replace the type metadata pointer with the class instance.
1420+
// FIXME: If there is a superclass constraint we might be able to
1421+
// use native refcounting.
14271422
if (!IGM.ObjCInterop) {
14281423
refcounting = ReferenceCounting::Native;
14291424
fields[1] = IGM.RefCountedPtrTy;
@@ -1432,6 +1427,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
14321427
fields[1] = IGM.UnknownRefCountedPtrTy;
14331428
}
14341429

1430+
// Replace the type metadata pointer with the class instance.
14351431
auto classFields = llvm::makeArrayRef(fields).slice(1);
14361432
type->setBody(classFields);
14371433

@@ -1463,33 +1459,31 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
14631459
fields[1] = IGM.TypeMetadataPtrTy;
14641460
type->setBody(fields);
14651461

1466-
OpaqueExistentialLayout layout(entries.size());
1467-
Alignment align = layout.getAlignment(IGM);
1468-
Size size = layout.getSize(IGM);
1462+
OpaqueExistentialLayout opaque(entries.size());
1463+
Alignment align = opaque.getAlignment(IGM);
1464+
Size size = opaque.getSize(IGM);
14691465
return OpaqueExistentialTypeInfo::create(entries, type, size, align);
14701466
}
14711467

14721468
const TypeInfo *TypeConverter::convertProtocolType(ProtocolType *T) {
1473-
// Protocol types are nominal.
1474-
return createExistentialTypeInfo(IGM, CanType(T), T->getDecl());
1469+
return createExistentialTypeInfo(IGM, CanType(T));
14751470
}
14761471

14771472
const TypeInfo *
14781473
TypeConverter::convertProtocolCompositionType(ProtocolCompositionType *T) {
1479-
// Find the canonical protocols. There might not be any.
1480-
SmallVector<ProtocolDecl*, 4> protocols;
1481-
T->getExistentialTypeProtocols(protocols);
1482-
1483-
return createExistentialTypeInfo(IGM, CanType(T), protocols);
1474+
return createExistentialTypeInfo(IGM, CanType(T));
14841475
}
14851476

14861477
const TypeInfo *
14871478
TypeConverter::convertExistentialMetatypeType(ExistentialMetatypeType *T) {
14881479
assert(T->hasRepresentation() &&
14891480
"metatype should have been assigned a representation by SIL");
14901481

1491-
SmallVector<ProtocolDecl*, 4> protocols;
1492-
T->getAnyExistentialTypeProtocols(protocols);
1482+
auto instanceT = CanExistentialMetatypeType(T).getInstanceType();
1483+
while (isa<ExistentialMetatypeType>(instanceT))
1484+
instanceT = cast<ExistentialMetatypeType>(instanceT).getInstanceType();
1485+
1486+
auto layout = instanceT.getExistentialLayout();
14931487

14941488
SmallVector<ProtocolEntry, 4> entries;
14951489
SmallVector<llvm::Type*, 4> fields;
@@ -1502,13 +1496,15 @@ TypeConverter::convertExistentialMetatypeType(ExistentialMetatypeType *T) {
15021496
fields.push_back(baseTI.getStorageType());
15031497
spareBits.append(baseTI.getSpareBits());
15041498

1505-
for (auto protocol : protocols) {
1506-
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
1499+
for (auto protoTy : layout.getProtocols()) {
1500+
auto *protoDecl = protoTy->getDecl();
1501+
1502+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protoDecl))
15071503
continue;
15081504

15091505
// Find the protocol layout.
1510-
const ProtocolInfo &impl = IGM.getProtocolInfo(protocol);
1511-
entries.push_back(ProtocolEntry(protocol, impl));
1506+
const ProtocolInfo &impl = IGM.getProtocolInfo(protoDecl);
1507+
entries.push_back(ProtocolEntry(protoDecl, impl));
15121508

15131509
// Each protocol gets a witness table.
15141510
fields.push_back(IGM.WitnessTablePtrTy);
@@ -1640,15 +1636,17 @@ static void forEachProtocolWitnessTable(IRGenFunction &IGF,
16401636
ArrayRef<ProtocolConformanceRef> conformances,
16411637
std::function<void (unsigned, llvm::Value*)> body) {
16421638
// Collect the conformances that need witness tables.
1643-
SmallVector<ProtocolDecl*, 2> destProtocols;
1644-
destType.getExistentialTypeProtocols(destProtocols);
1639+
auto layout = destType.getExistentialLayout();
1640+
auto destProtocols = layout.getProtocols();
16451641

16461642
SmallVector<ProtocolConformanceRef, 2> witnessConformances;
16471643
assert(destProtocols.size() == conformances.size() &&
16481644
"mismatched protocol conformances");
1649-
for (unsigned i = 0, size = destProtocols.size(); i < size; ++i)
1650-
if (Lowering::TypeConverter::protocolRequiresWitnessTable(destProtocols[i]))
1645+
for (unsigned i = 0, size = destProtocols.size(); i < size; ++i) {
1646+
auto destProtocol = destProtocols[i]->getDecl();
1647+
if (Lowering::TypeConverter::protocolRequiresWitnessTable(destProtocol))
16511648
witnessConformances.push_back(conformances[i]);
1649+
}
16521650

16531651
assert(protocols.size() == witnessConformances.size() &&
16541652
"mismatched protocol conformances");
@@ -1797,20 +1795,11 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF,
17971795
// As a special case, an Error existential can be represented as a
17981796
// reference to an already existing NSError or CFError instance.
17991797
if (outType.getSwiftRValueType().isExistentialType()) {
1800-
SmallVector<ProtocolDecl*, 4> protocols;
1801-
outType.getSwiftRValueType().getExistentialTypeProtocols(protocols);
1802-
if (protocols.size() == 1) {
1803-
switch (getSpecialProtocolID(protocols[0])) {
1804-
case SpecialProtocol::Error: {
1805-
// Bitcast the incoming class reference to Error.
1806-
out.add(IGF.Builder.CreateBitCast(instance, IGF.IGM.ErrorPtrTy));
1807-
return;
1808-
}
1809-
1810-
case SpecialProtocol::AnyObject:
1811-
case SpecialProtocol::None:
1812-
break;
1813-
}
1798+
auto layout = outType.getSwiftRValueType().getExistentialLayout();
1799+
if (layout.isErrorExistential()) {
1800+
// Bitcast the incoming class reference to Error.
1801+
out.add(IGF.Builder.CreateBitCast(instance, IGF.IGM.ErrorPtrTy));
1802+
return;
18141803
}
18151804
}
18161805

lib/IRGen/IRGenMangler.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "IRGenMangler.h"
14+
#include "swift/AST/ExistentialLayout.h"
1415
#include "swift/Demangling/ManglingMacros.h"
1516

1617
using namespace swift;
@@ -76,21 +77,30 @@ std::string IRGenMangler::mangleTypeForLLVMTypeName(CanType Ty) {
7677

7778
std::string IRGenMangler::
7879
mangleProtocolForLLVMTypeName(ProtocolCompositionType *type) {
79-
SmallVector<ProtocolDecl *, 4> protocols;
80-
type->getExistentialTypeProtocols(protocols);
80+
ExistentialLayout layout = type->getExistentialLayout();
8181

82-
if (protocols.empty()) {
82+
if (type->isAny()) {
8383
Buffer << "Any";
84+
} else if (layout.isAnyObject()) {
85+
Buffer << "AnyObject";
8486
} else {
8587
// To make LLVM IR more readable we always add a 'T' prefix so that type names
8688
// don't start with a digit and don't need to be quoted.
8789
Buffer << 'T';
90+
auto protocols = layout.getProtocols();
8891
for (unsigned i = 0, e = protocols.size(); i != e; ++i) {
89-
appendProtocolName(protocols[i]);
92+
appendProtocolName(protocols[i]->getDecl());
9093
if (i == 0)
9194
appendOperator("_");
9295
}
93-
appendOperator("p");
96+
if (layout.superclass) {
97+
appendType(layout.superclass);
98+
appendOperator("Xc");
99+
} else if (layout.getLayoutConstraint()) {
100+
appendOperator("Xl");
101+
} else {
102+
appendOperator("p");
103+
}
94104
}
95105
return finalize();
96106
}

0 commit comments

Comments
 (0)