Skip to content

Commit 3070f83

Browse files
committed
[SILCombine] Dominance check for inject_enum_addr.
If stores of empty values to the address don't dominate the inject_enum_addr, the inject_enum_addr can't be eliminated--it's the only indication of the case that's in the address.
1 parent 7fbf22c commit 3070f83

File tree

2 files changed

+386
-25
lines changed

2 files changed

+386
-25
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -865,14 +865,20 @@ SILInstruction *SILCombiner::visitCondFailInst(CondFailInst *CFI) {
865865
return nullptr;
866866
}
867867

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.
869870
///
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;
876882
enum Kind {
877883
none, store, tuple
878884
} kind = none;
@@ -884,7 +890,7 @@ static SILValue createValueFromAddr(SILValue addr, SILBuilder *builder,
884890

885891
auto *st = dyn_cast<StoreInst>(user);
886892
if (st && kind == none && st->getDest() == addr) {
887-
elems.push_back(st->getSrc());
893+
pairs.push_back({{st->getSrc(), st}});
888894
kind = store;
889895
// We cannot just return st->getSrc() here because we also have to check
890896
// if the store destination is the only use of addr.
@@ -893,35 +899,55 @@ static SILValue createValueFromAddr(SILValue addr, SILBuilder *builder,
893899

894900
if (auto *telem = dyn_cast<TupleElementAddrInst>(user)) {
895901
if (kind == none) {
896-
elems.resize(addr->getType().castTo<TupleType>()->getNumElements());
902+
pairs.resize(addr->getType().castTo<TupleType>()->getNumElements());
897903
kind = tuple;
898904
}
899905
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);
903913
continue;
904914
}
905915
}
906916
// TODO: handle StructElementAddrInst to create structs.
907917

908-
return SILValue();
918+
return std::nullopt;
909919
}
910920
switch (kind) {
911921
case none:
912-
return SILValue();
922+
return std::nullopt;
913923
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+
}
916933
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;
920940
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}};
922948
}
923949
// Just return anything not null for the dry-run.
924-
return elems[0];
950+
return pairs[0];
925951
}
926952
llvm_unreachable("invalid kind");
927953
}
@@ -1185,9 +1211,12 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
11851211
// store %payload1 to %elem1_addr
11861212
// inject_enum_addr %enum_addr, $EnumType.case
11871213
//
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;
11911220
assert(en);
11921221

11931222
// In that case, create the payload enum/store.
@@ -1224,7 +1253,14 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
12241253
// store %1 to %nopayload_addr
12251254
//
12261255
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)))
12281264
return nullptr;
12291265

12301266
unsigned ArgIdx = 0;

0 commit comments

Comments
 (0)