Skip to content

Commit d3a1e06

Browse files
committed
WIP: [FieldSensitivePL] Fix vectorization.
FieldSensitivePrunedLiveness is used as a vectorization of PrunedLiveness. An instance of FSPL with N elements needs to be able to represent the same states as N instances of PL. Previously, it failed to do that in two significant ways: (1) It attempted to save space for which elements were live by using a range. This failed to account for instructions which are users of non-contiguous fields of an aggregate. apply( @owned (struct_element_addr %s, #S.f1), @owned (struct_element_addr %s, #S.f3) ) (2) It used a single bit to represent whether the instruction was consuming. This failed to account for instructions which consumed some fields and borrowed others. apply( @owned (struct_element_addr %s, #S.f1), @guaranteed (struct_element_addr %s, #S.f2) ) The fix for (1) is to use a bit vector to represent which elements are used by the instruction. The fix for (2) is to use a second bit vector to represent which elements are _consumed_ by the instruction. rdar://110676577
1 parent 06e748a commit d3a1e06

File tree

6 files changed

+272
-171
lines changed

6 files changed

+272
-171
lines changed

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 127 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,12 @@ struct TypeTreeLeafTypeRange {
384384
endEltOffset >= range.endEltOffset;
385385
}
386386

387+
void setBits(SmallBitVector &bits) {
388+
for (auto element : getRange()) {
389+
bits.set(element);
390+
}
391+
}
392+
387393
IntRange<unsigned> getRange() const {
388394
return range(startEltOffset, endEltOffset);
389395
}
@@ -692,17 +698,66 @@ class FieldSensitivePrunedLiveness {
692698
FieldSensitivePrunedLiveBlocks liveBlocks;
693699

694700
public:
701+
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
702+
695703
struct InterestingUser {
696-
TypeTreeLeafTypeRange subEltSpan;
697-
bool isConsuming;
704+
SmallBitVector liveBits;
705+
SmallBitVector consumingBits;
698706

699-
InterestingUser() : subEltSpan(), isConsuming(false) {}
700-
InterestingUser(TypeTreeLeafTypeRange subEltSpan, bool isConsuming)
701-
: subEltSpan(subEltSpan), isConsuming(isConsuming) {}
707+
// FIXME: FIXME_NOW: Where is this called from?
708+
InterestingUser() {};
702709

703-
InterestingUser &operator&=(bool otherValue) {
704-
isConsuming &= otherValue;
705-
return *this;
710+
InterestingUser(unsigned bitCount, TypeTreeLeafTypeRange range, bool lifetimeEnding) : liveBits(bitCount), consumingBits(bitCount) {
711+
for (auto field : range.getRange()) {
712+
liveBits.set(field);
713+
if (lifetimeEnding) {
714+
consumingBits.set(field);
715+
}
716+
}
717+
}
718+
719+
void getContiguousRanges(SmallVectorImpl<std::pair<TypeTreeLeafTypeRange, IsInterestingUser>> &ranges) const {
720+
if (liveBits.size() == 0)
721+
return;
722+
723+
assert(ranges.empty());
724+
Optional<std::pair<unsigned, IsInterestingUser>> current = llvm::None;
725+
for (unsigned bit = 0, size = liveBits.size(); bit < size; ++bit) {
726+
auto interesting = isInterestingUser(bit);
727+
if (!current) {
728+
current = {bit, interesting};
729+
continue;
730+
}
731+
if (current->second != interesting) {
732+
ranges.push_back({TypeTreeLeafTypeRange(current->first, bit), current->second});
733+
current = {bit, interesting};
734+
}
735+
}
736+
ranges.push_back({TypeTreeLeafTypeRange(current->first, liveBits.size()), current->second});
737+
}
738+
739+
// Optional<IsInterestingUser> isInterestingUserAtBits(SmallBitVector bits) const {
740+
// if (bits.count() == 0)
741+
// return NonUser;
742+
743+
// Optional<IsInterestingUser> retval = llvm::None;
744+
// for (auto bit : bits.set_bits()) {
745+
// auto interesting = isInterestingUser(bit);
746+
// if (!retval) {
747+
// retval = interesting;
748+
// continue;
749+
// }
750+
// if (*retval != interesting)
751+
// return llvm::None;
752+
// }
753+
754+
// return retval;
755+
// }
756+
757+
IsInterestingUser isInterestingUser(unsigned element) const {
758+
if (!liveBits.test(element))
759+
return NonUser;
760+
return consumingBits.test(element) ? LifetimeEndingUse : NonLifetimeEndingUse;
706761
}
707762
};
708763

@@ -788,37 +843,37 @@ class FieldSensitivePrunedLiveness {
788843
UserRange,
789844
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
790845
const std::pair<SILInstruction *, InterestingUser> &)>>;
791-
LifetimeEndingUserRange getAllLifetimeEndingUses() const {
792-
assert(isInitialized());
793-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
794-
const std::pair<SILInstruction *, InterestingUser> &)>
795-
op;
796-
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
797-
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
798-
if (pair.second.isConsuming)
799-
return {{pair.first, pair.second.subEltSpan}};
800-
return None;
801-
};
802-
return LifetimeEndingUserRange(getAllUsers(), op);
803-
}
846+
// LifetimeEndingUserRange getAllLifetimeEndingUses() const {
847+
// assert(isInitialized());
848+
// function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
849+
// const std::pair<SILInstruction *, InterestingUser> &)>
850+
// op;
851+
// op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
852+
// -> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
853+
// if (pair.second.isConsuming)
854+
// return {{pair.first, pair.second.subEltSpan}};
855+
// return None;
856+
// };
857+
// return LifetimeEndingUserRange(getAllUsers(), op);
858+
// }
804859

805860
using NonLifetimeEndingUserRange = OptionalTransformRange<
806861
UserRange,
807862
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
808863
const std::pair<SILInstruction *, InterestingUser> &)>>;
809-
NonLifetimeEndingUserRange getAllNonLifetimeEndingUses() const {
810-
assert(isInitialized());
811-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
812-
const std::pair<SILInstruction *, InterestingUser> &)>
813-
op;
814-
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
815-
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
816-
if (!pair.second.isConsuming)
817-
return {{pair.first, pair.second.subEltSpan}};
818-
return None;
819-
};
820-
return NonLifetimeEndingUserRange(getAllUsers(), op);
821-
}
864+
// NonLifetimeEndingUserRange getAllNonLifetimeEndingUses() const {
865+
// assert(isInitialized());
866+
// function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
867+
// const std::pair<SILInstruction *, InterestingUser> &)>
868+
// op;
869+
// op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
870+
// -> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
871+
// if (!pair.second.isConsuming)
872+
// return {{pair.first, pair.second.subEltSpan}};
873+
// return None;
874+
// };
875+
// return NonLifetimeEndingUserRange(getAllUsers(), op);
876+
// }
822877

823878
using UserBlockRange = TransformRange<
824879
UserRange, function_ref<SILBasicBlock *(
@@ -874,19 +929,41 @@ class FieldSensitivePrunedLiveness {
874929
SmallBitVector &liveOutBits,
875930
SmallBitVector &deadBits) const;
876931

877-
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
932+
InterestingUser const *getInterestingUser(SILInstruction *user) const {
933+
auto iter = users.find(user);
934+
if (iter == users.end())
935+
return nullptr;
936+
return &iter->second;
937+
}
878938

879939
/// Return a result indicating whether the given user was identified as an
880940
/// interesting use of the current def and whether it ends the lifetime.
881-
std::pair<IsInterestingUser, Optional<TypeTreeLeafTypeRange>>
882-
isInterestingUser(SILInstruction *user) const {
941+
IsInterestingUser
942+
isInterestingUser(SILInstruction *user, unsigned element) const {
883943
assert(isInitialized());
884944
auto useIter = users.find(user);
885945
if (useIter == users.end())
886-
return {NonUser, None};
887-
auto isInteresting =
888-
useIter->second.isConsuming ? LifetimeEndingUse : NonLifetimeEndingUse;
889-
return {isInteresting, useIter->second.subEltSpan};
946+
return NonUser;
947+
auto &record = useIter->second;
948+
return record.isInterestingUser(element);
949+
}
950+
951+
bool isInterestingUserOfKindThroughoutRange(SILInstruction *user, IsInterestingUser kind, TypeTreeLeafTypeRange range) const {
952+
assert(kind != NonUser);
953+
bool wantsConsuming = (kind == LifetimeEndingUse);
954+
955+
auto iter = users.find(user);
956+
if (iter == users.end())
957+
return false;
958+
auto &record = iter->second;
959+
for (auto element : range.getRange()) {
960+
if (!record.liveBits.test(element))
961+
return false;
962+
auto consuming = record.consumingBits.test(element);
963+
if (consuming != wantsConsuming)
964+
return false;
965+
}
966+
return true;
890967
}
891968

892969
unsigned getNumSubElements() const { return liveBlocks.getNumBitsToTrack(); }
@@ -912,11 +989,15 @@ class FieldSensitivePrunedLiveness {
912989
/// argument must be copied.
913990
void addInterestingUser(SILInstruction *user, TypeTreeLeafTypeRange range,
914991
bool lifetimeEnding) {
915-
auto iterAndSuccess =
916-
users.insert({user, InterestingUser(range, lifetimeEnding)});
917-
if (!iterAndSuccess.second) {
918-
iterAndSuccess.first->second.subEltSpan.extendThrough(range);
919-
iterAndSuccess.first->second &= lifetimeEnding;
992+
auto iter = users.find(user);
993+
if (iter == users.end()) {
994+
iter = users.insert({user, InterestingUser(getNumSubElements(), range, lifetimeEnding)}).first;
995+
}
996+
for (auto element : range.getRange()) {
997+
iter->second.liveBits.set(element);
998+
if (lifetimeEnding) {
999+
iter->second.consumingBits.set(element);
1000+
}
9201001
}
9211002
}
9221003
};

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,9 @@ bool FieldSensitivePrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
699699
// If we are not live and have an interesting user that maps to our bit,
700700
// mark this bit as being live again.
701701
if (!isLive) {
702-
auto interestingUser = isInterestingUser(&blockInst);
702+
auto interestingUser = isInterestingUser(&blockInst, bit);
703703
bool isInteresting =
704-
interestingUser.first && interestingUser.second->contains(bit);
704+
interestingUser;
705705
PRUNED_LIVENESS_LOG(llvm::dbgs()
706706
<< " Inst was dead... Is InterestingUser: "
707707
<< (isInteresting ? "true" : "false") << '\n');
@@ -832,8 +832,8 @@ void findBoundaryInNonDefBlock(SILBasicBlock *block, unsigned bitNo,
832832
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Looking for boundary in non-def block\n");
833833
for (SILInstruction &inst : llvm::reverse(*block)) {
834834
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Visiting: " << inst);
835-
auto interestingUser = liveness.isInterestingUser(&inst);
836-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
835+
auto interestingUser = liveness.isInterestingUser(&inst, bitNo);
836+
if (interestingUser) {
837837
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Is interesting user for this bit!\n");
838838
boundary.getLastUserBits(&inst).set(bitNo);
839839
return;
@@ -863,8 +863,8 @@ void findBoundaryInSSADefBlock(SILNode *ssaDef, unsigned bitNo,
863863
boundary.getDeadDefsBits(cast<SILNode>(&inst)).set(bitNo);
864864
return;
865865
}
866-
auto interestingUser = liveness.isInterestingUser(&inst);
867-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
866+
auto interestingUser = liveness.isInterestingUser(&inst, bitNo);
867+
if (interestingUser) {
868868
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found interesting user: " << inst);
869869
boundary.getLastUserBits(&inst).set(bitNo);
870870
return;
@@ -999,8 +999,8 @@ void FieldSensitiveMultiDefPrunedLiveRange::findBoundariesInBlock(
999999
PRUNED_LIVENESS_LOG(llvm::dbgs()
10001000
<< " Checking if this inst is also a last user...\n");
10011001
if (!isLive) {
1002-
auto interestingUser = isInterestingUser(&inst);
1003-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
1002+
auto interestingUser = isInterestingUser(&inst, bitNo);
1003+
if (interestingUser) {
10041004
PRUNED_LIVENESS_LOG(
10051005
llvm::dbgs()
10061006
<< " Was interesting user! Moving from dead -> live!\n");

0 commit comments

Comments
 (0)