@@ -865,14 +865,20 @@ SILInstruction *SILCombiner::visitCondFailInst(CondFailInst *CFI) {
865
865
return nullptr ;
866
866
}
867
867
868
- // / Create a value from stores to an address.
868
+ // / Whether there exists a unique value to which \p addr is always initialized
869
+ // / at \p forInst.
869
870
// /
870
- // / If there are only stores to \p addr, return the stored value. Also, if there
871
- // / are address projections, create aggregate instructions for it.
872
- // / If builder is null, it's just a dry-run to check if it's possible.
873
- static SILValue createValueFromAddr (SILValue addr, SILBuilder *builder,
874
- SILLocation loc) {
875
- SmallVector<SILValue, 4 > elems;
871
+ // / If \p builder is passed, create the value using it. If \p addr is
872
+ // / initialized piecewise via initializations of tuple element memory, the full
873
+ // / tuple is constructed via the builder.
874
+ // /
875
+ // / A best effort.
876
+ // / TODO: Construct structs.
877
+ // / Handle stores of identical values on multiple paths.
878
+ static std::optional<std::pair<SILValue, SILInstruction *>>
879
+ createValueFromAddr (SILValue addr, SILInstruction *forInst, DominanceInfo *DI,
880
+ SILBuilder *builder, SILLocation loc) {
881
+ SmallVector<std::optional<std::pair<SILValue, SILInstruction *>>, 4 > pairs;
876
882
enum Kind {
877
883
none, store, tuple
878
884
} kind = none;
@@ -884,7 +890,7 @@ static SILValue createValueFromAddr(SILValue addr, SILBuilder *builder,
884
890
885
891
auto *st = dyn_cast<StoreInst>(user);
886
892
if (st && kind == none && st->getDest () == addr) {
887
- elems .push_back (st->getSrc ());
893
+ pairs .push_back ({{ st->getSrc (), st}} );
888
894
kind = store;
889
895
// We cannot just return st->getSrc() here because we also have to check
890
896
// if the store destination is the only use of addr.
@@ -893,35 +899,55 @@ static SILValue createValueFromAddr(SILValue addr, SILBuilder *builder,
893
899
894
900
if (auto *telem = dyn_cast<TupleElementAddrInst>(user)) {
895
901
if (kind == none) {
896
- elems .resize (addr->getType ().castTo <TupleType>()->getNumElements ());
902
+ pairs .resize (addr->getType ().castTo <TupleType>()->getNumElements ());
897
903
kind = tuple;
898
904
}
899
905
if (kind == tuple) {
900
- if (elems[telem->getFieldIndex ()])
901
- return SILValue ();
902
- elems[telem->getFieldIndex ()] = createValueFromAddr (telem, builder, loc);
906
+ if (pairs[telem->getFieldIndex ()]) {
907
+ // Already found a tuple_element_addr at this index. Assume that a
908
+ // different value is stored to addr by it.
909
+ return std::nullopt;
910
+ }
911
+ pairs[telem->getFieldIndex ()] =
912
+ createValueFromAddr (telem, forInst, DI, builder, loc);
903
913
continue ;
904
914
}
905
915
}
906
916
// TODO: handle StructElementAddrInst to create structs.
907
917
908
- return SILValue () ;
918
+ return std::nullopt ;
909
919
}
910
920
switch (kind) {
911
921
case none:
912
- return SILValue () ;
922
+ return std::nullopt ;
913
923
case store:
914
- assert (elems.size () == 1 );
915
- return elems[0 ];
924
+ assert (pairs.size () == 1 );
925
+ {
926
+ auto pair = pairs[0 ];
927
+ assert (pair.has_value ());
928
+ bool isEmpty = pair->first ->getType ().isEmpty (*addr->getFunction ());
929
+ if (isEmpty && !DI->properlyDominates (pair->second , forInst))
930
+ return std::nullopt;
931
+ return pair;
932
+ }
916
933
case tuple:
917
- if (std::any_of (elems.begin (), elems.end (),
918
- [](SILValue v){ return !(bool )v; }))
919
- return SILValue ();
934
+ if (std::any_of (pairs.begin (), pairs.end (), [&](auto pair) {
935
+ return !pair.has_value () ||
936
+ (pair->first ->getType ().isEmpty (*addr->getFunction ()) &&
937
+ !DI->properlyDominates (pair->second , forInst));
938
+ }))
939
+ return std::nullopt;
920
940
if (builder) {
921
- return builder->createTuple (loc, addr->getType ().getObjectType (), elems);
941
+ SmallVector<SILValue, 4 > elements;
942
+ for (auto pair : pairs) {
943
+ elements.push_back (pair->first );
944
+ }
945
+ auto *tuple =
946
+ builder->createTuple (loc, addr->getType ().getObjectType (), elements);
947
+ return {{tuple, tuple}};
922
948
}
923
949
// Just return anything not null for the dry-run.
924
- return elems [0 ];
950
+ return pairs [0 ];
925
951
}
926
952
llvm_unreachable (" invalid kind" );
927
953
}
@@ -1185,9 +1211,12 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
1185
1211
// store %payload1 to %elem1_addr
1186
1212
// inject_enum_addr %enum_addr, $EnumType.case
1187
1213
//
1188
- if (createValueFromAddr (DataAddrInst, nullptr , DataAddrInst->getLoc ())) {
1189
- SILValue en =
1190
- createValueFromAddr (DataAddrInst, &Builder, DataAddrInst->getLoc ());
1214
+ auto DI = DA->get (IEAI->getFunction ());
1215
+ if (createValueFromAddr (DataAddrInst, IEAI, DI, nullptr ,
1216
+ DataAddrInst->getLoc ())) {
1217
+ SILValue en = createValueFromAddr (DataAddrInst, IEAI, DI, &Builder,
1218
+ DataAddrInst->getLoc ())
1219
+ ->first ;
1191
1220
assert (en);
1192
1221
1193
1222
// In that case, create the payload enum/store.
@@ -1224,7 +1253,14 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
1224
1253
// store %1 to %nopayload_addr
1225
1254
//
1226
1255
auto *AI = dyn_cast_or_null<ApplyInst>(getSingleNonDebugUser (DataAddrInst));
1227
- if (!AI)
1256
+ bool hasEmptyAssociatedType =
1257
+ IEAI->getElement ()->hasAssociatedValues ()
1258
+ ? IEAI->getOperand ()
1259
+ ->getType ()
1260
+ .getEnumElementType (IEAI->getElement (), func)
1261
+ .isEmpty (*func)
1262
+ : false ;
1263
+ if (!AI || (hasEmptyAssociatedType && !DI->properlyDominates (AI, IEAI)))
1228
1264
return nullptr ;
1229
1265
1230
1266
unsigned ArgIdx = 0 ;
0 commit comments