Skip to content

Commit 96b1809

Browse files
committed
[MoveOnlyAddressChecker] Fix repr for consumes.
An instruction can consume multiple (discontiguous) fields. Use a SmallBitVector to track the fields consumed by an instruction rather than a TypeTreeLeafRange. rdar://125103951
1 parent f849bdf commit 96b1809

File tree

5 files changed

+97
-79
lines changed

5 files changed

+97
-79
lines changed

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,10 @@ class FieldSensitivePrunedLiveBlocks {
480480

481481
/// Returns the liveness in \p resultingFoundLiveness. We only return the
482482
/// bits for endBitNo - startBitNo.
483-
void getLiveness(unsigned startBitNo, unsigned endBitNo,
483+
void getLiveness(SmallBitVector const &bitsOfInterest,
484484
SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
485-
for (unsigned i = startBitNo, e = endBitNo; i != e; ++i) {
486-
resultingFoundLiveness.push_back(getLiveness(i));
485+
for (auto bit : bitsOfInterest.set_bits()) {
486+
resultingFoundLiveness.push_back(getLiveness(bit));
487487
}
488488
}
489489

@@ -601,17 +601,26 @@ class FieldSensitivePrunedLiveBlocks {
601601
void getBlockLiveness(SILBasicBlock *bb, unsigned startBitNo,
602602
unsigned endBitNo,
603603
SmallVectorImpl<IsLive> &foundLivenessInfo) const {
604+
SmallBitVector bits(*numBitsToTrack);
605+
for (auto index = startBitNo; index < endBitNo; ++index) {
606+
bits.set(index);
607+
}
608+
getBlockLiveness(bb, bits, foundLivenessInfo);
609+
}
610+
611+
void getBlockLiveness(SILBasicBlock *bb, SmallBitVector const &bits,
612+
SmallVectorImpl<IsLive> &foundLivenessInfo) const {
604613
assert(isInitialized());
605614
auto liveBlockIter = liveBlocks.find(bb);
606615
if (liveBlockIter == liveBlocks.end()) {
607-
for (unsigned i : range(endBitNo - startBitNo)) {
608-
(void)i;
616+
for (auto bit : bits.set_bits()) {
617+
(void)bit;
609618
foundLivenessInfo.push_back(Dead);
610619
}
611620
return;
612621
}
613622

614-
liveBlockIter->second.getLiveness(startBitNo, endBitNo, foundLivenessInfo);
623+
liveBlockIter->second.getLiveness(bits, foundLivenessInfo);
615624
}
616625

617626
llvm::StringRef getStringRef(IsLive isLive) const;
@@ -919,6 +928,12 @@ class FieldSensitivePrunedLiveness {
919928
resultingFoundLiveness);
920929
}
921930

931+
void getBlockLiveness(SILBasicBlock *bb, SmallBitVector const &bits,
932+
SmallVectorImpl<FieldSensitivePrunedLiveBlocks::IsLive>
933+
&foundLivenessInfo) const {
934+
liveBlocks.getBlockLiveness(bb, bits, foundLivenessInfo);
935+
}
936+
922937
/// Return the liveness for this specific sub-element of our root value.
923938
FieldSensitivePrunedLiveBlocks::IsLive
924939
getBlockLiveness(SILBasicBlock *bb, unsigned subElementNumber) const {
@@ -963,16 +978,16 @@ class FieldSensitivePrunedLiveness {
963978
return record->isInterestingUser(element);
964979
}
965980

966-
/// Whether \p user uses the fields in \p range as indicated by \p kind.
981+
/// Whether \p user uses the fields in \p bits as indicated by \p kind.
967982
bool isInterestingUserOfKind(SILInstruction *user, IsInterestingUser kind,
968-
TypeTreeLeafTypeRange range) const {
983+
SmallBitVector const &bits) const {
969984
auto *record = getInterestingUser(user);
970985
if (!record) {
971986
return kind == IsInterestingUser::NonUser;
972987
}
973988

974-
for (auto element : range.getRange()) {
975-
if (record->isInterestingUser(element) != kind)
989+
for (auto bit : bits.set_bits()) {
990+
if (record->isInterestingUser(bit) != kind)
976991
return false;
977992
}
978993
return true;
@@ -1119,10 +1134,10 @@ class FieldSensitivePrunedLiveRange : public FieldSensitivePrunedLiveness {
11191134
: FieldSensitivePrunedLiveness(fn, discoveredBlocks) {}
11201135

11211136
/// Check if \p inst occurs in between the definition of a def and the
1122-
/// liveness boundary for bits in \p span.
1137+
/// liveness boundary for \p bits.
11231138
///
1124-
/// NOTE: It is assumed that \p inst is correctly described by span.
1125-
bool isWithinBoundary(SILInstruction *inst, TypeTreeLeafTypeRange span) const;
1139+
/// NOTE: It is assumed that \p inst is correctly described by \p bits.
1140+
bool isWithinBoundary(SILInstruction *inst, SmallBitVector const &bits) const;
11261141

11271142
/// Customize updateForUse for FieldSensitivePrunedLiveness such that we check
11281143
/// that we consider defs as stopping liveness from being propagated up.

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -875,16 +875,15 @@ static FunctionTest FieldSensitiveSSAUseLivenessTest(
875875

876876
template <typename LivenessWithDefs>
877877
bool FieldSensitivePrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
878-
SILInstruction *inst, TypeTreeLeafTypeRange span) const {
878+
SILInstruction *inst, SmallBitVector const &bits) const {
879879
assert(asImpl().isInitialized());
880880

881-
PRUNED_LIVENESS_LOG(
882-
llvm::dbgs() << "FieldSensitivePrunedLiveRange::isWithinBoundary!\n"
883-
<< "Span: ";
884-
span.print(llvm::dbgs()); llvm::dbgs() << '\n');
881+
PRUNED_LIVENESS_LOG(llvm::dbgs()
882+
<< "FieldSensitivePrunedLiveRange::isWithinBoundary!\n"
883+
<< "Bits: " << bits << "\n");
885884

886885
// If we do not have any span, return true since we have no counter examples.
887-
if (span.empty()) {
886+
if (bits.empty()) {
888887
PRUNED_LIVENESS_LOG(llvm::dbgs() << " span is empty! Returning true!\n");
889888
return true;
890889
}
@@ -894,13 +893,13 @@ bool FieldSensitivePrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
894893
auto *block = inst->getParent();
895894

896895
SmallVector<IsLive, 8> outVector;
897-
getBlockLiveness(block, span, outVector);
896+
getBlockLiveness(block, bits, outVector);
898897

899-
for (auto pair : llvm::enumerate(outVector)) {
900-
unsigned bit = span.startEltOffset + pair.index();
898+
for (auto bitAndIndex : llvm::enumerate(bits.set_bits())) {
899+
unsigned bit = bitAndIndex.value();
901900
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Visiting bit: " << bit << '\n');
902901
bool isLive = false;
903-
switch (pair.value()) {
902+
switch (outVector[bitAndIndex.index()]) {
904903
case FieldSensitivePrunedLiveBlocks::DeadToLiveEdge:
905904
case FieldSensitivePrunedLiveBlocks::Dead:
906905
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Dead... continuing!\n");

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ struct UseState {
553553
/// consider them to be takes since after the transform they must be a take.
554554
///
555555
/// Importantly, these we know are never copied and are only consumed once.
556-
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4> takeInsts;
556+
InstToBitMap takeInsts;
557557

558558
/// A map from a copy_addr, load [copy], or load [take] that we determine
559559
/// semantically are true copies to the part of the type tree they must copy.
@@ -573,7 +573,7 @@ struct UseState {
573573
/// We represent these separately from \p takeInsts since:
574574
///
575575
/// 1.
576-
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4> copyInsts;
576+
InstToBitMap copyInsts;
577577

578578
/// A map from an instruction that initializes memory to the description of
579579
/// the part of the type tree that it initializes.
@@ -654,6 +654,14 @@ struct UseState {
654654
setAffectedBits(inst, range, initInsts);
655655
}
656656

657+
void recordTakeUse(SILInstruction *inst, TypeTreeLeafTypeRange range) {
658+
setAffectedBits(inst, range, takeInsts);
659+
}
660+
661+
void recordCopyUse(SILInstruction *inst, TypeTreeLeafTypeRange range) {
662+
setAffectedBits(inst, range, copyInsts);
663+
}
664+
657665
/// Returns true if this is an instruction that is used by the pass to ensure
658666
/// that we reinit said argument if we consumed it in a region of code.
659667
///
@@ -795,18 +803,18 @@ struct UseState {
795803
});
796804
}
797805

798-
bool isConsume(SILInstruction *inst, TypeTreeLeafTypeRange span) const {
806+
bool isConsume(SILInstruction *inst, SmallBitVector const &bits) const {
799807
{
800808
auto iter = takeInsts.find(inst);
801809
if (iter != takeInsts.end()) {
802-
if (span.setIntersection(iter->second))
810+
if (bits.anyCommon(iter->second))
803811
return true;
804812
}
805813
}
806814
{
807815
auto iter = copyInsts.find(inst);
808816
if (iter != copyInsts.end()) {
809-
if (span.setIntersection(iter->second))
817+
if (bits.anyCommon(iter->second))
810818
return true;
811819
}
812820
}
@@ -816,34 +824,32 @@ struct UseState {
816824
bool isCopy(SILInstruction *inst, const SmallBitVector &bv) const {
817825
auto iter = copyInsts.find(inst);
818826
if (iter != copyInsts.end()) {
819-
for (unsigned index : iter->second.getRange()) {
820-
if (bv[index])
821-
return true;
822-
}
827+
if (bv.anyCommon(iter->second))
828+
return true;
823829
}
824830
return false;
825831
}
826832

827-
bool isLivenessUse(SILInstruction *inst, TypeTreeLeafTypeRange span) const {
833+
bool isLivenessUse(SILInstruction *inst, SmallBitVector const &bits) const {
828834
{
829835
auto iter = nonconsumingUses.find(inst);
830836
if (iter != nonconsumingUses.end()) {
831-
if (span.intersects(iter->second))
837+
if (bits.anyCommon(iter->second))
832838
return true;
833839
}
834840
}
835841
{
836842
auto iter = borrows.find(inst);
837843
if (iter != borrows.end()) {
838-
if (span.setIntersection(iter->second))
844+
if (iter->second.intersects(bits))
839845
return true;
840846
}
841847
}
842848

843849
if (!isReinitToInitConvertibleInst(inst)) {
844850
auto iter = reinitInsts.find(inst);
845851
if (iter != reinitInsts.end()) {
846-
if (span.intersects(iter->second))
852+
if (bits.anyCommon(iter->second))
847853
return true;
848854
}
849855
}
@@ -857,40 +863,19 @@ struct UseState {
857863
return false;
858864
}
859865

860-
bool isInitUse(SILInstruction *inst, TypeTreeLeafTypeRange span) const {
861-
{
862-
auto iter = initInsts.find(inst);
863-
if (iter != initInsts.end()) {
864-
if (span.intersects(iter->second))
865-
return true;
866-
}
867-
}
868-
if (isReinitToInitConvertibleInst(inst)) {
869-
auto iter = reinitInsts.find(inst);
870-
if (iter != reinitInsts.end()) {
871-
if (span.intersects(iter->second))
872-
return true;
873-
}
874-
}
875-
return false;
876-
}
877-
878-
bool isInitUse(SILInstruction *inst, const SmallBitVector &requiredBits,
879-
SmallBitVector &foundInitBits) const {
866+
bool isInitUse(SILInstruction *inst, const SmallBitVector &requiredBits) const {
880867
{
881868
auto iter = initInsts.find(inst);
882869
if (iter != initInsts.end()) {
883-
foundInitBits = iter->second & requiredBits;
884-
if (foundInitBits.any())
870+
if (requiredBits.anyCommon(iter->second))
885871
return true;
886872
}
887873
}
888874

889875
if (isReinitToInitConvertibleInst(inst)) {
890876
auto iter = reinitInsts.find(inst);
891877
if (iter != reinitInsts.end()) {
892-
foundInitBits = iter->second & requiredBits;
893-
if (foundInitBits.any())
878+
if (requiredBits.anyCommon(iter->second))
894879
return true;
895880
}
896881
}
@@ -2193,10 +2178,10 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
21932178

21942179
if (copyAddr->isTakeOfSrc()) {
21952180
LLVM_DEBUG(llvm::dbgs() << "Found take: " << *user);
2196-
useState.takeInsts.insert({user, *leafRange});
2181+
useState.recordTakeUse(user, *leafRange);
21972182
} else {
21982183
LLVM_DEBUG(llvm::dbgs() << "Found copy: " << *user);
2199-
useState.copyInsts.insert({user, *leafRange});
2184+
useState.recordCopyUse(user, *leafRange);
22002185
}
22012186
return true;
22022187
}
@@ -2405,10 +2390,10 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
24052390
// done checking. The load [take] are already complete and good to go.
24062391
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) {
24072392
LLVM_DEBUG(llvm::dbgs() << "Found take inst: " << *user);
2408-
useState.takeInsts.insert({user, *leafRange});
2393+
useState.recordTakeUse(user, *leafRange);
24092394
} else {
24102395
LLVM_DEBUG(llvm::dbgs() << "Found copy inst: " << *user);
2411-
useState.copyInsts.insert({user, *leafRange});
2396+
useState.recordCopyUse(user, *leafRange);
24122397
}
24132398
}
24142399
return true;
@@ -2457,7 +2442,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
24572442
}
24582443

24592444
LLVM_DEBUG(llvm::dbgs() << "Pure consuming use: " << *user);
2460-
useState.takeInsts.insert({user, *leafRange});
2445+
useState.recordTakeUse(user, *leafRange);
24612446
return true;
24622447
}
24632448

@@ -2668,9 +2653,7 @@ struct GlobalLivenessChecker {
26682653
/// Returns true if we emitted any errors.
26692654
bool compute();
26702655

2671-
bool testInstVectorLiveness(
2672-
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4>
2673-
&instsToTest);
2656+
bool testInstVectorLiveness(UseState::InstToBitMap &instsToTest);
26742657

26752658
void clear() {
26762659
livenessVector.clear();
@@ -2681,8 +2664,7 @@ struct GlobalLivenessChecker {
26812664
} // namespace
26822665

26832666
bool GlobalLivenessChecker::testInstVectorLiveness(
2684-
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4>
2685-
&instsToTest) {
2667+
UseState::InstToBitMap &instsToTest) {
26862668
bool emittedDiagnostic = false;
26872669

26882670
for (auto takeInstAndValue : instsToTest) {
@@ -2835,9 +2817,7 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
28352817
#ifndef NDEBUG
28362818
SmallBitVector defBits(addressUseState.getNumSubelements());
28372819
liveness.isDefBlock(block, errorSpan, defBits);
2838-
SmallBitVector errorSpanBits(addressUseState.getNumSubelements());
2839-
errorSpan.setBits(errorSpanBits);
2840-
assert((defBits & errorSpanBits).none() &&
2820+
assert((defBits & errorSpan).none() &&
28412821
"If in def block... we are in liveness block");
28422822
#endif
28432823
[[clang::fallthrough]];
@@ -3228,8 +3208,7 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses(
32283208

32293209
// Check all takes.
32303210
for (auto takeInst : addressUseState.takeInsts) {
3231-
SmallBitVector bits(liveness.getNumSubElements());
3232-
takeInst.second.setBits(bits);
3211+
auto &bits = takeInst.second;
32333212
bool claimedConsume = consumes.claimConsume(takeInst.first, bits);
32343213
(void)claimedConsume;
32353214
if (!claimedConsume) {
@@ -3242,8 +3221,7 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses(
32423221

32433222
// Then rewrite all copy insts to be takes and claim them.
32443223
for (auto copyInst : addressUseState.copyInsts) {
3245-
SmallBitVector bits(liveness.getNumSubElements());
3246-
copyInst.second.setBits(bits);
3224+
auto &bits = copyInst.second;
32473225
bool claimedConsume = consumes.claimConsume(copyInst.first, bits);
32483226
if (!claimedConsume) {
32493227
llvm::errs()
@@ -3408,7 +3386,7 @@ void ExtendUnconsumedLiveness::run() {
34083386
}
34093387
}
34103388
for (auto pair : addressUseState.takeInsts) {
3411-
if (pair.second.contains(element)) {
3389+
if (pair.second.test(element)) {
34123390
destroys[pair.first] = DestroyKind::Take;
34133391
}
34143392
}

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,9 @@ void Implementation::checkDestructureUsesOnBoundary() const {
604604
<< " DestructureNeedingUse: " << *use->getUser());
605605

606606
auto destructureUseSpan = *TypeTreeLeafTypeRange::get(use, getRootValue());
607-
if (!liveness.isWithinBoundary(use->getUser(), destructureUseSpan)) {
607+
SmallBitVector destructureUseBits(liveness.getNumSubElements());
608+
destructureUseSpan.setBits(destructureUseBits);
609+
if (!liveness.isWithinBoundary(use->getUser(), destructureUseBits)) {
608610
LLVM_DEBUG(llvm::dbgs()
609611
<< " On boundary or within boundary! No error!\n");
610612
continue;

0 commit comments

Comments
 (0)