@@ -1170,6 +1170,8 @@ static llvm::Constant *emitEmptyTupleTypeMetadataRef(IRGenModule &IGM) {
1170
1170
IGM.FullExistentialTypeMetadataStructTy , fullMetadata, indices);
1171
1171
}
1172
1172
1173
+ // / Emit metadata for a tuple type containing one or more pack expansions, eg
1174
+ // / (T, repeat each U, v: V, repeat each W).
1173
1175
static MetadataResponse emitDynamicTupleTypeMetadataRef (IRGenFunction &IGF,
1174
1176
CanTupleType type,
1175
1177
DynamicMetadataRequest request) {
@@ -1179,32 +1181,105 @@ static MetadataResponse emitDynamicTupleTypeMetadataRef(IRGenFunction &IGF,
1179
1181
1180
1182
CanPackType packType = CanPackType::get (IGF.IGM .Context , types);
1181
1183
1184
+ // Begin by computing the number of elements in the tuple type.
1182
1185
auto *shapeExpression = IGF.emitPackShapeExpression (packType);
1183
- auto addr = emitTypeMetadataPack (IGF, packType, MetadataState::Abstract);
1186
+ llvm::BasicBlock *trueBB = nullptr , *falseBB = nullptr , *restBB = nullptr ;
1187
+ llvm::BasicBlock *unwrappedBB = nullptr ;
1188
+ llvm::Value *unwrapped = nullptr ;
1184
1189
1185
- auto *pointerToFirst = IGF.Builder .CreatePointerCast (
1186
- addr.getAddressPointer (), IGF.IGM .TypeMetadataPtrPtrTy );
1190
+ // A tuple type containing zero or one non-pack-expansions might contain
1191
+ // exactly one element after substitution, in which case the tuple
1192
+ // "vanishes" and gets unwrapped. This behavior is implemented in both
1193
+ // compile-time type substitution, and runtime type metadata instantiation,
1194
+ // ensuring consistent behavior.
1195
+ if (type->getNumScalarElements () <= 1 ) {
1196
+ ConditionalDominanceScope scope (IGF);
1187
1197
1188
- llvm::Value *args[] = {
1189
- request.get (IGF),
1190
- shapeExpression,
1191
- pointerToFirst,
1192
- getTupleLabelsString (IGF.IGM , type),
1193
- llvm::ConstantPointerNull::get (IGF.IGM .WitnessTablePtrTy ) // proposed
1194
- };
1198
+ // Test if the runtime length of the pack type is exactly 1.
1199
+ auto *one = llvm::ConstantInt::get (IGF.IGM .SizeTy , 1 );
1200
+ auto *isOne = IGF.Builder .CreateICmpEQ (shapeExpression, one);
1195
1201
1196
- auto call = IGF.Builder .CreateCall (
1197
- IGF.IGM .getGetTupleMetadataFunctionPointer (), args);
1198
- call->setCallingConv (IGF.IGM .SwiftCC );
1199
- call->setDoesNotThrow ();
1202
+ trueBB = IGF.createBasicBlock (" vanishing-tuple" );
1203
+ falseBB = IGF.createBasicBlock (" actual-tuple" );
1200
1204
1201
- Optional<unsigned > elementCount = 0 ;
1202
- if (auto *constant = dyn_cast<llvm::ConstantInt>(shapeExpression))
1203
- elementCount = constant->getValue ().getZExtValue ();
1205
+ IGF.Builder .CreateCondBr (isOne, trueBB, falseBB);
1204
1206
1205
- cleanupTypeMetadataPack (IGF, addr, elementCount );
1207
+ IGF. Builder . emitBlock (trueBB );
1206
1208
1207
- return MetadataResponse::handle (IGF, request, call);
1209
+ // If the length is 1, directly emit the metadata for the first pack element.
1210
+ ArrayRef<ProtocolConformanceRef> conformances;
1211
+ llvm::SmallVector<llvm::Value *, 2 > wtables;
1212
+
1213
+ auto *index = llvm::ConstantInt::get (IGF.IGM .SizeTy , 0 );
1214
+ auto *value = emitTypeMetadataPackElementRef (
1215
+ IGF, packType, conformances, index, request, wtables);
1216
+
1217
+ // FIXME: Should emitTypeMetadataPackElementRef() preserve the dynamic state?
1218
+ auto response = MetadataResponse::forBounded (
1219
+ value, request.getStaticLowerBoundOnResponseState ());
1220
+ response.ensureDynamicState (IGF);
1221
+
1222
+ unwrapped = response.combine (IGF);
1223
+ unwrappedBB = IGF.Builder .GetInsertBlock ();
1224
+
1225
+ assert (wtables.empty ());
1226
+
1227
+ restBB = IGF.createBasicBlock (" tuple-rest" );
1228
+ IGF.Builder .CreateBr (restBB);
1229
+
1230
+ IGF.Builder .emitBlock (falseBB);
1231
+ }
1232
+
1233
+ llvm::CallInst *call = nullptr ;
1234
+
1235
+ {
1236
+ ConditionalDominanceScope scope (IGF);
1237
+
1238
+ // Otherwise, we know that either statically or dynamically, we have more than
1239
+ // one element. Emit the pack.
1240
+ auto addr = emitTypeMetadataPack (IGF, packType, MetadataState::Abstract);
1241
+
1242
+ auto *pointerToFirst = IGF.Builder .CreatePointerCast (
1243
+ addr.getAddressPointer (), IGF.IGM .TypeMetadataPtrPtrTy );
1244
+
1245
+ // Call swift_getTupleMetadata().
1246
+ llvm::Value *args[] = {
1247
+ request.get (IGF),
1248
+ shapeExpression,
1249
+ pointerToFirst,
1250
+ getTupleLabelsString (IGF.IGM , type),
1251
+ llvm::ConstantPointerNull::get (IGF.IGM .WitnessTablePtrTy ) // proposed
1252
+ };
1253
+
1254
+ call = IGF.Builder .CreateCall (
1255
+ IGF.IGM .getGetTupleMetadataFunctionPointer (), args);
1256
+ call->setCallingConv (IGF.IGM .SwiftCC );
1257
+ call->setDoesNotThrow ();
1258
+
1259
+ // Clean up the pack.
1260
+ Optional<unsigned > elementCount = 0 ;
1261
+ if (auto *constant = dyn_cast<llvm::ConstantInt>(shapeExpression))
1262
+ elementCount = constant->getValue ().getZExtValue ();
1263
+
1264
+ cleanupTypeMetadataPack (IGF, addr, elementCount);
1265
+ }
1266
+
1267
+ // Control flow join with the one-element case.
1268
+ llvm::Value *result = nullptr ;
1269
+ if (unwrapped != nullptr ) {
1270
+ IGF.Builder .CreateBr (restBB);
1271
+ IGF.Builder .emitBlock (restBB);
1272
+
1273
+ auto *phi = IGF.Builder .CreatePHI (IGF.IGM .TypeMetadataResponseTy , 2 );
1274
+ phi->addIncoming (unwrapped, unwrappedBB);
1275
+ phi->addIncoming (call, call->getParent ());
1276
+
1277
+ result = phi;
1278
+ } else {
1279
+ result = call;
1280
+ }
1281
+
1282
+ return MetadataResponse::handle (IGF, request, result);
1208
1283
}
1209
1284
1210
1285
static MetadataResponse emitTupleTypeMetadataRef (IRGenFunction &IGF,
0 commit comments