Skip to content

Commit d06fe1c

Browse files
Merge pull request #66905 from nate-chandler/cherrypick/release/5.9/rdar111221183
5.9: [MoveOnlyAddressChecker] Fixed two use-before-def handlings.
2 parents a32d2e0 + 9c75821 commit d06fe1c

File tree

9 files changed

+469
-87
lines changed

9 files changed

+469
-87
lines changed

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -571,19 +571,22 @@ class FieldSensitivePrunedLiveBlocks {
571571
}
572572

573573
/// Update this liveness result for a single use.
574-
IsLive updateForUse(SILInstruction *user, unsigned bitNo) {
574+
IsLive updateForUse(SILInstruction *user, unsigned bitNo,
575+
bool isUserBeforeDef) {
575576
assert(isInitialized());
576577
auto *block = user->getParent();
577-
auto liveness = getBlockLiveness(block, bitNo);
578-
if (liveness != Dead)
579-
return liveness;
578+
if (!isUserBeforeDef) {
579+
auto liveness = getBlockLiveness(block, bitNo);
580+
if (liveness != Dead)
581+
return liveness;
582+
}
580583
computeScalarUseBlockLiveness(block, bitNo);
581584
return getBlockLiveness(block, bitNo);
582585
}
583586

584587
/// Update this range of liveness results for a single use.
585588
void updateForUse(SILInstruction *user, unsigned startBitNo,
586-
unsigned endBitNo,
589+
unsigned endBitNo, SmallBitVector const &useBeforeDefBits,
587590
SmallVectorImpl<IsLive> &resultingLiveness);
588591

589592
IsLive getBlockLiveness(SILBasicBlock *bb, unsigned bitNo) const {
@@ -854,10 +857,12 @@ class FieldSensitivePrunedLiveness {
854857
/// Also for flexibility, \p affectedAddress must be a derived projection from
855858
/// the base that \p user is affecting.
856859
void updateForUse(SILInstruction *user, TypeTreeLeafTypeRange span,
857-
bool lifetimeEnding);
860+
bool lifetimeEnding,
861+
SmallBitVector const &useBeforeDefBits);
858862

859863
void updateForUse(SILInstruction *user, SmallBitVector const &bits,
860-
bool lifetimeEnding);
864+
bool lifetimeEnding,
865+
SmallBitVector const &useBeforeDefBits);
861866

862867
void getBlockLiveness(SILBasicBlock *bb, TypeTreeLeafTypeRange span,
863868
SmallVectorImpl<FieldSensitivePrunedLiveBlocks::IsLive>
@@ -1160,6 +1165,12 @@ class FieldSensitiveSSAPrunedLiveRange
11601165
return def.first->getParentBlock() == block && def.second->contains(bit);
11611166
}
11621167

1168+
template <typename Iterable>
1169+
void isUserBeforeDef(SILInstruction *user, Iterable const &iterable,
1170+
SmallBitVector &useBeforeDefBits) const {
1171+
assert(useBeforeDefBits.none());
1172+
}
1173+
11631174
void
11641175
findBoundariesInBlock(SILBasicBlock *block, unsigned bitNo, bool isLiveOut,
11651176
FieldSensitivePrunedLivenessBoundary &boundary) const;
@@ -1243,6 +1254,36 @@ class FieldSensitiveMultiDefPrunedLiveRange
12431254
});
12441255
}
12451256

1257+
bool isDefBlock(SILBasicBlock *block, SmallBitVector const &bits) const {
1258+
assert(isInitialized());
1259+
auto iter = defBlocks.find(block);
1260+
if (!iter)
1261+
return false;
1262+
return llvm::any_of(*iter, [&](TypeTreeLeafTypeRange storedSpan) {
1263+
return storedSpan.intersects(bits);
1264+
});
1265+
}
1266+
1267+
/// Return true if \p user occurs before the first def in the same basic
1268+
/// block. In classical liveness dataflow terms, gen/kill conditions over all
1269+
/// users in 'bb' are:
1270+
///
1271+
/// Gen(bb) |= !isDefBlock(bb) || isUserBeforeDef(bb)
1272+
/// Kill(bb) &= isDefBlock(bb) && !isUserBeforeDef(bb)
1273+
///
1274+
/// If 'bb' has no users, it is neither a Gen nor Kill. Otherwise, Gen and
1275+
/// Kill are complements.
1276+
bool isUserBeforeDef(SILInstruction *user, unsigned element) const;
1277+
template <typename Iterable>
1278+
void isUserBeforeDef(SILInstruction *user, Iterable const &iterable,
1279+
SmallBitVector &useBeforeDefBits) const {
1280+
for (auto bit : iterable) {
1281+
if (isUserBeforeDef(user, bit)) {
1282+
useBeforeDefBits.set(bit);
1283+
}
1284+
}
1285+
}
1286+
12461287
bool isDef(SILInstruction *inst, unsigned bit) const {
12471288
assert(isInitialized());
12481289
auto iter = defs.find(cast<SILNode>(inst));

include/swift/SIL/SILBasicBlock.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,17 @@ public SwiftObjectHeader {
509509

510510
void printAsOperand(raw_ostream &OS, bool PrintType = true);
511511

512+
#ifndef NDEBUG
513+
/// Print the ID of the block, bbN.
514+
void dumpID() const;
515+
516+
/// Print the ID of the block with \p OS, bbN.
517+
void printID(llvm::raw_ostream &OS) const;
518+
519+
/// Print the ID of the block with \p Ctx, bbN.
520+
void printID(SILPrintContext &Ctx) const;
521+
#endif
522+
512523
/// getSublistAccess() - returns pointer to member of instruction list
513524
static InstListType SILBasicBlock::*getSublistAccess() {
514525
return &SILBasicBlock::InstList;

lib/SIL/IR/SILPrinter.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,12 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
832832
*this << ')';
833833
}
834834

835+
#ifndef NDEBUG
836+
void printID(const SILBasicBlock *BB) {
837+
*this << Ctx.getID(BB) << "\n";
838+
}
839+
#endif
840+
835841
void print(const SILBasicBlock *BB) {
836842
// Output uses for BB arguments. These are put into place as comments before
837843
// the block header.
@@ -3070,6 +3076,21 @@ void SILBasicBlock::print(SILPrintContext &Ctx) const {
30703076
SILPrinter(Ctx).print(this);
30713077
}
30723078

3079+
#ifndef NDEBUG
3080+
void SILBasicBlock::dumpID() const {
3081+
printID(llvm::errs());
3082+
}
3083+
3084+
void SILBasicBlock::printID(llvm::raw_ostream &OS) const {
3085+
SILPrintContext Ctx(OS);
3086+
printID(Ctx);
3087+
}
3088+
3089+
void SILBasicBlock::printID(SILPrintContext &Ctx) const {
3090+
SILPrinter(Ctx).printID(this);
3091+
}
3092+
#endif
3093+
30733094
/// Pretty-print the SILFunction to errs.
30743095
void SILFunction::dump(bool Verbose) const {
30753096
SILPrintContext Ctx(llvm::errs(), Verbose);

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 47 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ void FieldSensitivePrunedLiveBlocks::computeScalarUseBlockLiveness(
523523
/// Terminators are not live out of the block.
524524
void FieldSensitivePrunedLiveBlocks::updateForUse(
525525
SILInstruction *user, unsigned startBitNo, unsigned endBitNo,
526+
SmallBitVector const &useBeforeDefBits,
526527
SmallVectorImpl<IsLive> &resultingLivenessInfo) {
527528
assert(isInitialized());
528529
resultingLivenessInfo.clear();
@@ -535,10 +536,15 @@ void FieldSensitivePrunedLiveBlocks::updateForUse(
535536

536537
for (unsigned index : indices(resultingLivenessInfo)) {
537538
unsigned specificBitNo = startBitNo + index;
539+
auto isUseBeforeDef = useBeforeDefBits.test(specificBitNo);
538540
switch (resultingLivenessInfo[index]) {
539541
case LiveOut:
540542
case LiveWithin:
541-
continue;
543+
if (!isUseBeforeDef) {
544+
continue;
545+
} else {
546+
LLVM_FALLTHROUGH;
547+
}
542548
case Dead: {
543549
// This use block has not yet been marked live. Mark it and its
544550
// predecessor blocks live.
@@ -617,21 +623,21 @@ void FieldSensitivePrunedLivenessBoundary::dump() const {
617623
// MARK: FieldSensitiveLiveness
618624
//===----------------------------------------------------------------------===//
619625

620-
void FieldSensitivePrunedLiveness::updateForUse(SILInstruction *user,
621-
TypeTreeLeafTypeRange range,
622-
bool lifetimeEnding) {
626+
void FieldSensitivePrunedLiveness::updateForUse(
627+
SILInstruction *user, TypeTreeLeafTypeRange range, bool lifetimeEnding,
628+
SmallBitVector const &useBeforeDefBits) {
623629
SmallVector<FieldSensitivePrunedLiveBlocks::IsLive, 8> resultingLiveness;
624630
liveBlocks.updateForUse(user, range.startEltOffset, range.endEltOffset,
625-
resultingLiveness);
631+
useBeforeDefBits, resultingLiveness);
626632

627633
addInterestingUser(user, range, lifetimeEnding);
628634
}
629635

630-
void FieldSensitivePrunedLiveness::updateForUse(SILInstruction *user,
631-
SmallBitVector const &bits,
632-
bool lifetimeEnding) {
636+
void FieldSensitivePrunedLiveness::updateForUse(
637+
SILInstruction *user, SmallBitVector const &bits, bool lifetimeEnding,
638+
SmallBitVector const &useBeforeDefBits) {
633639
for (auto bit : bits.set_bits()) {
634-
liveBlocks.updateForUse(user, bit);
640+
liveBlocks.updateForUse(user, bit, useBeforeDefBits.test(bit));
635641
}
636642

637643
addInterestingUser(user, bits, lifetimeEnding);
@@ -816,74 +822,46 @@ void FieldSensitivePrunedLiveRange<LivenessWithDefs>::computeBoundary(
816822
}
817823
}
818824

825+
bool FieldSensitiveMultiDefPrunedLiveRange::isUserBeforeDef(
826+
SILInstruction *user, unsigned element) const {
827+
auto *block = user->getParent();
828+
if (!isDefBlock(block, element))
829+
return false;
830+
831+
if (llvm::any_of(block->getArguments(), [this, element](SILArgument *arg) {
832+
return isDef(arg, element);
833+
})) {
834+
return false;
835+
}
836+
837+
auto *current = user;
838+
while (true) {
839+
// If user is also a def, then the use is considered before the def.
840+
current = current->getPreviousInstruction();
841+
if (!current)
842+
return true;
843+
844+
if (isDef(current, element))
845+
return false;
846+
}
847+
}
848+
819849
template <typename LivenessWithDefs>
820850
void FieldSensitivePrunedLiveRange<LivenessWithDefs>::updateForUse(
821851
SILInstruction *user, TypeTreeLeafTypeRange range, bool lifetimeEnding) {
822-
PRUNED_LIVENESS_LOG(
823-
llvm::dbgs()
824-
<< "Begin FieldSensitivePrunedLiveRange<LivenessWithDefs>::updateForUse "
825-
"for: "
826-
<< *user);
827-
PRUNED_LIVENESS_LOG(
828-
llvm::dbgs() << "Looking for def instruction earlier in the block!\n");
829-
830-
auto *parentBlock = user->getParent();
831-
for (auto ii = std::next(user->getReverseIterator()),
832-
ie = parentBlock->rend();
833-
ii != ie; ++ii) {
834-
// If we find the def, just mark this instruction as being an interesting
835-
// instruction.
836-
if (asImpl().isDef(&*ii, range)) {
837-
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found def: " << *ii);
838-
PRUNED_LIVENESS_LOG(llvm::dbgs()
839-
<< " Marking inst as interesting user and returning!\n");
840-
addInterestingUser(user, range, lifetimeEnding);
841-
return;
842-
}
843-
}
844-
845-
// Otherwise, just delegate to our parent class's update for use. This will
846-
// update liveness for our predecessor blocks and add this instruction as an
847-
// interesting user.
848-
PRUNED_LIVENESS_LOG(llvm::dbgs() << "No defs found! Delegating to "
849-
"FieldSensitivePrunedLiveness::updateForUse.\n");
850-
FieldSensitivePrunedLiveness::updateForUse(user, range, lifetimeEnding);
852+
SmallBitVector useBeforeDefBits(getNumSubElements());
853+
asImpl().isUserBeforeDef(user, range.getRange(), useBeforeDefBits);
854+
FieldSensitivePrunedLiveness::updateForUse(user, range, lifetimeEnding,
855+
useBeforeDefBits);
851856
}
852857

853858
template <typename LivenessWithDefs>
854859
void FieldSensitivePrunedLiveRange<LivenessWithDefs>::updateForUse(
855860
SILInstruction *user, SmallBitVector const &bits, bool lifetimeEnding) {
856-
PRUNED_LIVENESS_LOG(
857-
llvm::dbgs()
858-
<< "Begin FieldSensitivePrunedLiveRange<LivenessWithDefs>::updateForUse "
859-
"for: "
860-
<< *user);
861-
PRUNED_LIVENESS_LOG(llvm::dbgs()
862-
<< "Looking for def instruction earlier in the block!\n");
863-
864-
auto *parentBlock = user->getParent();
865-
for (auto ii = std::next(user->getReverseIterator()),
866-
ie = parentBlock->rend();
867-
ii != ie; ++ii) {
868-
// If we find the def, just mark this instruction as being an interesting
869-
// instruction.
870-
if (asImpl().isDef(&*ii, bits)) {
871-
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found def: " << *ii);
872-
PRUNED_LIVENESS_LOG(
873-
llvm::dbgs()
874-
<< " Marking inst as interesting user and returning!\n");
875-
addInterestingUser(user, bits, lifetimeEnding);
876-
return;
877-
}
878-
}
879-
880-
// Otherwise, just delegate to our parent class's update for use. This will
881-
// update liveness for our predecessor blocks and add this instruction as an
882-
// interesting user.
883-
PRUNED_LIVENESS_LOG(llvm::dbgs()
884-
<< "No defs found! Delegating to "
885-
"FieldSensitivePrunedLiveness::updateForUse.\n");
886-
FieldSensitivePrunedLiveness::updateForUse(user, bits, lifetimeEnding);
861+
SmallBitVector useBeforeDefBits(getNumSubElements());
862+
asImpl().isUserBeforeDef(user, bits.set_bits(), useBeforeDefBits);
863+
FieldSensitivePrunedLiveness::updateForUse(user, bits, lifetimeEnding,
864+
useBeforeDefBits);
887865
}
888866

889867
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,11 +1075,11 @@ void UseState::initializeLiveness(
10751075
// Now at this point, we have defined all of our defs so we can start adding
10761076
// uses to the liveness.
10771077
for (auto reinitInstAndValue : reinitInsts) {
1078+
recordConsumingBlock(reinitInstAndValue.first->getParent(),
1079+
reinitInstAndValue.second);
10781080
if (!isReinitToInitConvertibleInst(reinitInstAndValue.first)) {
10791081
liveness.updateForUse(reinitInstAndValue.first, reinitInstAndValue.second,
10801082
false /*lifetime ending*/);
1081-
recordConsumingBlock(reinitInstAndValue.first->getParent(),
1082-
reinitInstAndValue.second);
10831083
LLVM_DEBUG(llvm::dbgs() << "Added liveness for reinit: "
10841084
<< *reinitInstAndValue.first;
10851085
liveness.print(llvm::dbgs()));
@@ -1419,6 +1419,8 @@ class ExtendUnconsumedLiveness {
14191419

14201420
private:
14211421
bool hasDefAfter(SILInstruction *inst, unsigned element);
1422+
bool isLiveAtBegin(SILBasicBlock *block, unsigned element, bool isLiveAtEnd,
1423+
DestroysCollection const &destroys);
14221424

14231425
bool
14241426
shouldAddDestroyToLiveness(SILInstruction *destroy, unsigned element,
@@ -2979,7 +2981,14 @@ void ExtendUnconsumedLiveness::runOnField(
29792981
// as the other consuming uses).
29802982
BasicBlockWorklist worklist(currentDef->getFunction());
29812983
for (auto *consumingBlock : consumingBlocks) {
2982-
worklist.push(consumingBlock);
2984+
if (!originalLiveBlocks.insert(consumingBlock)
2985+
// Don't walk into the predecessors of blocks which kill liveness.
2986+
&& !isLiveAtBegin(consumingBlock, element, /*isLiveAtEnd=*/true, destroys)) {
2987+
continue;
2988+
}
2989+
for (auto *predecessor : consumingBlock->getPredecessorBlocks()) {
2990+
worklist.pushIfNotVisited(predecessor);
2991+
}
29832992
}
29842993

29852994
// Walk backwards from consuming blocks.
@@ -2988,10 +2997,6 @@ void ExtendUnconsumedLiveness::runOnField(
29882997
continue;
29892998
}
29902999
for (auto *predecessor : block->getPredecessorBlocks()) {
2991-
// If the block was discovered by liveness, we already added it to the
2992-
// set.
2993-
if (originalLiveBlocks.contains(predecessor))
2994-
continue;
29953000
worklist.pushIfNotVisited(predecessor);
29963001
}
29973002
}
@@ -3108,6 +3113,37 @@ bool ExtendUnconsumedLiveness::shouldAddDestroyToLiveness(
31083113
return !consumedAtEntryBlocks.contains(block);
31093114
}
31103115

3116+
/// Compute the block's effect on liveness and apply it to \p isLiveAtEnd.
3117+
bool ExtendUnconsumedLiveness::isLiveAtBegin(SILBasicBlock *block,
3118+
unsigned element, bool isLiveAtEnd,
3119+
DestroysCollection const &destroys) {
3120+
enum class Effect {
3121+
None, // 0
3122+
Kill, // 1
3123+
Gen, // 2
3124+
};
3125+
auto effect = Effect::None;
3126+
for (auto &instruction : llvm::reverse(*block)) {
3127+
// An instruction can be both a destroy and a def. If it is, its
3128+
// behavior is first to destroy and then to init. So when walking
3129+
// backwards, its last action is to destroy, so its effect is that of any
3130+
// destroy.
3131+
if (destroys.find(&instruction) != destroys.end()) {
3132+
effect = Effect::Gen;
3133+
} else if (liveness.isDef(&instruction, element)) {
3134+
effect = Effect::Kill;
3135+
}
3136+
}
3137+
switch (effect) {
3138+
case Effect::None:
3139+
return isLiveAtEnd;
3140+
case Effect::Kill:
3141+
return false;
3142+
case Effect::Gen:
3143+
return true;
3144+
}
3145+
}
3146+
31113147
bool ExtendUnconsumedLiveness::hasDefAfter(SILInstruction *start,
31123148
unsigned element) {
31133149
// NOTE: Start iteration at \p start, not its sequel, because

0 commit comments

Comments
 (0)