Skip to content

Commit 91ee824

Browse files
Merge pull request #66690 from nate-chandler/rdar110676577
[FieldSensitivePL] Fix vectorization.
2 parents 606eef6 + f4e3292 commit 91ee824

File tree

6 files changed

+352
-149
lines changed

6 files changed

+352
-149
lines changed

include/swift/Basic/FrozenMultiMap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class FrozenMultiMap {
7171
// Since our array is sorted, we need to first find the first pair with our
7272
// inst as the first element.
7373
auto start = std::lower_bound(
74-
storage.begin(), storage.end(), std::make_pair(key, Value()),
74+
storage.begin(), storage.end(), std::make_pair(key, llvm::None),
7575
[&](const std::pair<Key, Optional<Value>> &p1,
7676
const std::pair<Key, Optional<Value>> &p2) {
7777
return p1.first < p2.first;

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,13 @@ struct TypeTreeLeafTypeRange {
358358
endEltOffset >= range.endEltOffset;
359359
}
360360

361+
/// Sets each bit in \p bits corresponding to an element of this range.
362+
void setBits(SmallBitVector &bits) {
363+
for (auto element : getRange()) {
364+
bits.set(element);
365+
}
366+
}
367+
361368
IntRange<unsigned> getRange() const {
362369
return range(startEltOffset, endEltOffset);
363370
}
@@ -666,17 +673,60 @@ class FieldSensitivePrunedLiveness {
666673
FieldSensitivePrunedLiveBlocks liveBlocks;
667674

668675
public:
676+
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
677+
669678
struct InterestingUser {
670-
TypeTreeLeafTypeRange subEltSpan;
671-
bool isConsuming;
679+
SmallBitVector liveBits;
680+
SmallBitVector consumingBits;
672681

673-
InterestingUser() : subEltSpan(), isConsuming(false) {}
674-
InterestingUser(TypeTreeLeafTypeRange subEltSpan, bool isConsuming)
675-
: subEltSpan(subEltSpan), isConsuming(isConsuming) {}
682+
InterestingUser(unsigned bitCount)
683+
: liveBits(bitCount), consumingBits(bitCount) {}
676684

677-
InterestingUser &operator&=(bool otherValue) {
678-
isConsuming &= otherValue;
679-
return *this;
685+
InterestingUser(unsigned bitCount, TypeTreeLeafTypeRange range,
686+
bool lifetimeEnding)
687+
: liveBits(bitCount), consumingBits(bitCount) {
688+
addUses(range, lifetimeEnding);
689+
}
690+
691+
/// Record that the instruction uses the bits of the value in \p range.
692+
void addUses(TypeTreeLeafTypeRange range, bool lifetimeEnding) {
693+
range.setBits(liveBits);
694+
if (lifetimeEnding) {
695+
range.setBits(consumingBits);
696+
}
697+
}
698+
699+
/// Populates the provided vector with contiguous ranges of bits which are
700+
/// users of the same sort.
701+
void getContiguousRanges(
702+
SmallVectorImpl<std::pair<TypeTreeLeafTypeRange, IsInterestingUser>>
703+
&ranges) const {
704+
if (liveBits.size() == 0)
705+
return;
706+
707+
assert(ranges.empty());
708+
Optional<std::pair<unsigned, IsInterestingUser>> current = llvm::None;
709+
for (unsigned bit = 0, size = liveBits.size(); bit < size; ++bit) {
710+
auto interesting = isInterestingUser(bit);
711+
if (!current) {
712+
current = {bit, interesting};
713+
continue;
714+
}
715+
if (current->second != interesting) {
716+
ranges.push_back(
717+
{TypeTreeLeafTypeRange(current->first, bit), current->second});
718+
current = {bit, interesting};
719+
}
720+
}
721+
ranges.push_back({TypeTreeLeafTypeRange(current->first, liveBits.size()),
722+
current->second});
723+
}
724+
725+
IsInterestingUser isInterestingUser(unsigned element) const {
726+
if (!liveBits.test(element))
727+
return NonUser;
728+
return consumingBits.test(element) ? LifetimeEndingUse
729+
: NonLifetimeEndingUse;
680730
}
681731
};
682732

@@ -758,42 +808,6 @@ class FieldSensitivePrunedLiveness {
758808
return llvm::make_range(users.begin(), users.end());
759809
}
760810

761-
using LifetimeEndingUserRange = OptionalTransformRange<
762-
UserRange,
763-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
764-
const std::pair<SILInstruction *, InterestingUser> &)>>;
765-
LifetimeEndingUserRange getAllLifetimeEndingUses() const {
766-
assert(isInitialized());
767-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
768-
const std::pair<SILInstruction *, InterestingUser> &)>
769-
op;
770-
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
771-
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
772-
if (pair.second.isConsuming)
773-
return {{pair.first, pair.second.subEltSpan}};
774-
return None;
775-
};
776-
return LifetimeEndingUserRange(getAllUsers(), op);
777-
}
778-
779-
using NonLifetimeEndingUserRange = OptionalTransformRange<
780-
UserRange,
781-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
782-
const std::pair<SILInstruction *, InterestingUser> &)>>;
783-
NonLifetimeEndingUserRange getAllNonLifetimeEndingUses() const {
784-
assert(isInitialized());
785-
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
786-
const std::pair<SILInstruction *, InterestingUser> &)>
787-
op;
788-
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
789-
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
790-
if (!pair.second.isConsuming)
791-
return {{pair.first, pair.second.subEltSpan}};
792-
return None;
793-
};
794-
return NonLifetimeEndingUserRange(getAllUsers(), op);
795-
}
796-
797811
using UserBlockRange = TransformRange<
798812
UserRange, function_ref<SILBasicBlock *(
799813
const std::pair<SILInstruction *, InterestingUser> &)>>;
@@ -848,19 +862,37 @@ class FieldSensitivePrunedLiveness {
848862
SmallBitVector &liveOutBits,
849863
SmallBitVector &deadBits) const;
850864

851-
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
865+
/// If \p user has had uses recored, return a pointer to the InterestingUser
866+
/// where they've been recorded.
867+
InterestingUser const *getInterestingUser(SILInstruction *user) const {
868+
auto iter = users.find(user);
869+
if (iter == users.end())
870+
return nullptr;
871+
return &iter->second;
872+
}
852873

853-
/// Return a result indicating whether the given user was identified as an
854-
/// interesting use of the current def and whether it ends the lifetime.
855-
std::pair<IsInterestingUser, Optional<TypeTreeLeafTypeRange>>
856-
isInterestingUser(SILInstruction *user) const {
874+
/// How \p user uses the field at \p element.
875+
IsInterestingUser isInterestingUser(SILInstruction *user,
876+
unsigned element) const {
857877
assert(isInitialized());
858-
auto useIter = users.find(user);
859-
if (useIter == users.end())
860-
return {NonUser, None};
861-
auto isInteresting =
862-
useIter->second.isConsuming ? LifetimeEndingUse : NonLifetimeEndingUse;
863-
return {isInteresting, useIter->second.subEltSpan};
878+
auto *record = getInterestingUser(user);
879+
if (!record)
880+
return NonUser;
881+
return record->isInterestingUser(element);
882+
}
883+
884+
/// Whether \p user uses the fields in \p range as indicated by \p kind.
885+
bool isInterestingUserOfKind(SILInstruction *user, IsInterestingUser kind,
886+
TypeTreeLeafTypeRange range) const {
887+
auto *record = getInterestingUser(user);
888+
if (!record)
889+
return kind == IsInterestingUser::NonUser;
890+
891+
for (auto element : range.getRange()) {
892+
if (isInterestingUser(user, element) != kind)
893+
return false;
894+
}
895+
return true;
864896
}
865897

866898
unsigned getNumSubElements() const { return liveBlocks.getNumBitsToTrack(); }
@@ -886,10 +918,11 @@ class FieldSensitivePrunedLiveness {
886918
/// argument must be copied.
887919
void addInterestingUser(SILInstruction *user, TypeTreeLeafTypeRange range,
888920
bool lifetimeEnding) {
889-
auto iterAndSuccess =
890-
users.insert({user, InterestingUser(range, lifetimeEnding)});
891-
if (!iterAndSuccess.second)
892-
iterAndSuccess.first->second &= lifetimeEnding;
921+
auto iter = users.find(user);
922+
if (iter == users.end()) {
923+
iter = users.insert({user, InterestingUser(getNumSubElements())}).first;
924+
}
925+
iter->second.addUses(range, lifetimeEnding);
893926
}
894927
};
895928

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,38 @@ void FieldSensitivePrunedLiveBlocks::print(llvm::raw_ostream &OS) const {
563563

564564
void FieldSensitivePrunedLiveBlocks::dump() const { print(llvm::dbgs()); }
565565

566+
//===----------------------------------------------------------------------===//
567+
// FieldSensitivePrunedLivenessBoundary
568+
//===----------------------------------------------------------------------===//
569+
570+
void FieldSensitivePrunedLivenessBoundary::print(llvm::raw_ostream &OS) const {
571+
for (auto pair : lastUsers) {
572+
auto *user = pair.first;
573+
auto bits = pair.second;
574+
OS << "last user: " << *user
575+
<< "\tat " << bits << "\n";
576+
}
577+
for (auto pair : boundaryEdges) {
578+
auto *block = pair.first;
579+
auto bits = pair.second;
580+
OS << "boundary edge: ";
581+
block->printAsOperand(OS);
582+
OS << "\n" << "\tat " << bits << "\n";
583+
}
584+
if (!deadDefs.empty()) {
585+
for (auto pair : deadDefs) {
586+
auto *deadDef = pair.first;
587+
auto bits = pair.second;
588+
OS << "dead def: " << *deadDef
589+
<< "\tat " << bits << "\n";
590+
}
591+
}
592+
}
593+
594+
void FieldSensitivePrunedLivenessBoundary::dump() const {
595+
print(llvm::dbgs());
596+
}
597+
566598
//===----------------------------------------------------------------------===//
567599
// MARK: FieldSensitiveLiveness
568600
//===----------------------------------------------------------------------===//
@@ -673,9 +705,7 @@ bool FieldSensitivePrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
673705
// If we are not live and have an interesting user that maps to our bit,
674706
// mark this bit as being live again.
675707
if (!isLive) {
676-
auto interestingUser = isInterestingUser(&blockInst);
677-
bool isInteresting =
678-
interestingUser.first && interestingUser.second->contains(bit);
708+
bool isInteresting = isInterestingUser(&blockInst, bit);
679709
PRUNED_LIVENESS_LOG(llvm::dbgs()
680710
<< " Inst was dead... Is InterestingUser: "
681711
<< (isInteresting ? "true" : "false") << '\n');
@@ -806,8 +836,7 @@ void findBoundaryInNonDefBlock(SILBasicBlock *block, unsigned bitNo,
806836
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Looking for boundary in non-def block\n");
807837
for (SILInstruction &inst : llvm::reverse(*block)) {
808838
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Visiting: " << inst);
809-
auto interestingUser = liveness.isInterestingUser(&inst);
810-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
839+
if (liveness.isInterestingUser(&inst, bitNo)) {
811840
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Is interesting user for this bit!\n");
812841
boundary.getLastUserBits(&inst).set(bitNo);
813842
return;
@@ -837,8 +866,7 @@ void findBoundaryInSSADefBlock(SILNode *ssaDef, unsigned bitNo,
837866
boundary.getDeadDefsBits(cast<SILNode>(&inst)).set(bitNo);
838867
return;
839868
}
840-
auto interestingUser = liveness.isInterestingUser(&inst);
841-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
869+
if (liveness.isInterestingUser(&inst, bitNo)) {
842870
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found interesting user: " << inst);
843871
boundary.getLastUserBits(&inst).set(bitNo);
844872
return;
@@ -973,8 +1001,7 @@ void FieldSensitiveMultiDefPrunedLiveRange::findBoundariesInBlock(
9731001
PRUNED_LIVENESS_LOG(llvm::dbgs()
9741002
<< " Checking if this inst is also a last user...\n");
9751003
if (!isLive) {
976-
auto interestingUser = isInterestingUser(&inst);
977-
if (interestingUser.first && interestingUser.second->contains(bitNo)) {
1004+
if (isInterestingUser(&inst, bitNo)) {
9781005
PRUNED_LIVENESS_LOG(
9791006
llvm::dbgs()
9801007
<< " Was interesting user! Moving from dead -> live!\n");

0 commit comments

Comments
 (0)