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