Skip to content

Commit bc1aa97

Browse files
committed
IRGen: Clean up types of outlined existential buffer operations
The uniquing key for these was just the number of witness tables, but the function itself referenced the specific existential type it was instantiated with. Everything still worked because getOrCreateHelperFunction() would bitcast an existing function to the correct type, and in practice the layout of an existential type only depends on the number of witness tables. However on master-next, other changes were made that stripped off the bitcasts. This would result in assertions or LLVM verifier failures when multiple existential types were used in a single translation unit. Fixes <rdar://problem/54780404>.
1 parent 9ffb35c commit bc1aa97

File tree

7 files changed

+216
-82
lines changed

7 files changed

+216
-82
lines changed

lib/IRGen/GenExistential.cpp

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -789,12 +789,10 @@ namespace {
789789

790790

791791
static llvm::Constant *getAssignBoxedOpaqueExistentialBufferFunction(
792-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
793-
llvm::Type *existContainerPointerTy);
792+
IRGenModule &IGM, OpaqueExistentialLayout existLayout);
794793

795794
static llvm::Constant *getDestroyBoxedOpaqueExistentialBufferFunction(
796-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
797-
llvm::Type *existContainerPointerTy);
795+
IRGenModule &IGM, OpaqueExistentialLayout existLayout);
798796

799797
static llvm::Constant *
800798
getProjectBoxedOpaqueExistentialFunction(IRGenFunction &IGF,
@@ -843,13 +841,14 @@ class OpaqueExistentialTypeInfo final :
843841
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T,
844842
bool isOutlined) const override {
845843

846-
auto objPtrTy = dest.getAddress()->getType();
847-
848844
// Use copy-on-write existentials?
849845
auto fn = getAssignBoxedOpaqueExistentialBufferFunction(
850-
IGF.IGM, getLayout(), objPtrTy);
846+
IGF.IGM, getLayout());
847+
auto *type = IGF.IGM.getExistentialPtrTy(getLayout().getNumTables());
848+
auto *destAddr = IGF.Builder.CreateBitCast(dest.getAddress(), type);
849+
auto *srcAddr = IGF.Builder.CreateBitCast(src.getAddress(), type);
851850
auto call =
852-
IGF.Builder.CreateCall(fn, {dest.getAddress(), src.getAddress()});
851+
IGF.Builder.CreateCall(fn, {destAddr, srcAddr});
853852
call->setCallingConv(IGF.IGM.DefaultCC);
854853
call->setDoesNotThrow();
855854
return;
@@ -904,12 +903,15 @@ class OpaqueExistentialTypeInfo final :
904903
}
905904
}
906905

907-
void destroy(IRGenFunction &IGF, Address addr, SILType T,
906+
void destroy(IRGenFunction &IGF, Address buffer, SILType T,
908907
bool isOutlined) const override {
909908
// Use copy-on-write existentials?
910909
auto fn = getDestroyBoxedOpaqueExistentialBufferFunction(
911-
IGF.IGM, getLayout(), addr.getAddress()->getType());
912-
auto call = IGF.Builder.CreateCall(fn, {addr.getAddress()});
910+
IGF.IGM, getLayout());
911+
auto *addr = IGF.Builder.CreateBitCast(
912+
buffer.getAddress(),
913+
IGF.IGM.getExistentialPtrTy(getLayout().getNumTables()));
914+
auto call = IGF.Builder.CreateCall(fn, {addr});
913915
call->setCallingConv(IGF.IGM.DefaultCC);
914916
call->setDoesNotThrow();
915917
return;
@@ -1355,6 +1357,36 @@ createErrorExistentialTypeInfo(IRGenModule &IGM,
13551357
refcounting);
13561358
}
13571359

1360+
llvm::Type *TypeConverter::getExistentialType(unsigned numWitnessTables) {
1361+
llvm::StructType *&type = OpaqueExistentialTypes[numWitnessTables];
1362+
if (type)
1363+
return type;
1364+
1365+
SmallVector<llvm::Type*, 5> fields;
1366+
1367+
fields.push_back(IGM.getFixedBufferTy());
1368+
fields.push_back(IGM.TypeMetadataPtrTy);
1369+
1370+
for (auto i : range(numWitnessTables)) {
1371+
fields.push_back(IGM.WitnessTablePtrTy);
1372+
(void) i;
1373+
}
1374+
1375+
llvm::SmallString<40> typeName;
1376+
llvm::raw_svector_ostream(typeName)
1377+
<< "__opaque_existential_type_"
1378+
<< numWitnessTables;
1379+
1380+
type = llvm::StructType::create(IGM.getLLVMContext(), StringRef(typeName));
1381+
type->setBody(fields);
1382+
1383+
return type;
1384+
}
1385+
1386+
llvm::PointerType *IRGenModule::getExistentialPtrTy(unsigned numTables) {
1387+
return Types.getExistentialType(numTables)->getPointerTo();
1388+
}
1389+
13581390
static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
13591391
auto layout = T.getExistentialLayout();
13601392

@@ -1767,24 +1799,26 @@ void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF,
17671799
});
17681800
}
17691801

1770-
void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address addr,
1802+
void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address buffer,
17711803
SILType type, Explosion &out) {
17721804
assert(type.isExistentialType());
17731805
assert(!type.isClassExistentialType());
17741806
auto &baseTI = IGF.getTypeInfo(type).as<OpaqueExistentialTypeInfo>();
17751807

17761808
// Get the static metadata.
17771809
auto existLayout = baseTI.getLayout();
1778-
llvm::Value *metadata = existLayout.loadMetadataRef(IGF, addr);
1810+
llvm::Value *metadata = existLayout.loadMetadataRef(IGF, buffer);
17791811

17801812
// Project the buffer and apply the 'typeof' value witness.
1781-
Address buffer = existLayout.projectExistentialBuffer(IGF, addr);
17821813
llvm::Value *object;
17831814

1815+
auto *addr = IGF.Builder.CreateBitCast(
1816+
buffer.getAddress(),
1817+
IGF.IGM.getExistentialPtrTy(existLayout.getNumTables()));
17841818
auto *projectFunc = getProjectBoxedOpaqueExistentialFunction(
17851819
IGF, OpenedExistentialAccess::Immutable, existLayout);
17861820
auto *addrOfValue =
1787-
IGF.Builder.CreateCall(projectFunc, {buffer.getAddress(), metadata});
1821+
IGF.Builder.CreateCall(projectFunc, {addr, metadata});
17881822
addrOfValue->setCallingConv(IGF.IGM.DefaultCC);
17891823
addrOfValue->setDoesNotThrow();
17901824
object = addrOfValue;
@@ -1796,7 +1830,7 @@ void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address addr,
17961830
out.add(dynamicType);
17971831

17981832
// Get the witness tables.
1799-
baseTI.emitLoadOfTables(IGF, addr, out);
1833+
baseTI.emitLoadOfTables(IGF, buffer, out);
18001834
}
18011835

18021836
void irgen::emitMetatypeOfBoxedExistential(IRGenFunction &IGF, Explosion &value,
@@ -1967,10 +2001,9 @@ static Address castToOpaquePtr(IRGenFunction &IGF, Address addr) {
19672001
}
19682002

19692003
static llvm::Constant *getAllocateBoxedOpaqueExistentialBufferFunction(
1970-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
1971-
llvm::Type *existContainerPointerTy) {
2004+
IRGenModule &IGM, OpaqueExistentialLayout existLayout) {
19722005

1973-
llvm::Type *argTys[] = {existContainerPointerTy};
2006+
llvm::Type *argTys[] = {IGM.getExistentialPtrTy(existLayout.getNumTables())};
19742007

19752008
// __swift_allocate_boxed_opaque_existential__N is the well-known function for
19762009
// allocating buffers in existential containers of types with N witness
@@ -2051,20 +2084,22 @@ Address irgen::emitAllocateBoxedOpaqueExistentialBuffer(
20512084
}
20522085
/// Call a function to handle the non-fixed case.
20532086
auto *allocateFun = getAllocateBoxedOpaqueExistentialBufferFunction(
2054-
IGF.IGM, existLayout, existentialContainer.getAddress()->getType());
2087+
IGF.IGM, existLayout);
2088+
auto *existentialAddr = IGF.Builder.CreateBitCast(
2089+
existentialContainer.getAddress(),
2090+
IGF.IGM.getExistentialPtrTy(existLayout.getNumTables()));
20552091
auto *call =
2056-
IGF.Builder.CreateCall(allocateFun, {existentialContainer.getAddress()});
2092+
IGF.Builder.CreateCall(allocateFun, {existentialAddr});
20572093
call->setCallingConv(IGF.IGM.DefaultCC);
20582094
call->setDoesNotThrow();
20592095
auto addressOfValue = IGF.Builder.CreateBitCast(call, valuePointerType);
20602096
return valueTI.getAddressForPointer(addressOfValue);
20612097
}
20622098

20632099
static llvm::Constant *getDeallocateBoxedOpaqueExistentialBufferFunction(
2064-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
2065-
llvm::Type *existContainerPointerTy) {
2100+
IRGenModule &IGM, OpaqueExistentialLayout existLayout) {
20662101

2067-
llvm::Type *argTys[] = {existContainerPointerTy};
2102+
llvm::Type *argTys[] = {IGM.getExistentialPtrTy(existLayout.getNumTables())};
20682103

20692104
// __swift_deallocate_boxed_opaque_existential_N is the well-known function
20702105
// for deallocating buffers in existential containers of types with N witness
@@ -2141,9 +2176,11 @@ void irgen::emitDeallocateBoxedOpaqueExistentialBuffer(
21412176
OpaqueExistentialLayout existLayout = existentialTI.getLayout();
21422177

21432178
auto *deallocateFun = getDeallocateBoxedOpaqueExistentialBufferFunction(
2144-
IGF.IGM, existLayout, existentialContainer.getAddress()->getType());
2145-
auto *call = IGF.Builder.CreateCall(deallocateFun,
2146-
{existentialContainer.getAddress()});
2179+
IGF.IGM, existLayout);
2180+
auto *bufferAddr = IGF.Builder.CreateBitCast(
2181+
existentialContainer.getAddress(),
2182+
IGF.IGM.getExistentialPtrTy(existLayout.getNumTables()));
2183+
auto *call = IGF.Builder.CreateCall(deallocateFun, {bufferAddr});
21472184
call->setCallingConv(IGF.IGM.DefaultCC);
21482185
call->setDoesNotThrow();
21492186
return;
@@ -2155,7 +2192,7 @@ getProjectBoxedOpaqueExistentialFunction(IRGenFunction &IGF,
21552192
OpaqueExistentialLayout existLayout) {
21562193

21572194
auto &IGM = IGF.IGM;
2158-
auto *existentialBufferTy = IGM.getFixedBufferTy()->getPointerTo();
2195+
auto *existentialBufferTy = IGM.getExistentialPtrTy(existLayout.getNumTables());
21592196
llvm::Type *argTys[] = {existentialBufferTy, IGM.TypeMetadataPtrTy};
21602197

21612198
// __swift_project_boxed_opaque_existential_N is the well-known function for
@@ -2278,11 +2315,13 @@ Address irgen::emitOpaqueBoxedExistentialProjection(
22782315
wtables);
22792316
}
22802317

2281-
Address buffer = layout.projectExistentialBuffer(IGF, base);
22822318
auto *projectFunc =
22832319
getProjectBoxedOpaqueExistentialFunction(IGF, accessKind, layout);
2320+
auto *bufferAddr = IGF.Builder.CreateBitCast(
2321+
base.getAddress(),
2322+
IGF.IGM.getExistentialPtrTy(layout.getNumTables()));
22842323
auto *addrOfValue =
2285-
IGF.Builder.CreateCall(projectFunc, {buffer.getAddress(), metadata});
2324+
IGF.Builder.CreateCall(projectFunc, {bufferAddr, metadata});
22862325
addrOfValue->setCallingConv(IGF.IGM.DefaultCC);
22872326
addrOfValue->setDoesNotThrow();
22882327

@@ -2309,10 +2348,10 @@ static void initBufferWithCopyOfReference(IRGenFunction &IGF,
23092348
}
23102349

23112350
static llvm::Constant *getAssignBoxedOpaqueExistentialBufferFunction(
2312-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
2313-
llvm::Type *existContainerPointerTy) {
2351+
IRGenModule &IGM, OpaqueExistentialLayout existLayout) {
23142352

2315-
llvm::Type *argTys[] = {existContainerPointerTy, existContainerPointerTy};
2353+
llvm::Type *argTys[] = {IGM.getExistentialPtrTy(existLayout.getNumTables()),
2354+
IGM.getExistentialPtrTy(existLayout.getNumTables())};
23162355

23172356
// __swift_assign_box_in_existentials_N is the well-known function for
23182357
// assigning buffers in existential containers of types with N witness
@@ -2528,10 +2567,9 @@ static llvm::Constant *getAssignBoxedOpaqueExistentialBufferFunction(
25282567
}
25292568

25302569
static llvm::Constant *getDestroyBoxedOpaqueExistentialBufferFunction(
2531-
IRGenModule &IGM, OpaqueExistentialLayout existLayout,
2532-
llvm::Type *existContainerPointerTy) {
2570+
IRGenModule &IGM, OpaqueExistentialLayout existLayout) {
25332571

2534-
llvm::Type *argTys[] = {existContainerPointerTy};
2572+
llvm::Type *argTys[] = {IGM.getExistentialPtrTy(existLayout.getNumTables())};
25352573

25362574
llvm::SmallString<40> fnName;
25372575
llvm::raw_svector_ostream(fnName)

lib/IRGen/GenType.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ class TypeConverter {
117117
llvm::StringMap<YAMLTypeInfoNode> LegacyTypeInfos;
118118
llvm::DenseMap<NominalTypeDecl *, std::string> DeclMangledNames;
119119

120+
/// The key is the number of witness tables.
121+
llvm::DenseMap<unsigned, llvm::StructType *> OpaqueExistentialTypes;
122+
120123
const LoadableTypeInfo *createPrimitive(llvm::Type *T,
121124
Size size, Alignment align);
122125
const LoadableTypeInfo *createPrimitiveForAlignedPointer(llvm::PointerType *T,
@@ -182,6 +185,8 @@ class TypeConverter {
182185
bool isOptional);
183186
#include "swift/AST/ReferenceStorage.def"
184187

188+
llvm::Type *getExistentialType(unsigned numWitnessTables);
189+
185190
/// Enter a generic context for lowering the parameters of a generic function
186191
/// type.
187192
void pushGenericContext(CanGenericSignature signature);

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ class IRGenModule {
725725
ReferenceCounting style) const;
726726

727727
llvm::Type *getFixedBufferTy();
728+
llvm::PointerType *getExistentialPtrTy(unsigned numTables);
728729
llvm::Type *getValueWitnessTy(ValueWitness index);
729730
Signature getValueWitnessSignature(ValueWitness index);
730731

0 commit comments

Comments
 (0)