Skip to content

Commit 2600aa5

Browse files
Merge pull request #73040 from nate-chandler/rdar126231554
[SILCombine] Dominance check for inject_enum_addr.
2 parents 70757ff + 3070f83 commit 2600aa5

File tree

3 files changed

+402
-27
lines changed

3 files changed

+402
-27
lines changed

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ static llvm::cl::opt<DebugOnlyPassNumberOpt, true,
204204
llvm::cl::location(DebugOnlyPassNumberOptLoc),
205205
llvm::cl::ValueRequired);
206206

207+
static llvm::cl::opt<bool> SILPrintEverySubpass(
208+
"sil-print-every-subpass", llvm::cl::init(false),
209+
llvm::cl::desc("Print the function before every subpass run of passes that "
210+
"have multiple subpasses"));
211+
207212
static bool isInPrintFunctionList(SILFunction *F) {
208213
for (const std::string &printFnName : SILPrintFunction) {
209214
if (printFnName == F->getName())
@@ -478,13 +483,22 @@ bool SILPassManager::continueTransforming() {
478483
bool SILPassManager::continueWithNextSubpassRun(SILInstruction *forInst,
479484
SILFunction *function,
480485
SILTransform *trans) {
486+
unsigned subPass = numSubpassesRun++;
487+
488+
if (forInst && isFunctionSelectedForPrinting(function) &&
489+
SILPrintEverySubpass) {
490+
dumpPassInfo("*** SIL function before ", trans, function);
491+
if (forInst) {
492+
llvm::dbgs() << " *** sub-pass " << subPass << " for " << *forInst;
493+
}
494+
function->dump(getOptions().EmitVerboseSIL);
495+
}
496+
481497
if (isMandatory)
482498
return true;
483499
if (NumPassesRun != maxNumPassesToRun - 1)
484500
return true;
485501

486-
unsigned subPass = numSubpassesRun++;
487-
488502
if (subPass == maxNumSubpassesToRun - 1 && SILPrintLast) {
489503
dumpPassInfo("*** SIL function before ", trans, function);
490504
if (forInst) {

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)