@@ -945,13 +945,73 @@ SILInstruction *SILCombiner::visitStrongRetainInst(StrongRetainInst *SRI) {
945
945
return nullptr ;
946
946
}
947
947
948
+ // / Create a value from stores to an address.
949
+ // /
950
+ // / If there are only stores to \p addr, return the stored value. Also, if there
951
+ // / are address projections, create aggregate instructions for it.
952
+ // / If builder is null, it's just a dry-run to check if it's possible.
953
+ static SILValue createValueFromAddr (SILValue addr, SILBuilder *builder,
954
+ SILLocation loc) {
955
+ SmallVector<SILValue, 4 > elems;
956
+ enum Kind {
957
+ none, store, tuple
958
+ } kind = none;
959
+
960
+ for (Operand *use : addr->getUses ()) {
961
+ SILInstruction *user = use->getUser ();
962
+ if (user->isDebugInstruction ())
963
+ continue ;
964
+
965
+ auto *st = dyn_cast<StoreInst>(user);
966
+ if (st && kind == none && st->getDest () == addr) {
967
+ elems.push_back (st->getSrc ());
968
+ kind = store;
969
+ // We cannot just return st->getSrc() here because we also have to check
970
+ // if the store destination is the only use of addr.
971
+ continue ;
972
+ }
973
+
974
+ if (auto *telem = dyn_cast<TupleElementAddrInst>(user)) {
975
+ if (kind == none) {
976
+ elems.resize (addr->getType ().castTo <TupleType>()->getNumElements ());
977
+ kind = tuple;
978
+ }
979
+ if (kind == tuple) {
980
+ if (elems[telem->getFieldNo ()])
981
+ return SILValue ();
982
+ elems[telem->getFieldNo ()] = createValueFromAddr (telem, builder, loc);
983
+ continue ;
984
+ }
985
+ }
986
+ // TODO: handle StructElementAddrInst to create structs.
987
+
988
+ return SILValue ();
989
+ }
990
+ switch (kind) {
991
+ case none:
992
+ return SILValue ();
993
+ case store:
994
+ assert (elems.size () == 1 );
995
+ return elems[0 ];
996
+ case tuple:
997
+ if (std::any_of (elems.begin (), elems.end (),
998
+ [](SILValue v){ return !(bool )v; }))
999
+ return SILValue ();
1000
+ if (builder) {
1001
+ return builder->createTuple (loc, addr->getType ().getObjectType (), elems);
1002
+ }
1003
+ // Just return anything not null for the dry-run.
1004
+ return elems[0 ];
1005
+ }
1006
+ }
1007
+
948
1008
// / Simplify the following two frontend patterns:
949
1009
// /
950
1010
// / %payload_addr = init_enum_data_addr %payload_allocation
951
1011
// / store %payload to %payload_addr
952
1012
// / inject_enum_addr %payload_allocation, $EnumType.case
953
1013
// /
954
- // / inject_enum_add %nopayload_allocation, $EnumType.case
1014
+ // / inject_enum_addr %nopayload_allocation, $EnumType.case
955
1015
// /
956
1016
// / for a concrete enum type $EnumType.case to:
957
1017
// /
@@ -1144,16 +1204,6 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
1144
1204
}
1145
1205
assert ((EnumAddrIns == IEAI) &&
1146
1206
" Found InitEnumDataAddrInst differs from IEAI" );
1147
- // Found the DataAddrInst to this enum payload. Check if it has only use.
1148
- if (!hasOneNonDebugUse (DataAddrInst))
1149
- return nullptr ;
1150
-
1151
- auto *SI = dyn_cast<StoreInst>(getSingleNonDebugUser (DataAddrInst));
1152
- auto *AI = dyn_cast<ApplyInst>(getSingleNonDebugUser (DataAddrInst));
1153
- if (!SI && !AI) {
1154
- return nullptr ;
1155
- }
1156
-
1157
1207
// Make sure the enum pattern instructions are the only ones which write to
1158
1208
// this location
1159
1209
if (!WriteSet.empty ()) {
@@ -1201,18 +1251,30 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
1201
1251
}
1202
1252
}
1203
1253
1204
- if (SI) {
1205
- assert ((SI->getDest () == DataAddrInst) &&
1206
- " Can't find StoreInst with DataAddrInst as its destination" );
1254
+ // Check if we can replace all stores to the enum data with an enum of the
1255
+ // stored value. We can also handle tuples as payloads, e.g.
1256
+ //
1257
+ // %payload_addr = init_enum_data_addr %enum_addr
1258
+ // %elem0_addr = tuple_element_addr %payload_addr, 0
1259
+ // %elem1_addr = tuple_element_addr %payload_addr, 1
1260
+ // store %payload0 to %elem0_addr
1261
+ // store %payload1 to %elem1_addr
1262
+ // inject_enum_addr %enum_addr, $EnumType.case
1263
+ //
1264
+ if (createValueFromAddr (DataAddrInst, nullptr , DataAddrInst->getLoc ())) {
1265
+ SILValue en =
1266
+ createValueFromAddr (DataAddrInst, &Builder, DataAddrInst->getLoc ());
1267
+ assert (en);
1268
+
1207
1269
// In that case, create the payload enum/store.
1208
1270
EnumInst *E = Builder.createEnum (
1209
- DataAddrInst->getLoc (), SI-> getSrc () , DataAddrInst->getElement (),
1271
+ DataAddrInst->getLoc (), en , DataAddrInst->getElement (),
1210
1272
DataAddrInst->getOperand ()->getType ().getObjectType ());
1211
1273
Builder.createStore (DataAddrInst->getLoc (), E, DataAddrInst->getOperand (),
1212
1274
StoreOwnershipQualifier::Unqualified);
1213
1275
// Cleanup.
1214
- eraseInstFromFunction (*SI );
1215
- eraseInstFromFunction (* DataAddrInst);
1276
+ eraseUsesOfInstruction (DataAddrInst );
1277
+ recursivelyDeleteTriviallyDeadInstructions ( DataAddrInst, true );
1216
1278
return eraseInstFromFunction (*IEAI);
1217
1279
}
1218
1280
@@ -1230,7 +1292,9 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
1230
1292
// %1 = enum $EnumType, $EnumType.case, %load
1231
1293
// store %1 to %nopayload_addr
1232
1294
//
1233
- assert (AI && " Must have an apply" );
1295
+ auto *AI = dyn_cast_or_null<ApplyInst>(getSingleNonDebugUser (DataAddrInst));
1296
+ if (!AI)
1297
+ return nullptr ;
1234
1298
unsigned ArgIdx = 0 ;
1235
1299
Operand *EnumInitOperand = nullptr ;
1236
1300
for (auto &Opd : AI->getArgumentOperands ()) {
0 commit comments