Skip to content

Commit 98d895d

Browse files
Merge pull request swiftlang#66892 from nate-chandler/rdar111221183
[MoveOnlyAddressChecker] Fixed two use-before-def handlings.
2 parents 270089f + ff7aa3c commit 98d895d

File tree

8 files changed

+208
-109
lines changed

8 files changed

+208
-109
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
@@ -516,6 +516,17 @@ public SwiftObjectHeader {
516516

517517
void printAsOperand(raw_ostream &OS, bool PrintType = true);
518518

519+
#ifndef NDEBUG
520+
/// Print the ID of the block, bbN.
521+
void dumpID() const;
522+
523+
/// Print the ID of the block with \p OS, bbN.
524+
void printID(llvm::raw_ostream &OS) const;
525+
526+
/// Print the ID of the block with \p Ctx, bbN.
527+
void printID(SILPrintContext &Ctx) const;
528+
#endif
529+
519530
/// getSublistAccess() - returns pointer to member of instruction list
520531
static InstListType SILBasicBlock::*getSublistAccess() {
521532
return &SILBasicBlock::InstList;

lib/SIL/IR/SILPrinter.cpp

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

858+
#ifndef NDEBUG
859+
void printID(const SILBasicBlock *BB) {
860+
*this << Ctx.getID(BB) << "\n";
861+
}
862+
#endif
863+
858864
void print(const SILBasicBlock *BB) {
859865
// Output uses for BB arguments. These are put into place as comments before
860866
// the block header.
@@ -3086,6 +3092,21 @@ void SILBasicBlock::print(SILPrintContext &Ctx) const {
30863092
SILPrinter(Ctx).print(this);
30873093
}
30883094

3095+
#ifndef NDEBUG
3096+
void SILBasicBlock::dumpID() const {
3097+
printID(llvm::errs());
3098+
}
3099+
3100+
void SILBasicBlock::printID(llvm::raw_ostream &OS) const {
3101+
SILPrintContext Ctx(OS);
3102+
printID(Ctx);
3103+
}
3104+
3105+
void SILBasicBlock::printID(SILPrintContext &Ctx) const {
3106+
SILPrinter(Ctx).printID(this);
3107+
}
3108+
#endif
3109+
30893110
/// Pretty-print the SILFunction to errs.
30903111
void SILFunction::dump(bool Verbose) const {
30913112
SILPrintContext Ctx(llvm::errs(), Verbose);

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 47 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ void FieldSensitivePrunedLiveBlocks::computeScalarUseBlockLiveness(
514514
/// Terminators are not live out of the block.
515515
void FieldSensitivePrunedLiveBlocks::updateForUse(
516516
SILInstruction *user, unsigned startBitNo, unsigned endBitNo,
517+
SmallBitVector const &useBeforeDefBits,
517518
SmallVectorImpl<IsLive> &resultingLivenessInfo) {
518519
assert(isInitialized());
519520
resultingLivenessInfo.clear();
@@ -526,10 +527,15 @@ void FieldSensitivePrunedLiveBlocks::updateForUse(
526527

527528
for (unsigned index : indices(resultingLivenessInfo)) {
528529
unsigned specificBitNo = startBitNo + index;
530+
auto isUseBeforeDef = useBeforeDefBits.test(specificBitNo);
529531
switch (resultingLivenessInfo[index]) {
530532
case LiveOut:
531533
case LiveWithin:
532-
continue;
534+
if (!isUseBeforeDef) {
535+
continue;
536+
} else {
537+
LLVM_FALLTHROUGH;
538+
}
533539
case Dead: {
534540
// This use block has not yet been marked live. Mark it and its
535541
// predecessor blocks live.
@@ -608,21 +614,21 @@ void FieldSensitivePrunedLivenessBoundary::dump() const {
608614
// MARK: FieldSensitiveLiveness
609615
//===----------------------------------------------------------------------===//
610616

611-
void FieldSensitivePrunedLiveness::updateForUse(SILInstruction *user,
612-
TypeTreeLeafTypeRange range,
613-
bool lifetimeEnding) {
617+
void FieldSensitivePrunedLiveness::updateForUse(
618+
SILInstruction *user, TypeTreeLeafTypeRange range, bool lifetimeEnding,
619+
SmallBitVector const &useBeforeDefBits) {
614620
SmallVector<FieldSensitivePrunedLiveBlocks::IsLive, 8> resultingLiveness;
615621
liveBlocks.updateForUse(user, range.startEltOffset, range.endEltOffset,
616-
resultingLiveness);
622+
useBeforeDefBits, resultingLiveness);
617623

618624
addInterestingUser(user, range, lifetimeEnding);
619625
}
620626

621-
void FieldSensitivePrunedLiveness::updateForUse(SILInstruction *user,
622-
SmallBitVector const &bits,
623-
bool lifetimeEnding) {
627+
void FieldSensitivePrunedLiveness::updateForUse(
628+
SILInstruction *user, SmallBitVector const &bits, bool lifetimeEnding,
629+
SmallBitVector const &useBeforeDefBits) {
624630
for (auto bit : bits.set_bits()) {
625-
liveBlocks.updateForUse(user, bit);
631+
liveBlocks.updateForUse(user, bit, useBeforeDefBits.test(bit));
626632
}
627633

628634
addInterestingUser(user, bits, lifetimeEnding);
@@ -807,74 +813,46 @@ void FieldSensitivePrunedLiveRange<LivenessWithDefs>::computeBoundary(
807813
}
808814
}
809815

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

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

880858
//===----------------------------------------------------------------------===//

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)