@@ -1158,6 +1158,140 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI) {
1158
1158
return propagateConcreteTypeOfInitExistential (AI, PD, PropagateIntoOperand);
1159
1159
}
1160
1160
1161
+ // / A peephole optimizer that propagates concrete types of all arguments to Apply.
1162
+ SILInstruction *
1163
+ SILCombiner::propagateConcreteTypeOfInitExistentialToAllApplyArgs (FullApplySite AI) {
1164
+ // / Check if legal to perform propagation.
1165
+ if (!AI.hasSubstitutions ())
1166
+ return nullptr ;
1167
+ auto *Callee = AI.getReferencedFunction ();
1168
+ if (!Callee)
1169
+ return nullptr ;
1170
+
1171
+ auto FnTy = AI.getCallee ()->getType ().castTo <SILFunctionType>();
1172
+ if (!FnTy->isPolymorphic ())
1173
+ return nullptr ;
1174
+
1175
+ // / Find a mapping from Archetype to the Protocol declaration.
1176
+ ArrayRef<Substitution> CallerSubs = Callee->getForwardingSubstitutions ();
1177
+ llvm::DenseMap<Type, ProtocolDecl *> GenericType2ProtocolMap;
1178
+ for (auto &sub : CallerSubs) {
1179
+ auto ReplacementType = sub.getReplacement ();
1180
+ auto Conformances = sub.getConformances ();
1181
+ ArchetypeType * ArcheType;
1182
+ if (ReplacementType->hasArchetype () &&
1183
+ (ArcheType = ReplacementType->getAs <ArchetypeType>()) &&
1184
+ (Conformances.size () == 1 )) {
1185
+ auto ProtoDecl = Conformances[0 ].getRequirement ();
1186
+ GenericType2ProtocolMap[ArcheType->getInterfaceType ()] = ProtoDecl;
1187
+ }
1188
+ }
1189
+
1190
+ auto Args = Callee->begin ()->getFunctionArguments ();
1191
+ SmallVector<SILValue, 8 > NewApplyArgs;
1192
+ llvm::DenseMap<SubstitutableType *, Type> GenericType2ConcreteTypeMap;
1193
+ llvm::DenseMap<Type, Optional<ProtocolConformanceRef>> ConcreteType2ConformanceMap;
1194
+ bool MatchPattern = false ;
1195
+
1196
+ // / We are looking for the following pattern (can be extended in the future).
1197
+ // / %0 = alloc_ref $SomeClass
1198
+ // / %1 = init_existential_ref %0 : $SomeClass : $SomeClass, $SomeProtocol
1199
+ // / %2 = function_ref @something_to_devirtualize : $@convention(thin) (@guaranteed SomeProtocol) -> Int
1200
+ // / %3 = apply %2(%1) : $@convention(thin) (@guaranteed SomeProtocol) -> Int
1201
+ for (unsigned i = 0 , e = Args.size (); i != e; ++i) {
1202
+ auto ArgType = Args[i]->getType ();
1203
+ auto ArgASTType = ArgType.getSwiftRValueType ();
1204
+ auto OrigApplyArg = AI.getArgument (i);
1205
+ ArchetypeType *ArcheType;
1206
+ OpenExistentialRefInst *Open;
1207
+ InitExistentialRefInst *IE;
1208
+ // / Check all conditions for pattern matching.
1209
+ if (ArgASTType->hasArchetype () && (ArcheType = ArgASTType->getAs <ArchetypeType>()) &&
1210
+ (ArcheType->getInterfaceType ()->is <GenericTypeParamType>()) &&
1211
+ GenericType2ProtocolMap[ArcheType->getInterfaceType ()] &&
1212
+ (Open = dyn_cast<OpenExistentialRefInst>(OrigApplyArg)) &&
1213
+ (IE = dyn_cast<InitExistentialRefInst>(Open->getOperand ()))
1214
+ ) {
1215
+ auto Protocol = GenericType2ProtocolMap[ArcheType->getInterfaceType ()];
1216
+ auto Conformances = IE->getConformances ();
1217
+ auto ConcreteType = IE->getFormalConcreteType ();
1218
+ auto NewApplyArg = IE->getOperand ();
1219
+ auto ExistentialType = IE->getType ().getSwiftRValueType ();
1220
+ auto OpenedArchetype = Open->getType ().castTo <ArchetypeType>();;
1221
+ auto ExistentialSig = AI.getModule ().getASTContext ()
1222
+ .getExistentialSignature (ExistentialType,
1223
+ AI.getModule ().getSwiftModule ());
1224
+
1225
+ Substitution ConcreteSub (ConcreteType, Conformances);
1226
+ auto SubMap = ExistentialSig->getSubstitutionMap ({&ConcreteSub, 1 });
1227
+ auto Conformance = SubMap.lookupConformance (
1228
+ CanType (ExistentialSig->getGenericParams ()[0 ]), Protocol);
1229
+ // / Store the concrete type and the conformance.
1230
+ GenericType2ConcreteTypeMap[OpenedArchetype] = ConcreteType;
1231
+ ConcreteType2ConformanceMap[ConcreteType] = Conformance;
1232
+ NewApplyArgs.push_back (NewApplyArg);
1233
+ MatchPattern = true ;
1234
+ } else {
1235
+ NewApplyArgs.push_back (OrigApplyArg);
1236
+ }
1237
+ }
1238
+ // / Bail if we did not find a pattern.
1239
+ if (!MatchPattern) {
1240
+ return nullptr ;
1241
+ }
1242
+
1243
+ // / Create the substition map for Apply. Boilerplate code.
1244
+ SmallVector<Substitution, 8 > Substitutions;
1245
+ SILType NewSubstCalleeType;
1246
+ auto FnSubsMap =
1247
+ FnTy->getGenericSignature ()->getSubstitutionMap (AI.getSubstitutions ());
1248
+ auto FinalSubsMap = FnSubsMap.subst (
1249
+ [&](SubstitutableType *type) -> Type {
1250
+ if (GenericType2ConcreteTypeMap[type])
1251
+ return GenericType2ConcreteTypeMap[type];
1252
+ return type;
1253
+ },
1254
+ [&](CanType origTy, Type substTy,
1255
+ ProtocolType *proto) -> Optional<ProtocolConformanceRef> {
1256
+ if (ConcreteType2ConformanceMap[substTy]) {
1257
+ auto Conformance = ConcreteType2ConformanceMap[substTy];
1258
+ assert (proto->getDecl () == Conformance->getRequirement ());
1259
+ return Conformance;
1260
+ }
1261
+ return ProtocolConformanceRef (proto->getDecl ());
1262
+ });
1263
+ FnTy->getGenericSignature ()->getSubstitutions (FinalSubsMap, Substitutions);
1264
+ CanSILFunctionType SFT = FnTy->substGenericArgs (
1265
+ AI.getModule (),
1266
+ Substitutions);
1267
+ NewSubstCalleeType = SILType::getPrimitiveObjectType (SFT);
1268
+
1269
+ // / Create a new ApplySite
1270
+ FullApplySite NewAI;
1271
+
1272
+ // / Setup the builder.
1273
+ Builder.setCurrentDebugScope (AI.getDebugScope ());
1274
+ Builder.addOpenedArchetypeOperands (AI.getInstruction ());
1275
+
1276
+ // / Create the new Apply Instruction with concrete types
1277
+ if (auto *TAI = dyn_cast<TryApplyInst>(AI))
1278
+ NewAI = Builder.createTryApply (AI.getLoc (), AI.getCallee (), Substitutions,
1279
+ NewApplyArgs, TAI->getNormalBB (), TAI->getErrorBB ());
1280
+ else
1281
+ NewAI = Builder.createApply (AI.getLoc (), AI.getCallee (), Substitutions,
1282
+ NewApplyArgs, cast<ApplyInst>(AI)->isNonThrowing ());
1283
+
1284
+ // / Rewrite the uses of Apply based on the new one.
1285
+ if (auto apply = dyn_cast<ApplyInst>(NewAI))
1286
+ replaceInstUsesWith (*cast<ApplyInst>(AI.getInstruction ()), apply);
1287
+
1288
+ // / Delete the Apply Site.
1289
+ eraseInstFromFunction (*AI.getInstruction ());
1290
+
1291
+ return NewAI.getInstruction ();
1292
+ }
1293
+
1294
+
1161
1295
// / \brief Check that all users of the apply are retain/release ignoring one
1162
1296
// / user.
1163
1297
static bool
@@ -1387,6 +1521,8 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
1387
1521
if (isa<FunctionRefInst>(AI->getCallee ())) {
1388
1522
if (propagateConcreteTypeOfInitExistential (AI)) {
1389
1523
return nullptr ;
1524
+ } else if (propagateConcreteTypeOfInitExistentialToAllApplyArgs (AI)) {
1525
+ return nullptr ;
1390
1526
}
1391
1527
}
1392
1528
0 commit comments