@@ -1170,41 +1170,112 @@ static llvm::Constant *emitEmptyTupleTypeMetadataRef(IRGenModule &IGM) {
11701170 IGM.FullExistentialTypeMetadataStructTy , fullMetadata, indices);
11711171}
11721172
1173+ // / Emit metadata for a tuple type containing one or more pack expansions, eg
1174+ // / (T, repeat each U, v: V, repeat each W).
11731175static MetadataResponse emitDynamicTupleTypeMetadataRef (IRGenFunction &IGF,
11741176 CanTupleType type,
11751177 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 ();
11811179
1180+ // Begin by computing the number of elements in the tuple type.
11821181 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 ;
11841185
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);
11871193
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);
11951197
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" );
12001200
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);
12041202
1205- cleanupTypeMetadataPack (IGF, addr, elementCount );
1203+ IGF. Builder . emitBlock (trueBB );
12061204
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);
12081279}
12091280
12101281static MetadataResponse emitTupleTypeMetadataRef (IRGenFunction &IGF,
0 commit comments